Coverage Report

Created: 2025-07-11 06:04

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