Coverage Report

Created: 2026-05-30 06:20

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