Coverage Report

Created: 2026-09-04 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-aat-layout-morx-table.hh
Line
Count
Source
1
/*
2
 * Copyright © 2017  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod
25
 */
26
27
#ifndef HB_AAT_LAYOUT_MORX_TABLE_HH
28
#define HB_AAT_LAYOUT_MORX_TABLE_HH
29
30
#include "hb-open-type.hh"
31
#include "hb-aat-layout-common.hh"
32
#include "hb-ot-layout.hh"
33
#include "hb-aat-map.hh"
34
35
/*
36
 * morx -- Extended Glyph Metamorphosis
37
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
38
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
39
 */
40
#define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
41
#define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
42
43
44
namespace AAT {
45
46
using namespace OT;
47
48
template <typename Types>
49
struct RearrangementSubtable
50
{
51
  typedef typename Types::HBUINT HBUINT;
52
53
  typedef void EntryData;
54
55
  enum Flags
56
  {
57
    MarkFirst   = 0x8000, /* If set, make the current glyph the first
58
           * glyph to be rearranged. */
59
    DontAdvance   = 0x4000, /* If set, don't advance to the next glyph
60
           * before going to the new state. This means
61
           * that the glyph index doesn't change, even
62
           * if the glyph at that index has changed. */
63
    MarkLast    = 0x2000, /* If set, make the current glyph the last
64
           * glyph to be rearranged. */
65
    Reserved    = 0x1FF0, /* These bits are reserved and should be set to 0. */
66
    Verb    = 0x000F, /* The type of rearrangement specified. */
67
  };
68
69
  bool is_action_initiable (const Entry<EntryData> &entry) const
70
0
  {
71
0
    return (entry.flags & MarkFirst);
72
0
  }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::is_action_initiable(AAT::Entry<void> const&) const
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::is_action_initiable(AAT::Entry<void> const&) const
73
  bool is_actionable (const Entry<EntryData> &entry) const
74
0
  {
75
0
    return (entry.flags & Verb);
76
0
  }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::is_actionable(AAT::Entry<void> const&) const
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::is_actionable(AAT::Entry<void> const&) const
77
78
  struct driver_context_t
79
  {
80
    static constexpr bool in_place = true;
81
82
    driver_context_t (const RearrangementSubtable *table_) :
83
0
  ret (false),
84
0
  table (table_),
85
0
  start (0), end (0) {}
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::RearrangementSubtable<AAT::ExtendedTypes> const*)
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::RearrangementSubtable<AAT::ObsoleteTypes> const*)
86
87
    HB_AAT_TRANSITION_INLINE
88
    void transition (hb_buffer_t *buffer,
89
         StateTableDriver<Types, EntryData, Flags> *driver,
90
         const Entry<EntryData> &entry)
91
0
    {
92
0
      unsigned int flags = entry.flags;
93
94
0
      if (flags & MarkFirst)
95
0
  start = buffer->idx;
96
97
0
      if (flags & MarkLast)
98
0
  end = hb_min (buffer->idx + 1, buffer->len);
99
100
0
      if ((flags & Verb) && start < end)
101
0
      {
102
  /* The following map has two nibbles, for start-side
103
   * and end-side. Values of 0,1,2 mean move that many
104
   * to the other side. Value of 3 means move 2 and
105
   * flip them. */
106
0
  const unsigned char map[16] =
107
0
  {
108
0
    0x00, /* 0  no change */
109
0
    0x10, /* 1  Ax => xA */
110
0
    0x01, /* 2  xD => Dx */
111
0
    0x11, /* 3  AxD => DxA */
112
0
    0x20, /* 4  ABx => xAB */
113
0
    0x30, /* 5  ABx => xBA */
114
0
    0x02, /* 6  xCD => CDx */
115
0
    0x03, /* 7  xCD => DCx */
116
0
    0x12, /* 8  AxCD => CDxA */
117
0
    0x13, /* 9  AxCD => DCxA */
118
0
    0x21, /* 10 ABxD => DxAB */
119
0
    0x31, /* 11 ABxD => DxBA */
120
0
    0x22, /* 12 ABxCD => CDxAB */
121
0
    0x32, /* 13 ABxCD => CDxBA */
122
0
    0x23, /* 14 ABxCD => DCxAB */
123
0
    0x33, /* 15 ABxCD => DCxBA */
124
0
  };
125
126
0
  unsigned int m = map[flags & Verb];
127
0
  unsigned int l = hb_min (2u, m >> 4);
128
0
  unsigned int r = hb_min (2u, m & 0x0F);
129
0
  bool reverse_l = 3 == (m >> 4);
130
0
  bool reverse_r = 3 == (m & 0x0F);
131
132
0
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
133
0
  {
134
0
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
135
0
    buffer->merge_clusters (start, end);
136
137
0
    hb_glyph_info_t *info = buffer->info;
138
0
    hb_glyph_info_t buf[4];
139
140
0
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
141
0
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
142
143
0
    if (l != r)
144
0
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
145
146
0
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
147
0
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
148
0
    if (reverse_l)
149
0
    {
150
0
      buf[0] = info[end - 1];
151
0
      info[end - 1] = info[end - 2];
152
0
      info[end - 2] = buf[0];
153
0
    }
154
0
    if (reverse_r)
155
0
    {
156
0
      buf[0] = info[start];
157
0
      info[start] = info[start + 1];
158
0
      info[start + 1] = buf[0];
159
0
    }
160
0
  }
161
0
      }
162
0
    }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ExtendedTypes, void, AAT::RearrangementSubtable<AAT::ExtendedTypes>::Flags>*, AAT::Entry<void> const&)
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, void, AAT::RearrangementSubtable<AAT::ObsoleteTypes>::Flags>*, AAT::Entry<void> const&)
163
164
    public:
165
    bool ret;
166
    const RearrangementSubtable *table;
167
    private:
168
    unsigned int start;
169
    unsigned int end;
170
  };
171
172
  bool apply (hb_aat_apply_context_t *c) const
173
0
  {
174
0
    TRACE_APPLY (this);
175
176
0
    driver_context_t dc (this);
177
178
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
179
180
0
    driver.drive (&dc, c);
181
182
0
    return_trace (dc.ret);
183
0
  }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
184
185
  bool sanitize (hb_sanitize_context_t *c) const
186
0
  {
187
0
    TRACE_SANITIZE (this);
188
0
    return_trace (machine.sanitize (c));
189
0
  }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
190
191
  public:
192
  StateTable<Types, EntryData>  machine;
193
  public:
194
  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size));
195
};
196
197
template <typename Types>
198
struct ContextualSubtable
199
{
200
  typedef typename Types::HBUINT HBUINT;
201
202
  struct EntryData
203
  {
204
    typedef typename std::conditional<Types::extended, HBUINT16, HBINT16>::type OffsetType;
205
206
    OffsetType  markIndex;  /* Index/offset of the substitution table for the
207
         * marked glyph. */
208
    OffsetType  currentIndex; /* Index/offset of the substitution table for the
209
         * current glyph. */
210
    public:
211
    DEFINE_SIZE_STATIC (4);
212
  };
213
214
  enum Flags
215
  {
216
    SetMark   = 0x8000, /* If set, make the current glyph the marked glyph. */
217
    DontAdvance   = 0x4000, /* If set, don't advance to the next glyph before
218
           * going to the new state. */
219
    Reserved    = 0x3FFF, /* These bits are reserved and should be set to 0. */
220
  };
221
222
  bool is_action_initiable (const Entry<EntryData> &entry) const
223
0
  {
224
0
    return (entry.flags & SetMark);
225
0
  }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::is_action_initiable(AAT::Entry<AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData> const&) const
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::is_action_initiable(AAT::Entry<AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData> const&) const
226
  bool is_actionable (const Entry<EntryData> &entry) const
227
0
  {
228
0
    if (Types::extended)
229
0
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
230
0
    else
231
0
      return entry.data.markIndex || entry.data.currentIndex;
232
0
  }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::is_actionable(AAT::Entry<AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData> const&) const
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::is_actionable(AAT::Entry<AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData> const&) const
233
234
  struct driver_context_t
235
  {
236
    static constexpr bool in_place = true;
237
238
    driver_context_t (const ContextualSubtable *table_,
239
           hb_aat_apply_context_t *c_) :
240
0
  ret (false),
241
0
  c (c_),
242
0
  table (table_),
243
0
  mark_set (false),
244
0
  mark (0),
245
0
  subs (table+table->substitutionTables) {}
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::ContextualSubtable<AAT::ExtendedTypes> const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::ContextualSubtable<AAT::ObsoleteTypes> const*, AAT::hb_aat_apply_context_t*)
246
247
    HB_AAT_TRANSITION_INLINE
248
    void transition (hb_buffer_t *buffer,
249
         StateTableDriver<Types, EntryData, Flags> *driver,
250
         const Entry<EntryData> &entry)
251
0
    {
252
      /* Looks like CoreText applies neither mark nor current substitution for
253
       * end-of-text if mark was not explicitly set. */
254
0
      if (buffer->idx == buffer->len && !mark_set)
255
0
  return;
256
257
0
      const HBGlyphID16 *replacement;
258
259
0
      replacement = nullptr;
260
0
      if (Types::extended)
261
0
      {
262
0
  if (entry.data.markIndex != 0xFFFF)
263
0
  {
264
0
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
265
0
    replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
266
0
  }
267
0
      }
268
0
      else
269
0
      {
270
0
  if (entry.data.markIndex)
271
0
  {
272
0
    int offset = (int) entry.data.markIndex + buffer->info[mark].codepoint;
273
0
    const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
274
0
    replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
275
0
    if (!(replacement->sanitize (&c->sanitizer) &&
276
0
    hb_barrier () &&
277
0
    *replacement))
278
0
      replacement = nullptr;
279
0
  }
280
0
      }
281
0
      if (replacement)
282
0
      {
283
0
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
284
0
  c->replace_glyph_inplace (mark, *replacement);
285
0
  ret = true;
286
0
      }
287
288
0
      replacement = nullptr;
289
0
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
290
0
      if (Types::extended)
291
0
      {
292
0
  if (entry.data.currentIndex != 0xFFFF)
293
0
  {
294
0
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
295
0
    replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
296
0
  }
297
0
      }
298
0
      else
299
0
      {
300
0
  if (entry.data.currentIndex)
301
0
  {
302
0
    int offset = (int) entry.data.currentIndex + buffer->info[idx].codepoint;
303
0
    const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
304
0
    replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
305
0
    if (!(replacement->sanitize (&c->sanitizer) &&
306
0
    hb_barrier () &&
307
0
    *replacement))
308
0
      replacement = nullptr;
309
0
  }
310
0
      }
311
0
      if (replacement)
312
0
      {
313
0
  c->replace_glyph_inplace (idx, *replacement);
314
0
  ret = true;
315
0
      }
316
317
0
      if (entry.flags & SetMark)
318
0
      {
319
0
  mark_set = true;
320
0
  mark = buffer->idx;
321
0
      }
322
0
    }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ExtendedTypes, AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData, AAT::ContextualSubtable<AAT::ExtendedTypes>::Flags>*, AAT::Entry<AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData> const&)
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData, AAT::ContextualSubtable<AAT::ObsoleteTypes>::Flags>*, AAT::Entry<AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData> const&)
323
324
    public:
325
    bool ret;
326
    hb_aat_apply_context_t *c;
327
    const ContextualSubtable *table;
328
    private:
329
    bool mark_set;
330
    unsigned int mark;
331
    const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
332
  };
333
334
  bool apply (hb_aat_apply_context_t *c) const
335
0
  {
336
0
    TRACE_APPLY (this);
337
338
0
    driver_context_t dc (this, c);
339
340
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
341
342
0
    driver.drive (&dc, c);
343
344
0
    return_trace (dc.ret);
345
0
  }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
346
347
  bool sanitize (hb_sanitize_context_t *c) const
348
0
  {
349
0
    TRACE_SANITIZE (this);
350
351
0
    unsigned int num_entries = 0;
352
0
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
353
0
    hb_barrier ();
354
355
0
    if (!Types::extended)
356
0
      return_trace (substitutionTables.sanitize (c, this, 0));
357
358
0
    unsigned int num_lookups = 0;
359
360
0
    const Entry<EntryData> *entries = machine.get_entries ();
361
0
    for (unsigned int i = 0; i < num_entries; i++)
362
0
    {
363
0
      const EntryData &data = entries[i].data;
364
365
0
      if (data.markIndex != 0xFFFF)
366
0
  num_lookups = hb_max (num_lookups, 1u + data.markIndex);
367
0
      if (data.currentIndex != 0xFFFF)
368
0
  num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
369
0
    }
370
371
0
    return_trace (substitutionTables.sanitize (c, this, num_lookups));
372
0
  }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
373
374
  public:
375
  StateTable<Types, EntryData>
376
    machine;
377
  protected:
378
  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
379
    substitutionTables;
380
  public:
381
  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
382
};
383
384
385
template <bool extended>
386
struct LigatureEntry;
387
388
template <>
389
struct LigatureEntry<true>
390
{
391
392
  struct EntryData
393
  {
394
    HBUINT16  ligActionIndex; /* Index to the first ligActionTable entry
395
         * for processing this group, if indicated
396
         * by the flags. */
397
    public:
398
    DEFINE_SIZE_STATIC (2);
399
  };
400
401
  enum Flags
402
  {
403
    SetComponent  = 0x8000, /* Push this glyph onto the component stack for
404
           * eventual processing. */
405
    DontAdvance   = 0x4000, /* Leave the glyph pointer at this glyph for the
406
             next iteration. */
407
    PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature
408
           * group. */
409
    Reserved    = 0x1FFF, /* These bits are reserved and should be set to 0. */
410
  };
411
412
  static bool initiateAction (const Entry<EntryData> &entry)
413
0
  { return entry.flags & SetComponent; }
414
415
  static bool performAction (const Entry<EntryData> &entry)
416
0
  { return entry.flags & PerformAction; }
417
418
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
419
0
  { return entry.data.ligActionIndex; }
420
};
421
template <>
422
struct LigatureEntry<false>
423
{
424
  typedef void EntryData;
425
426
  enum Flags
427
  {
428
    SetComponent  = 0x8000, /* Push this glyph onto the component stack for
429
           * eventual processing. */
430
    DontAdvance   = 0x4000, /* Leave the glyph pointer at this glyph for the
431
             next iteration. */
432
    Offset    = 0x3FFF, /* Byte offset from beginning of subtable to the
433
           * ligature action list. This value must be a
434
           * multiple of 4. */
435
  };
436
437
  static bool initiateAction (const Entry<EntryData> &entry)
438
0
  { return entry.flags & SetComponent; }
439
440
  static bool performAction (const Entry<EntryData> &entry)
441
0
  { return entry.flags & Offset; }
442
443
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
444
0
  { return entry.flags & Offset; }
445
};
446
447
448
template <typename Types>
449
struct LigatureSubtable
450
{
451
  typedef typename Types::HBUINT HBUINT;
452
453
  typedef LigatureEntry<Types::extended> LigatureEntryT;
454
  typedef typename LigatureEntryT::EntryData EntryData;
455
456
  enum Flags
457
  {
458
    DontAdvance = LigatureEntryT::DontAdvance,
459
  };
460
461
  bool is_action_initiable (const Entry<EntryData> &entry) const
462
0
  {
463
0
    return LigatureEntryT::initiateAction (entry);
464
0
  }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::is_action_initiable(AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&) const
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::is_action_initiable(AAT::Entry<void> const&) const
465
  bool is_actionable (const Entry<EntryData> &entry) const
466
0
  {
467
0
    return LigatureEntryT::performAction (entry);
468
0
  }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::is_actionable(AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&) const
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::is_actionable(AAT::Entry<void> const&) const
469
470
  struct driver_context_t
471
  {
472
    static constexpr bool in_place = false;
473
    enum LigActionFlags
474
    {
475
      LigActionLast = 0x80000000, /* This is the last action in the list. This also
476
           * implies storage. */
477
      LigActionStore  = 0x40000000, /* Store the ligature at the current cumulated index
478
           * in the ligature table in place of the marked
479
           * (i.e. currently-popped) glyph. */
480
      LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits
481
           * and added to the glyph ID, resulting in an index
482
           * into the component table. */
483
    };
484
485
    driver_context_t (const LigatureSubtable *table_,
486
          hb_aat_apply_context_t *c_) :
487
0
  ret (false),
488
0
  c (c_),
489
0
  table (table_),
490
0
  ligAction (table+table->ligAction),
491
0
  component (table+table->component),
492
0
  ligature (table+table->ligature),
493
0
  match_length (0) {}
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::LigatureSubtable<AAT::ExtendedTypes> const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::LigatureSubtable<AAT::ObsoleteTypes> const*, AAT::hb_aat_apply_context_t*)
494
495
    HB_AAT_TRANSITION_INLINE
496
    void transition (hb_buffer_t *buffer,
497
         StateTableDriver<Types, EntryData, Flags> *driver,
498
         const Entry<EntryData> &entry)
499
0
    {
500
0
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
501
0
      if (entry.flags & LigatureEntryT::SetComponent)
502
0
      {
503
  /* Never mark same index twice, in case DontAdvance was used... */
504
0
  if (unlikely (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len))
505
0
    match_length--;
506
507
0
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
508
0
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
509
0
      }
510
511
0
      if (LigatureEntryT::performAction (entry))
512
0
      {
513
0
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
514
0
  unsigned int end = buffer->out_len;
515
516
0
  if (unlikely (!match_length))
517
0
    return;
518
519
0
  if (buffer->idx >= buffer->len)
520
0
    return; /* TODO Work on previous instead? */
521
522
0
  unsigned int cursor = match_length;
523
524
0
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
525
0
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
526
0
  const HBUINT32 *actionData = &ligAction[action_idx];
527
528
0
  unsigned int ligature_idx = 0;
529
0
  unsigned int action;
530
0
  do
531
0
  {
532
0
    if (unlikely (!cursor))
533
0
    {
534
      /* Stack underflow.  Clear the stack. */
535
0
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
536
0
      match_length = 0;
537
0
      break;
538
0
    }
539
540
0
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
541
0
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
542
543
0
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
544
0
    hb_barrier ();
545
0
    action = *actionData;
546
547
0
    uint32_t uoffset = action & LigActionOffset;
548
0
    if (uoffset & 0x20000000)
549
0
      uoffset |= 0xC0000000; /* Sign-extend. */
550
0
    int32_t offset = (int32_t) uoffset;
551
0
    unsigned int component_idx = buffer->cur().codepoint + offset;
552
0
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
553
0
    const HBUINT16 &componentData = component[component_idx];
554
0
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
555
0
    hb_barrier ();
556
0
    ligature_idx += componentData;
557
558
0
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
559
0
         bool (action & LigActionStore),
560
0
         bool (action & LigActionLast));
561
0
    if (action & (LigActionStore | LigActionLast))
562
0
    {
563
0
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
564
0
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
565
0
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
566
0
      hb_barrier ();
567
0
      hb_codepoint_t lig = ligatureData;
568
569
0
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
570
0
      if (unlikely (!c->replace_glyph (lig))) return;
571
572
0
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
573
      /* Now go and delete all subsequent components. */
574
0
      while (match_length - 1u > cursor)
575
0
      {
576
0
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
577
0
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
578
0
        if (!c->delete_glyph ()) return;
579
0
      }
580
581
0
      if (unlikely (!buffer->move_to (lig_end))) return;
582
0
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
583
0
    }
584
585
0
    actionData++;
586
0
  }
587
0
  while (!(action & LigActionLast));
588
0
  if (unlikely (!buffer->move_to (end))) return;
589
0
      }
590
0
    }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ExtendedTypes, AAT::LigatureEntry<true>::EntryData, AAT::LigatureSubtable<AAT::ExtendedTypes>::Flags>*, AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&)
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, void, AAT::LigatureSubtable<AAT::ObsoleteTypes>::Flags>*, AAT::Entry<void> const&)
591
592
    public:
593
    bool ret;
594
    hb_aat_apply_context_t *c;
595
    const LigatureSubtable *table;
596
    private:
597
    const UnsizedArrayOf<HBUINT32> &ligAction;
598
    const UnsizedArrayOf<HBUINT16> &component;
599
    const UnsizedArrayOf<HBGlyphID16> &ligature;
600
    unsigned int match_length;
601
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
602
  };
603
604
  bool apply (hb_aat_apply_context_t *c) const
605
0
  {
606
0
    TRACE_APPLY (this);
607
608
0
    driver_context_t dc (this, c);
609
610
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
611
612
0
    driver.drive (&dc, c);
613
614
0
    return_trace (dc.ret);
615
0
  }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
616
617
  bool sanitize (hb_sanitize_context_t *c) const
618
0
  {
619
0
    TRACE_SANITIZE (this);
620
    /* The rest of array sanitizations are done at run-time. */
621
0
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
622
0
      hb_barrier () &&
623
0
      ligAction && component && ligature);
624
0
  }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
625
626
  public:
627
  StateTable<Types, EntryData>
628
    machine;
629
  protected:
630
  NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
631
    ligAction;  /* Offset to the ligature action table. */
632
  NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
633
    component;  /* Offset to the component table. */
634
  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
635
    ligature; /* Offset to the actual ligature lists. */
636
  public:
637
  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size));
638
};
639
640
template <typename Types>
641
struct NoncontextualSubtable
642
{
643
  bool apply (hb_aat_apply_context_t *c) const
644
0
  {
645
0
    TRACE_APPLY (this);
646
647
0
    bool ret = false;
648
0
    unsigned int num_glyphs = c->face->get_num_glyphs ();
649
650
0
    hb_glyph_info_t *info = c->buffer->info;
651
0
    unsigned int count = c->buffer->len;
652
    // If there's only one range, we already checked the flag.
653
0
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
654
0
    for (unsigned int i = 0; i < count; i++)
655
0
    {
656
      /* This block copied from StateTableDriver::drive. Keep in sync. */
657
0
      if (unlikely (last_range))
658
0
      {
659
0
  auto *range = last_range;
660
0
  {
661
0
    unsigned cluster = info[i].cluster;
662
0
    while (cluster < range->cluster_first)
663
0
      range--;
664
0
    while (cluster > range->cluster_last)
665
0
      range++;
666
667
0
    last_range = range;
668
0
  }
669
0
  if (!(range->flags & c->subtable_flags))
670
0
    continue;
671
0
      }
672
673
0
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
674
0
      if (replacement)
675
0
      {
676
0
  c->replace_glyph_inplace (i, *replacement);
677
0
  ret = true;
678
0
      }
679
0
    }
680
681
0
    return_trace (ret);
682
0
  }
Unexecuted instantiation: AAT::NoncontextualSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
683
684
  template <typename set_t>
685
  void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs) const
686
0
  {
687
0
    substitute.collect_glyphs (glyphs, num_glyphs);
688
0
  }
Unexecuted instantiation: void AAT::NoncontextualSubtable<AAT::ExtendedTypes>::collect_initial_glyphs<hb_bit_set_t>(hb_bit_set_t&, unsigned int) const
Unexecuted instantiation: void AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::collect_initial_glyphs<hb_bit_set_t>(hb_bit_set_t&, unsigned int) const
689
690
  bool sanitize (hb_sanitize_context_t *c) const
691
0
  {
692
0
    TRACE_SANITIZE (this);
693
0
    return_trace (substitute.sanitize (c));
694
0
  }
Unexecuted instantiation: AAT::NoncontextualSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
695
696
  protected:
697
  Lookup<HBGlyphID16> substitute;
698
  public:
699
  DEFINE_SIZE_MIN (2);
700
};
701
702
template <typename Types>
703
struct InsertionSubtable
704
{
705
  typedef typename Types::HBUINT HBUINT;
706
707
  struct EntryData
708
  {
709
    HBUINT16  currentInsertIndex; /* Zero-based index into the insertion glyph table.
710
           * The number of glyphs to be inserted is contained
711
           * in the currentInsertCount field in the flags.
712
           * A value of 0xFFFF indicates no insertion is to
713
           * be done. */
714
    HBUINT16  markedInsertIndex;  /* Zero-based index into the insertion glyph table.
715
           * The number of glyphs to be inserted is contained
716
           * in the markedInsertCount field in the flags.
717
           * A value of 0xFFFF indicates no insertion is to
718
           * be done. */
719
    public:
720
    DEFINE_SIZE_STATIC (4);
721
  };
722
723
  enum Flags
724
  {
725
    SetMark   = 0x8000,     /* If set, mark the current glyph. */
726
    DontAdvance   = 0x4000,     /* If set, don't advance to the next glyph before
727
               * going to the new state.  This does not mean
728
               * that the glyph pointed to is the same one as
729
               * before. If you've made insertions immediately
730
               * downstream of the current glyph, the next glyph
731
               * processed would in fact be the first one
732
               * inserted. */
733
    CurrentIsKashidaLike= 0x2000,     /* If set, and the currentInsertList is nonzero,
734
               * then the specified glyph list will be inserted
735
               * as a kashida-like insertion, either before or
736
               * after the current glyph (depending on the state
737
               * of the currentInsertBefore flag). If clear, and
738
               * the currentInsertList is nonzero, then the
739
               * specified glyph list will be inserted as a
740
               * split-vowel-like insertion, either before or
741
               * after the current glyph (depending on the state
742
               * of the currentInsertBefore flag). */
743
    MarkedIsKashidaLike= 0x1000,      /* If set, and the markedInsertList is nonzero,
744
               * then the specified glyph list will be inserted
745
               * as a kashida-like insertion, either before or
746
               * after the marked glyph (depending on the state
747
               * of the markedInsertBefore flag). If clear, and
748
               * the markedInsertList is nonzero, then the
749
               * specified glyph list will be inserted as a
750
               * split-vowel-like insertion, either before or
751
               * after the marked glyph (depending on the state
752
               * of the markedInsertBefore flag). */
753
    CurrentInsertBefore= 0x0800,      /* If set, specifies that insertions are to be made
754
               * to the left of the current glyph. If clear,
755
               * they're made to the right of the current glyph. */
756
    MarkedInsertBefore= 0x0400,       /* If set, specifies that insertions are to be
757
               * made to the left of the marked glyph. If clear,
758
               * they're made to the right of the marked glyph. */
759
    CurrentInsertCount= 0x3E0,        /* This 5-bit field is treated as a count of the
760
               * number of glyphs to insert at the current
761
               * position. Since zero means no insertions, the
762
               * largest number of insertions at any given
763
               * current location is 31 glyphs. */
764
    MarkedInsertCount= 0x001F,        /* This 5-bit field is treated as a count of the
765
               * number of glyphs to insert at the marked
766
               * position. Since zero means no insertions, the
767
               * largest number of insertions at any given
768
               * marked location is 31 glyphs. */
769
  };
770
771
  bool is_action_initiable (const Entry<EntryData> &entry) const
772
0
  {
773
0
    return (entry.flags & SetMark);
774
0
  }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::is_action_initiable(AAT::Entry<AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData> const&) const
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::is_action_initiable(AAT::Entry<AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData> const&) const
775
  bool is_actionable (const Entry<EntryData> &entry) const
776
0
  {
777
0
    return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
778
0
     (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
779
0
  }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::is_actionable(AAT::Entry<AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData> const&) const
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::is_actionable(AAT::Entry<AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData> const&) const
780
781
  struct driver_context_t
782
  {
783
    static constexpr bool in_place = false;
784
785
    driver_context_t (const InsertionSubtable *table_,
786
          hb_aat_apply_context_t *c_) :
787
0
  ret (false),
788
0
  c (c_),
789
0
  table (table_),
790
0
  mark (0),
791
0
  insertionAction (table+table->insertionAction) {}
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::InsertionSubtable<AAT::ExtendedTypes> const*, AAT::hb_aat_apply_context_t*)
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::InsertionSubtable<AAT::ObsoleteTypes> const*, AAT::hb_aat_apply_context_t*)
792
793
    HB_AAT_TRANSITION_INLINE
794
    void transition (hb_buffer_t *buffer,
795
         StateTableDriver<Types, EntryData, Flags> *driver,
796
         const Entry<EntryData> &entry)
797
0
    {
798
0
      unsigned int flags = entry.flags;
799
800
0
      unsigned mark_loc = buffer->out_len;
801
802
0
      if (entry.data.markedInsertIndex != 0xFFFF)
803
0
      {
804
0
  unsigned int count = (flags & MarkedInsertCount);
805
0
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
806
0
  unsigned int start = entry.data.markedInsertIndex;
807
0
  const HBGlyphID16 *glyphs = &insertionAction[start];
808
0
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
809
0
  hb_barrier ();
810
811
0
  bool before = flags & MarkedInsertBefore;
812
813
0
  unsigned int end = buffer->out_len;
814
0
  if (unlikely (!buffer->move_to (mark))) return;
815
816
0
  if (buffer->idx < buffer->len && !before)
817
0
    if (unlikely (!buffer->copy_glyph ())) return;
818
  /* TODO We ignore KashidaLike setting. */
819
0
  if (unlikely (!c->output_glyphs (count, glyphs))) return;
820
0
  ret = true;
821
0
  if (buffer->idx < buffer->len && !before)
822
0
    buffer->skip_glyph ();
823
824
0
  if (unlikely (!buffer->move_to (end + count))) return;
825
826
0
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
827
0
      }
828
829
0
      if (flags & SetMark)
830
0
  mark = mark_loc;
831
832
0
      if (entry.data.currentInsertIndex != 0xFFFF)
833
0
      {
834
0
  unsigned int count = (flags & CurrentInsertCount) >> 5;
835
0
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
836
0
  unsigned int start = entry.data.currentInsertIndex;
837
0
  const HBGlyphID16 *glyphs = &insertionAction[start];
838
0
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
839
0
  hb_barrier ();
840
841
0
  bool before = flags & CurrentInsertBefore;
842
843
0
  unsigned int end = buffer->out_len;
844
845
0
  if (buffer->idx < buffer->len && !before)
846
0
    if (unlikely (!buffer->copy_glyph ())) return;
847
  /* TODO We ignore KashidaLike setting. */
848
0
  if (unlikely (!c->output_glyphs (count, glyphs))) return;
849
0
  ret = true;
850
0
  if (buffer->idx < buffer->len && !before)
851
0
    buffer->skip_glyph ();
852
853
  /* Humm. Not sure where to move to.  There's this wording under
854
   * DontAdvance flag:
855
   *
856
   * "If set, don't update the glyph index before going to the new state.
857
   * This does not mean that the glyph pointed to is the same one as
858
   * before. If you've made insertions immediately downstream of the
859
   * current glyph, the next glyph processed would in fact be the first
860
   * one inserted."
861
   *
862
   * This suggests that if DontAdvance is NOT set, we should move to
863
   * end+count.  If it *was*, then move to end, such that newly inserted
864
   * glyphs are now visible.
865
   *
866
   * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
867
   */
868
0
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
869
0
      }
870
0
    }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ExtendedTypes, AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData, AAT::InsertionSubtable<AAT::ExtendedTypes>::Flags>*, AAT::Entry<AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData> const&)
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData, AAT::InsertionSubtable<AAT::ObsoleteTypes>::Flags>*, AAT::Entry<AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData> const&)
871
872
    public:
873
    bool ret;
874
    hb_aat_apply_context_t *c;
875
    const InsertionSubtable *table;
876
    private:
877
    unsigned int mark;
878
    const UnsizedArrayOf<HBGlyphID16> &insertionAction;
879
  };
880
881
  bool apply (hb_aat_apply_context_t *c) const
882
0
  {
883
0
    TRACE_APPLY (this);
884
885
0
    driver_context_t dc (this, c);
886
887
0
    StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
888
889
0
    driver.drive (&dc, c);
890
891
0
    return_trace (dc.ret);
892
0
  }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
893
894
  bool sanitize (hb_sanitize_context_t *c) const
895
0
  {
896
0
    TRACE_SANITIZE (this);
897
    /* The rest of array sanitizations are done at run-time. */
898
0
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
899
0
      hb_barrier () &&
900
0
      insertionAction);
901
0
  }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
902
903
  public:
904
  StateTable<Types, EntryData>
905
    machine;
906
  protected:
907
  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
908
    insertionAction;  /* Byte offset from stateHeader to the start of
909
           * the insertion glyph table. */
910
  public:
911
  DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size));
912
};
913
914
915
struct Feature
916
{
917
  bool sanitize (hb_sanitize_context_t *c) const
918
0
  {
919
0
    TRACE_SANITIZE (this);
920
0
    return_trace (c->check_struct (this));
921
0
  }
922
923
  public:
924
  HBUINT16  featureType;  /* The type of feature. */
925
  HBUINT16  featureSetting; /* The feature's setting (aka selector). */
926
  HBUINT32  enableFlags;  /* Flags for the settings that this feature
927
         * and setting enables. */
928
  HBUINT32  disableFlags; /* Complement of flags for the settings that this
929
         * feature and setting disable. */
930
931
  public:
932
  DEFINE_SIZE_STATIC (12);
933
};
934
935
936
struct hb_accelerate_subtables_context_t :
937
       hb_dispatch_context_t<hb_accelerate_subtables_context_t>
938
{
939
  struct hb_applicable_t
940
  {
941
    friend struct hb_accelerate_subtables_context_t;
942
    friend struct hb_aat_layout_lookup_accelerator_t;
943
944
    public:
945
    hb_bit_set_t glyph_set;
946
    mutable hb_aat_class_cache_t class_cache;
947
948
    template <typename T>
949
    auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
950
    (
951
      obj_.machine.collect_initial_glyphs (glyph_set, num_glyphs, obj_)
952
    )
953
954
    template <typename T>
955
    void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
956
0
    {
957
0
      obj_.collect_initial_glyphs (glyph_set, num_glyphs);
958
0
    }
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init_<AAT::NoncontextualSubtable<AAT::ExtendedTypes> >(AAT::NoncontextualSubtable<AAT::ExtendedTypes> const&, unsigned int, hb_priority<0u>)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init_<AAT::NoncontextualSubtable<AAT::ObsoleteTypes> >(AAT::NoncontextualSubtable<AAT::ObsoleteTypes> const&, unsigned int, hb_priority<0u>)
959
960
    template <typename T>
961
    void init (const T &obj_, unsigned num_glyphs)
962
0
    {
963
0
      glyph_set.init ();
964
0
      init_ (obj_, num_glyphs, hb_prioritize);
965
0
      class_cache.clear ();
966
0
    }
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::RearrangementSubtable<AAT::ExtendedTypes> >(AAT::RearrangementSubtable<AAT::ExtendedTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::ContextualSubtable<AAT::ExtendedTypes> >(AAT::ContextualSubtable<AAT::ExtendedTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::LigatureSubtable<AAT::ExtendedTypes> >(AAT::LigatureSubtable<AAT::ExtendedTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::NoncontextualSubtable<AAT::ExtendedTypes> >(AAT::NoncontextualSubtable<AAT::ExtendedTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::InsertionSubtable<AAT::ExtendedTypes> >(AAT::InsertionSubtable<AAT::ExtendedTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::RearrangementSubtable<AAT::ObsoleteTypes> >(AAT::RearrangementSubtable<AAT::ObsoleteTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::ContextualSubtable<AAT::ObsoleteTypes> >(AAT::ContextualSubtable<AAT::ObsoleteTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::LigatureSubtable<AAT::ObsoleteTypes> >(AAT::LigatureSubtable<AAT::ObsoleteTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::NoncontextualSubtable<AAT::ObsoleteTypes> >(AAT::NoncontextualSubtable<AAT::ObsoleteTypes> const&, unsigned int)
Unexecuted instantiation: void AAT::hb_accelerate_subtables_context_t::hb_applicable_t::init<AAT::InsertionSubtable<AAT::ObsoleteTypes> >(AAT::InsertionSubtable<AAT::ObsoleteTypes> const&, unsigned int)
967
968
    void
969
    fini ()
970
0
    {
971
0
      glyph_set.fini ();
972
0
    }
973
  };
974
975
  /* Dispatch interface. */
976
  template <typename T>
977
  return_t dispatch (const T &obj)
978
0
  {
979
0
    hb_applicable_t *entry = &array[i++];
980
981
0
    entry->init (obj, num_glyphs);
982
983
0
    return hb_empty_t ();
984
0
  }
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::RearrangementSubtable<AAT::ExtendedTypes> >(AAT::RearrangementSubtable<AAT::ExtendedTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::ContextualSubtable<AAT::ExtendedTypes> >(AAT::ContextualSubtable<AAT::ExtendedTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::LigatureSubtable<AAT::ExtendedTypes> >(AAT::LigatureSubtable<AAT::ExtendedTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::NoncontextualSubtable<AAT::ExtendedTypes> >(AAT::NoncontextualSubtable<AAT::ExtendedTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::InsertionSubtable<AAT::ExtendedTypes> >(AAT::InsertionSubtable<AAT::ExtendedTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::RearrangementSubtable<AAT::ObsoleteTypes> >(AAT::RearrangementSubtable<AAT::ObsoleteTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::ContextualSubtable<AAT::ObsoleteTypes> >(AAT::ContextualSubtable<AAT::ObsoleteTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::LigatureSubtable<AAT::ObsoleteTypes> >(AAT::LigatureSubtable<AAT::ObsoleteTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::NoncontextualSubtable<AAT::ObsoleteTypes> >(AAT::NoncontextualSubtable<AAT::ObsoleteTypes> const&)
Unexecuted instantiation: hb_empty_t AAT::hb_accelerate_subtables_context_t::dispatch<AAT::InsertionSubtable<AAT::ObsoleteTypes> >(AAT::InsertionSubtable<AAT::ObsoleteTypes> const&)
985
0
  static return_t default_return_value () { return hb_empty_t (); }
986
987
0
  bool stop_sublookup_iteration (return_t r) const { return false; }
988
989
  hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) :
990
0
             hb_dispatch_context_t<hb_accelerate_subtables_context_t> (),
991
0
             array (array_), num_glyphs (num_glyphs_) {}
992
993
  hb_applicable_t *array;
994
  unsigned num_glyphs;
995
  unsigned i = 0;
996
};
997
998
struct hb_aat_layout_chain_accelerator_t
999
{
1000
  template <typename TChain>
1001
  static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs)
1002
0
  {
1003
0
    unsigned count = chain.get_subtable_count ();
1004
1005
0
    unsigned product;
1006
0
    if (unlikely (hb_unsigned_mul_overflows (count,
1007
0
        sizeof (hb_accelerate_subtables_context_t::hb_applicable_t), &product)))
1008
0
      return nullptr;
1009
1010
0
    unsigned size;
1011
0
    if (unlikely (hb_unsigned_add_overflows (sizeof (hb_aat_layout_chain_accelerator_t) -
1012
0
        HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t), product, &size))) {
1013
0
      return nullptr;
1014
0
    }
1015
1016
    /* The following is a calloc because when we are collecting subtables,
1017
     * some of them might be invalid and hence not collect; as a result,
1018
     * we might not fill in all the count entries of the subtables array.
1019
     * Zeroing it allows the set digest to gatekeep it without having to
1020
     * initialize it further. */
1021
0
    auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size);
1022
0
    if (unlikely (!thiz))
1023
0
      return nullptr;
1024
1025
0
    thiz->count = count;
1026
1027
0
    hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
1028
0
    chain.dispatch (&c_accelerate_subtables);
1029
1030
0
    return thiz;
1031
0
  }
Unexecuted instantiation: AAT::hb_aat_layout_chain_accelerator_t* AAT::hb_aat_layout_chain_accelerator_t::create<AAT::Chain<AAT::ExtendedTypes> >(AAT::Chain<AAT::ExtendedTypes> const&, unsigned int)
Unexecuted instantiation: AAT::hb_aat_layout_chain_accelerator_t* AAT::hb_aat_layout_chain_accelerator_t::create<AAT::Chain<AAT::ObsoleteTypes> >(AAT::Chain<AAT::ObsoleteTypes> const&, unsigned int)
1032
1033
  void destroy ()
1034
0
  {
1035
0
    for (unsigned i = 0; i < count; i++)
1036
0
      subtables[i].fini ();
1037
0
  }
1038
1039
  unsigned count;
1040
  hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
1041
};
1042
1043
template <typename Types>
1044
struct ChainSubtable
1045
{
1046
  typedef typename Types::HBUINT HBUINT;
1047
1048
  template <typename T>
1049
  friend struct Chain;
1050
1051
0
  size_t get_size () const     { return length; }
Unexecuted instantiation: AAT::ChainSubtable<AAT::ExtendedTypes>::get_size() const
Unexecuted instantiation: AAT::ChainSubtable<AAT::ObsoleteTypes>::get_size() const
1052
0
  unsigned int get_type () const     { return coverage & 0xFF; }
Unexecuted instantiation: AAT::ChainSubtable<AAT::ExtendedTypes>::get_type() const
Unexecuted instantiation: AAT::ChainSubtable<AAT::ObsoleteTypes>::get_type() const
1053
0
  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
Unexecuted instantiation: AAT::ChainSubtable<AAT::ExtendedTypes>::get_coverage() const
Unexecuted instantiation: AAT::ChainSubtable<AAT::ObsoleteTypes>::get_coverage() const
1054
1055
  enum Coverage
1056
  {
1057
    Vertical    = 0x80, /* If set, this subtable will only be applied
1058
         * to vertical text. If clear, this subtable
1059
         * will only be applied to horizontal text. */
1060
    Backwards   = 0x40, /* If set, this subtable will process glyphs
1061
         * in descending order. If clear, it will
1062
         * process the glyphs in ascending order. */
1063
    AllDirections = 0x20, /* If set, this subtable will be applied to
1064
         * both horizontal and vertical text (i.e.
1065
         * the state of bit 0x80000000 is ignored). */
1066
    Logical   = 0x10, /* If set, this subtable will process glyphs
1067
         * in logical order (or reverse logical order,
1068
         * depending on the value of bit 0x80000000). */
1069
  };
1070
  enum Type
1071
  {
1072
    Rearrangement = 0,
1073
    Contextual    = 1,
1074
    Ligature    = 2,
1075
    Noncontextual = 4,
1076
    Insertion   = 5
1077
  };
1078
1079
  template <typename context_t, typename ...Ts>
1080
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1081
0
  {
1082
0
    unsigned int subtable_type = get_type ();
1083
0
    TRACE_DISPATCH (this, subtable_type);
1084
0
    switch (subtable_type) {
1085
0
    case Rearrangement:   hb_barrier (); return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
1086
0
    case Contextual:    hb_barrier (); return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
1087
0
    case Ligature:    hb_barrier (); return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
1088
0
    case Noncontextual:   hb_barrier (); return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
1089
0
    case Insertion:   hb_barrier (); return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
1090
0
    default:      return_trace (c->default_return_value ());
1091
0
    }
1092
0
  }
Unexecuted instantiation: hb_sanitize_context_t::return_t AAT::ChainSubtable<AAT::ExtendedTypes>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t AAT::ChainSubtable<AAT::ObsoleteTypes>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::hb_accelerate_subtables_context_t::return_t AAT::ChainSubtable<AAT::ExtendedTypes>::dispatch<AAT::hb_accelerate_subtables_context_t>(AAT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: AAT::hb_aat_apply_context_t::return_t AAT::ChainSubtable<AAT::ExtendedTypes>::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::hb_accelerate_subtables_context_t::return_t AAT::ChainSubtable<AAT::ObsoleteTypes>::dispatch<AAT::hb_accelerate_subtables_context_t>(AAT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: AAT::hb_aat_apply_context_t::return_t AAT::ChainSubtable<AAT::ObsoleteTypes>::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const
1093
1094
  bool apply (hb_aat_apply_context_t *c) const
1095
0
  {
1096
0
    TRACE_APPLY (this);
1097
    // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
1098
    //hb_sanitize_with_object_t with (&c->sanitizer, this);
1099
0
    return_trace (dispatch (c));
1100
0
  }
Unexecuted instantiation: AAT::ChainSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::ChainSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
1101
1102
  bool sanitize (hb_sanitize_context_t *c) const
1103
0
  {
1104
0
    TRACE_SANITIZE (this);
1105
0
    if (!(length.sanitize (c) &&
1106
0
    hb_barrier () &&
1107
0
    length >= min_size &&
1108
0
    c->check_range (this, length)))
1109
0
      return_trace (false);
1110
1111
    // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873
1112
    //hb_sanitize_with_object_t with (c, this);
1113
0
    return_trace (dispatch (c));
1114
0
  }
Unexecuted instantiation: AAT::ChainSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::ChainSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
1115
1116
  protected:
1117
  HBUINT  length;   /* Total subtable length, including this header. */
1118
  HBUINT  coverage; /* Coverage flags and subtable type. */
1119
  HBUINT32  subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
1120
  union {
1121
  RearrangementSubtable<Types>  rearrangement;
1122
  ContextualSubtable<Types> contextual;
1123
  LigatureSubtable<Types> ligature;
1124
  NoncontextualSubtable<Types>  noncontextual;
1125
  InsertionSubtable<Types>  insertion;
1126
  } u;
1127
  public:
1128
  DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
1129
};
1130
1131
template <typename Types>
1132
struct Chain
1133
{
1134
  typedef typename Types::HBUINT HBUINT;
1135
1136
0
  unsigned get_subtable_count () const { return subtableCount; }
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::get_subtable_count() const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::get_subtable_count() const
1137
1138
  hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
1139
0
  {
1140
0
    hb_mask_t flags = defaultFlags;
1141
0
    {
1142
0
      unsigned int count = featureCount;
1143
0
      for (unsigned i = 0; i < count; i++)
1144
0
      {
1145
0
  const Feature &feature = featureZ[i];
1146
0
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
1147
0
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
1148
0
      retry:
1149
  // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
1150
  // (The search here only looks at the type and setting fields of feature_info_t.)
1151
0
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
1152
0
  if (map->current_features.bsearch (info))
1153
0
  {
1154
0
    flags &= feature.disableFlags;
1155
0
    flags |= feature.enableFlags;
1156
0
  }
1157
0
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
1158
0
  {
1159
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
1160
0
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
1161
0
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1162
0
    goto retry;
1163
0
  }
1164
0
#ifndef HB_NO_AAT
1165
0
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1166
     /* TODO: Rudimentary language matching. */
1167
0
     hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
1168
0
  {
1169
0
    flags &= feature.disableFlags;
1170
0
    flags |= feature.enableFlags;
1171
0
  }
1172
0
#endif
1173
0
      }
1174
0
    }
1175
0
    return flags;
1176
0
  }
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::compile_flags(hb_aat_map_builder_t const*) const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::compile_flags(hb_aat_map_builder_t const*) const
1177
1178
  void apply (hb_aat_apply_context_t *c,
1179
        const hb_aat_layout_chain_accelerator_t *accel) const
1180
0
  {
1181
0
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1182
0
    unsigned int count = subtableCount;
1183
0
    for (unsigned int i = 0; i < count; i++)
1184
0
    {
1185
0
      bool reverse;
1186
1187
0
      auto coverage = subtable->get_coverage ();
1188
1189
0
      hb_mask_t subtable_flags = subtable->subFeatureFlags;
1190
0
      if (hb_none (hb_iter (c->range_flags) |
1191
0
       hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*, AAT::hb_aat_layout_chain_accelerator_t const*) const::{lambda(hb_aat_map_t::range_flags_t)#1}::operator()(hb_aat_map_t::range_flags_t) const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*, AAT::hb_aat_layout_chain_accelerator_t const*) const::{lambda(hb_aat_map_t::range_flags_t)#1}::operator()(hb_aat_map_t::range_flags_t) const
1192
0
  goto skip;
1193
1194
0
      if (!(coverage & ChainSubtable<Types>::AllDirections) &&
1195
0
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1196
0
    bool (coverage & ChainSubtable<Types>::Vertical))
1197
0
  goto skip;
1198
1199
0
      c->subtable_flags = subtable_flags;
1200
0
      c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
1201
0
      c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
1202
1203
0
      if (!c->buffer_intersects_machine ())
1204
0
      {
1205
0
  (void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
1206
0
  goto skip;
1207
0
      }
1208
1209
      /* Buffer contents is always in logical direction.  Determine if
1210
       * we need to reverse before applying this subtable.  We reverse
1211
       * back after if we did reverse indeed.
1212
       *
1213
       * Quoting the spac:
1214
       * """
1215
       * Bits 28 and 30 of the coverage field control the order in which
1216
       * glyphs are processed when the subtable is run by the layout engine.
1217
       * Bit 28 is used to indicate if the glyph processing direction is
1218
       * the same as logical order or layout order. Bit 30 is used to
1219
       * indicate whether glyphs are processed forwards or backwards within
1220
       * that order.
1221
1222
    Bit 30  Bit 28  Interpretation for Horizontal Text
1223
    0 0 The subtable is processed in layout order
1224
        (the same order as the glyphs, which is
1225
        always left-to-right).
1226
    1 0 The subtable is processed in reverse layout order
1227
        (the order opposite that of the glyphs, which is
1228
        always right-to-left).
1229
    0 1 The subtable is processed in logical order
1230
        (the same order as the characters, which may be
1231
        left-to-right or right-to-left).
1232
    1 1 The subtable is processed in reverse logical order
1233
        (the order opposite that of the characters, which
1234
        may be right-to-left or left-to-right).
1235
       */
1236
0
      reverse = coverage & ChainSubtable<Types>::Logical ?
1237
0
    bool (coverage & ChainSubtable<Types>::Backwards) :
1238
0
    bool (coverage & ChainSubtable<Types>::Backwards) !=
1239
0
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1240
1241
0
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1242
0
  goto skip;
1243
1244
0
      if (reverse != c->buffer_is_reversed)
1245
0
        c->reverse_buffer ();
1246
1247
0
      subtable->apply (c);
1248
1249
0
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1250
1251
0
      if (unlikely (!c->buffer->successful)) break;
1252
1253
0
    skip:
1254
0
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1255
0
      c->set_lookup_index (c->lookup_index + 1);
1256
0
    }
1257
0
    if (c->buffer_is_reversed)
1258
0
      c->reverse_buffer ();
1259
0
  }
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*, AAT::hb_aat_layout_chain_accelerator_t const*) const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*, AAT::hb_aat_layout_chain_accelerator_t const*) const
1260
1261
0
  size_t get_size () const { return length; }
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::get_size() const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::get_size() const
1262
1263
  template <typename context_t, typename ...Ts>
1264
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1265
0
  {
1266
0
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1267
0
    unsigned int count = subtableCount;
1268
0
    for (unsigned int i = 0; i < count; i++)
1269
0
    {
1270
0
      typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...);
1271
0
      if (c->stop_sublookup_iteration (ret))
1272
0
  return ret;
1273
0
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1274
0
    }
1275
0
    return c->default_return_value ();
1276
0
  }
Unexecuted instantiation: AAT::hb_accelerate_subtables_context_t::return_t AAT::Chain<AAT::ExtendedTypes>::dispatch<AAT::hb_accelerate_subtables_context_t>(AAT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: AAT::hb_accelerate_subtables_context_t::return_t AAT::Chain<AAT::ObsoleteTypes>::dispatch<AAT::hb_accelerate_subtables_context_t>(AAT::hb_accelerate_subtables_context_t*) const
1277
1278
  bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
1279
0
  {
1280
0
    TRACE_SANITIZE (this);
1281
0
    if (!(length.sanitize (c) &&
1282
0
    hb_barrier () &&
1283
0
    length >= min_size &&
1284
0
    c->check_range (this, length)))
1285
0
      return_trace (false);
1286
1287
0
    if (!c->check_array (featureZ.arrayZ, featureCount))
1288
0
      return_trace (false);
1289
1290
0
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1291
0
    unsigned int count = subtableCount;
1292
0
    for (unsigned int i = 0; i < count; i++)
1293
0
    {
1294
0
      if (!subtable->sanitize (c))
1295
0
  return_trace (false);
1296
0
      hb_barrier ();
1297
0
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1298
0
    }
1299
1300
0
    if (version >= 3)
1301
0
    {
1302
0
      const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable;
1303
0
      if (!coverage->sanitize (c, count))
1304
0
        return_trace (false);
1305
0
    }
1306
1307
0
    return_trace (true);
1308
0
  }
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*, unsigned int) const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*, unsigned int) const
1309
1310
  protected:
1311
  HBUINT32  defaultFlags; /* The default specification for subtables. */
1312
  HBUINT32  length;   /* Total byte count, including this header. */
1313
  HBUINT  featureCount; /* Number of feature subtable entries. */
1314
  HBUINT  subtableCount;  /* The number of subtables in the chain. */
1315
1316
  UnsizedArrayOf<Feature> featureZ; /* Features. */
1317
/*ChainSubtable firstSubtable;*//* Subtables. */
1318
/*SubtableGlyphCoverage coverages*//* Only if version >= 3. */
1319
1320
  public:
1321
  DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
1322
};
1323
1324
1325
/*
1326
 * The 'mort'/'morx' Table
1327
 */
1328
1329
template <typename T, typename Types, hb_tag_t TAG>
1330
struct mortmorx
1331
{
1332
  static constexpr hb_tag_t tableTag = TAG;
1333
1334
4.89k
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::has_data() const
Line
Count
Source
1334
2.44k
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::has_data() const
Line
Count
Source
1334
2.44k
  bool has_data () const { return version != 0; }
1335
1336
  struct accelerator_t
1337
  {
1338
    accelerator_t (hb_face_t *face)
1339
4.01k
    {
1340
4.01k
      hb_sanitize_context_t sc;
1341
4.01k
      this->table = sc.reference_table<T> (face);
1342
1343
4.01k
      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
1344
0
      {
1345
0
        hb_blob_destroy (this->table.get_blob ());
1346
0
        this->table = hb_blob_get_empty ();
1347
0
      }
1348
1349
4.01k
      this->chain_count = table->get_chain_count ();
1350
1351
4.01k
      this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
1352
4.01k
      if (unlikely (!this->accels))
1353
0
      {
1354
0
  this->chain_count = 0;
1355
0
  this->table.destroy ();
1356
0
  this->table = hb_blob_get_empty ();
1357
0
      }
1358
4.01k
    }
AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::accelerator_t::accelerator_t(hb_face_t*)
Line
Count
Source
1339
2.00k
    {
1340
2.00k
      hb_sanitize_context_t sc;
1341
2.00k
      this->table = sc.reference_table<T> (face);
1342
1343
2.00k
      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
1344
0
      {
1345
0
        hb_blob_destroy (this->table.get_blob ());
1346
0
        this->table = hb_blob_get_empty ();
1347
0
      }
1348
1349
2.00k
      this->chain_count = table->get_chain_count ();
1350
1351
2.00k
      this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
1352
2.00k
      if (unlikely (!this->accels))
1353
0
      {
1354
0
  this->chain_count = 0;
1355
0
  this->table.destroy ();
1356
0
  this->table = hb_blob_get_empty ();
1357
0
      }
1358
2.00k
    }
AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::accelerator_t::accelerator_t(hb_face_t*)
Line
Count
Source
1339
2.00k
    {
1340
2.00k
      hb_sanitize_context_t sc;
1341
2.00k
      this->table = sc.reference_table<T> (face);
1342
1343
2.00k
      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
1344
0
      {
1345
0
        hb_blob_destroy (this->table.get_blob ());
1346
0
        this->table = hb_blob_get_empty ();
1347
0
      }
1348
1349
2.00k
      this->chain_count = table->get_chain_count ();
1350
1351
2.00k
      this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
1352
2.00k
      if (unlikely (!this->accels))
1353
0
      {
1354
0
  this->chain_count = 0;
1355
0
  this->table.destroy ();
1356
0
  this->table = hb_blob_get_empty ();
1357
0
      }
1358
2.00k
    }
1359
    ~accelerator_t ()
1360
4.01k
    {
1361
4.01k
      for (unsigned int i = 0; i < this->chain_count; i++)
1362
0
      {
1363
0
  if (this->accels[i])
1364
0
    this->accels[i]->destroy ();
1365
0
  hb_free (this->accels[i]);
1366
0
      }
1367
4.01k
      hb_free (this->accels);
1368
4.01k
      this->table.destroy ();
1369
4.01k
    }
AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::accelerator_t::~accelerator_t()
Line
Count
Source
1360
2.00k
    {
1361
2.00k
      for (unsigned int i = 0; i < this->chain_count; i++)
1362
0
      {
1363
0
  if (this->accels[i])
1364
0
    this->accels[i]->destroy ();
1365
0
  hb_free (this->accels[i]);
1366
0
      }
1367
2.00k
      hb_free (this->accels);
1368
2.00k
      this->table.destroy ();
1369
2.00k
    }
AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::accelerator_t::~accelerator_t()
Line
Count
Source
1360
2.00k
    {
1361
2.00k
      for (unsigned int i = 0; i < this->chain_count; i++)
1362
0
      {
1363
0
  if (this->accels[i])
1364
0
    this->accels[i]->destroy ();
1365
0
  hb_free (this->accels[i]);
1366
0
      }
1367
2.00k
      hb_free (this->accels);
1368
2.00k
      this->table.destroy ();
1369
2.00k
    }
1370
1371
0
    hb_blob_t *get_blob () const { return table.get_blob (); }
Unexecuted instantiation: AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::accelerator_t::get_blob() const
Unexecuted instantiation: AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::accelerator_t::get_blob() const
1372
1373
    template <typename Chain>
1374
    hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const
1375
0
    {
1376
0
      if (unlikely (chain_index >= chain_count)) return nullptr;
1377
1378
0
    retry:
1379
0
      auto *accel = accels[chain_index].get_acquire ();
1380
0
      if (unlikely (!accel))
1381
0
      {
1382
0
  accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs);
1383
0
  if (unlikely (!accel))
1384
0
    return nullptr;
1385
1386
0
  if (unlikely (!accels[chain_index].cmpexch (nullptr, accel)))
1387
0
  {
1388
0
    hb_free (accel);
1389
0
    goto retry;
1390
0
  }
1391
0
      }
1392
1393
0
      return accel;
1394
0
    }
Unexecuted instantiation: AAT::hb_aat_layout_chain_accelerator_t* AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::accelerator_t::get_accel<AAT::Chain<AAT::ExtendedTypes> >(unsigned int, AAT::Chain<AAT::ExtendedTypes> const&, unsigned int) const
Unexecuted instantiation: AAT::hb_aat_layout_chain_accelerator_t* AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::accelerator_t::get_accel<AAT::Chain<AAT::ObsoleteTypes> >(unsigned int, AAT::Chain<AAT::ObsoleteTypes> const&, unsigned int) const
1395
1396
    hb_blob_ptr_t<T> table;
1397
    unsigned int chain_count;
1398
    hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
1399
    hb_aat_scratch_t scratch;
1400
  };
1401
1402
1403
  void compile_flags (const hb_aat_map_builder_t *mapper,
1404
          hb_aat_map_t *map) const
1405
0
  {
1406
0
    const Chain<Types> *chain = &firstChain;
1407
0
    unsigned int count = chainCount;
1408
0
    if (unlikely (!map->chain_flags.resize (count)))
1409
0
      return;
1410
0
    for (unsigned int i = 0; i < count; i++)
1411
0
    {
1412
0
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1413
0
                   mapper->range_first,
1414
0
                   mapper->range_last});
1415
0
      chain = &StructAfter<Chain<Types>> (*chain);
1416
0
    }
1417
0
  }
Unexecuted instantiation: AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
Unexecuted instantiation: AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
1418
1419
  unsigned get_chain_count () const
1420
4.01k
  {
1421
4.01k
    return chainCount;
1422
4.01k
  }
AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::get_chain_count() const
Line
Count
Source
1420
2.00k
  {
1421
2.00k
    return chainCount;
1422
2.00k
  }
AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::get_chain_count() const
Line
Count
Source
1420
2.00k
  {
1421
2.00k
    return chainCount;
1422
2.00k
  }
1423
  void apply (hb_aat_apply_context_t *c,
1424
        const hb_aat_map_t &map,
1425
        const accelerator_t &accel) const
1426
0
  {
1427
0
    if (unlikely (!c->buffer->successful)) return;
1428
1429
0
    c->buffer->unsafe_to_concat ();
1430
1431
0
    c->setup_buffer_glyph_set ();
1432
1433
0
    c->set_lookup_index (0);
1434
0
    const Chain<Types> *chain = &firstChain;
1435
0
    unsigned int count = chainCount;
1436
0
    for (unsigned int i = 0; i < count; i++)
1437
0
    {
1438
0
      auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ());
1439
0
      c->range_flags = &map.chain_flags[i];
1440
0
      chain->apply (c, chain_accel);
1441
0
      if (unlikely (!c->buffer->successful)) return;
1442
0
      chain = &StructAfter<Chain<Types>> (*chain);
1443
0
    }
1444
0
  }
Unexecuted instantiation: AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&, AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::accelerator_t const&) const
Unexecuted instantiation: AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&, AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::accelerator_t const&) const
1445
1446
  bool sanitize (hb_sanitize_context_t *c) const
1447
0
  {
1448
0
    TRACE_SANITIZE (this);
1449
0
    if (!(version.sanitize (c) &&
1450
0
    hb_barrier () &&
1451
0
    version &&
1452
0
    chainCount.sanitize (c)))
1453
0
      return_trace (false);
1454
1455
0
    const Chain<Types> *chain = &firstChain;
1456
0
    unsigned int count = chainCount;
1457
0
    for (unsigned int i = 0; i < count; i++)
1458
0
    {
1459
0
      if (!chain->sanitize (c, version))
1460
0
  return_trace (false);
1461
0
      hb_barrier ();
1462
0
      chain = &StructAfter<Chain<Types>> (*chain);
1463
0
    }
1464
1465
0
    return_trace (true);
1466
0
  }
Unexecuted instantiation: AAT::mortmorx<AAT::morx, AAT::ExtendedTypes, 1836020344u>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::mortmorx<AAT::mort, AAT::ObsoleteTypes, 1836020340u>::sanitize(hb_sanitize_context_t*) const
1467
1468
  protected:
1469
  HBUINT16  version;  /* Version number of the glyph metamorphosis table.
1470
         * 1, 2, or 3. */
1471
  HBUINT16  unused;   /* Set to 0. */
1472
  HBUINT32  chainCount; /* Number of metamorphosis chains contained in this
1473
         * table. */
1474
  Chain<Types>  firstChain; /* Chains. */
1475
1476
  public:
1477
  DEFINE_SIZE_MIN (8);
1478
};
1479
1480
struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx>
1481
{
1482
  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
1483
                                   hb_face_t *face) const;
1484
};
1485
1486
struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort>
1487
{
1488
  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
1489
                                   hb_face_t *face) const;
1490
};
1491
1492
struct morx_accelerator_t : morx::accelerator_t {
1493
2.00k
  morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}
1494
};
1495
struct mort_accelerator_t : mort::accelerator_t {
1496
2.00k
  mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {}
1497
};
1498
1499
1500
} /* namespace AAT */
1501
1502
1503
#endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */