Coverage Report

Created: 2023-09-25 06:24

/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-common.hh"
33
#include "hb-ot-layout-gdef-table.hh"
34
#include "hb-aat-map.hh"
35
36
/*
37
 * morx -- Extended Glyph Metamorphosis
38
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
39
 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
40
 */
41
#define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
42
#define HB_AAT_TAG_mort HB_TAG('m','o','r','t')
43
44
45
namespace AAT {
46
47
using namespace OT;
48
49
template <typename Types>
50
struct RearrangementSubtable
51
{
52
  typedef typename Types::HBUINT HBUINT;
53
54
  typedef void EntryData;
55
56
  struct driver_context_t
57
  {
58
    static constexpr bool in_place = true;
59
    enum Flags
60
    {
61
      MarkFirst   = 0x8000, /* If set, make the current glyph the first
62
           * glyph to be rearranged. */
63
      DontAdvance = 0x4000, /* If set, don't advance to the next glyph
64
           * before going to the new state. This means
65
           * that the glyph index doesn't change, even
66
           * if the glyph at that index has changed. */
67
      MarkLast    = 0x2000, /* If set, make the current glyph the last
68
           * glyph to be rearranged. */
69
      Reserved    = 0x1FF0, /* These bits are reserved and should be set to 0. */
70
      Verb    = 0x000F, /* The type of rearrangement specified. */
71
    };
72
73
    driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
74
  ret (false),
75
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*)
76
77
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
78
      const Entry<EntryData> &entry)
79
0
    {
80
0
      return (entry.flags & Verb) && start < end;
81
0
    }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, void>*, AAT::Entry<void> const&)
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
82
    void transition (StateTableDriver<Types, EntryData> *driver,
83
         const Entry<EntryData> &entry)
84
0
    {
85
0
      hb_buffer_t *buffer = driver->buffer;
86
0
      unsigned int flags = entry.flags;
87
88
0
      if (flags & MarkFirst)
89
0
  start = buffer->idx;
90
91
0
      if (flags & MarkLast)
92
0
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
0
      if ((flags & Verb) && start < end)
95
0
      {
96
  /* The following map has two nibbles, for start-side
97
   * and end-side. Values of 0,1,2 mean move that many
98
   * to the other side. Value of 3 means move 2 and
99
   * flip them. */
100
0
  const unsigned char map[16] =
101
0
  {
102
0
    0x00, /* 0  no change */
103
0
    0x10, /* 1  Ax => xA */
104
0
    0x01, /* 2  xD => Dx */
105
0
    0x11, /* 3  AxD => DxA */
106
0
    0x20, /* 4  ABx => xAB */
107
0
    0x30, /* 5  ABx => xBA */
108
0
    0x02, /* 6  xCD => CDx */
109
0
    0x03, /* 7  xCD => DCx */
110
0
    0x12, /* 8  AxCD => CDxA */
111
0
    0x13, /* 9  AxCD => DCxA */
112
0
    0x21, /* 10 ABxD => DxAB */
113
0
    0x31, /* 11 ABxD => DxBA */
114
0
    0x22, /* 12 ABxCD => CDxAB */
115
0
    0x32, /* 13 ABxCD => CDxBA */
116
0
    0x23, /* 14 ABxCD => DCxAB */
117
0
    0x33, /* 15 ABxCD => DCxBA */
118
0
  };
119
120
0
  unsigned int m = map[flags & Verb];
121
0
  unsigned int l = hb_min (2u, m >> 4);
122
0
  unsigned int r = hb_min (2u, m & 0x0F);
123
0
  bool reverse_l = 3 == (m >> 4);
124
0
  bool reverse_r = 3 == (m & 0x0F);
125
126
0
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
0
  {
128
0
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
0
    buffer->merge_clusters (start, end);
130
131
0
    hb_glyph_info_t *info = buffer->info;
132
0
    hb_glyph_info_t buf[4];
133
134
0
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
0
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
0
    if (l != r)
138
0
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
0
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
0
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
0
    if (reverse_l)
143
0
    {
144
0
      buf[0] = info[end - 1];
145
0
      info[end - 1] = info[end - 2];
146
0
      info[end - 2] = buf[0];
147
0
    }
148
0
    if (reverse_r)
149
0
    {
150
0
      buf[0] = info[start];
151
0
      info[start] = info[start + 1];
152
0
      info[start + 1] = buf[0];
153
0
    }
154
0
  }
155
0
      }
156
0
    }
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, void>*, AAT::Entry<void> const&)
Unexecuted instantiation: AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
157
158
    public:
159
    bool ret;
160
    private:
161
    unsigned int start;
162
    unsigned int end;
163
  };
164
165
  bool apply (hb_aat_apply_context_t *c) const
166
0
  {
167
0
    TRACE_APPLY (this);
168
169
0
    driver_context_t dc (this);
170
171
0
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
0
    driver.drive (&dc, c);
173
174
0
    return_trace (dc.ret);
175
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
176
177
  bool sanitize (hb_sanitize_context_t *c) const
178
0
  {
179
0
    TRACE_SANITIZE (this);
180
0
    return_trace (machine.sanitize (c));
181
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
182
183
  protected:
184
  StateTable<Types, EntryData>  machine;
185
  public:
186
  DEFINE_SIZE_STATIC (16);
187
};
188
189
template <typename Types>
190
struct ContextualSubtable
191
{
192
  typedef typename Types::HBUINT HBUINT;
193
194
  struct EntryData
195
  {
196
    HBUINT16  markIndex;  /* Index of the substitution table for the
197
         * marked glyph (use 0xFFFF for none). */
198
    HBUINT16  currentIndex; /* Index of the substitution table for the
199
         * current glyph (use 0xFFFF for none). */
200
    public:
201
    DEFINE_SIZE_STATIC (4);
202
  };
203
204
  struct driver_context_t
205
  {
206
    static constexpr bool in_place = true;
207
    enum Flags
208
    {
209
      SetMark   = 0x8000, /* If set, make the current glyph the marked glyph. */
210
      DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
211
           * going to the new state. */
212
      Reserved    = 0x3FFF, /* These bits are reserved and should be set to 0. */
213
    };
214
215
    driver_context_t (const ContextualSubtable *table_,
216
           hb_aat_apply_context_t *c_) :
217
  ret (false),
218
  c (c_),
219
  gdef (*c->gdef_table),
220
  mark_set (false),
221
  has_glyph_classes (gdef.has_glyph_classes ()),
222
  mark (0),
223
  table (table_),
224
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*)
225
226
    bool is_actionable (StateTableDriver<Types, EntryData> *driver,
227
      const Entry<EntryData> &entry)
228
0
    {
229
0
      hb_buffer_t *buffer = driver->buffer;
230
231
0
      if (buffer->idx == buffer->len && !mark_set)
232
0
  return false;
233
234
0
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
0
    }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData>*, AAT::Entry<AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData> const&)
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData>*, AAT::Entry<AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData> const&)
236
    void transition (StateTableDriver<Types, EntryData> *driver,
237
         const Entry<EntryData> &entry)
238
0
    {
239
0
      hb_buffer_t *buffer = driver->buffer;
240
241
      /* Looks like CoreText applies neither mark nor current substitution for
242
       * end-of-text if mark was not explicitly set. */
243
0
      if (buffer->idx == buffer->len && !mark_set)
244
0
  return;
245
246
0
      const HBGlyphID16 *replacement;
247
248
0
      replacement = nullptr;
249
0
      if (Types::extended)
250
0
      {
251
0
  if (entry.data.markIndex != 0xFFFF)
252
0
  {
253
0
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
254
0
    replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
255
0
  }
256
0
      }
257
0
      else
258
0
      {
259
0
  unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
260
0
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
261
0
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
262
0
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
263
0
    replacement = nullptr;
264
0
      }
265
0
      if (replacement)
266
0
      {
267
0
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
0
  buffer->info[mark].codepoint = *replacement;
269
0
  if (has_glyph_classes)
270
0
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
0
            gdef.get_glyph_props (*replacement));
272
0
  ret = true;
273
0
      }
274
275
0
      replacement = nullptr;
276
0
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
0
      if (Types::extended)
278
0
      {
279
0
  if (entry.data.currentIndex != 0xFFFF)
280
0
  {
281
0
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
282
0
    replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
283
0
  }
284
0
      }
285
0
      else
286
0
      {
287
0
  unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
288
0
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
289
0
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
290
0
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
291
0
    replacement = nullptr;
292
0
      }
293
0
      if (replacement)
294
0
      {
295
0
  buffer->info[idx].codepoint = *replacement;
296
0
  if (has_glyph_classes)
297
0
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
0
            gdef.get_glyph_props (*replacement));
299
0
  ret = true;
300
0
      }
301
302
0
      if (entry.flags & SetMark)
303
0
      {
304
0
  mark_set = true;
305
0
  mark = buffer->idx;
306
0
      }
307
0
    }
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData>*, AAT::Entry<AAT::ContextualSubtable<AAT::ExtendedTypes>::EntryData> const&)
Unexecuted instantiation: AAT::ContextualSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData>*, AAT::Entry<AAT::ContextualSubtable<AAT::ObsoleteTypes>::EntryData> const&)
308
309
    public:
310
    bool ret;
311
    private:
312
    hb_aat_apply_context_t *c;
313
    const OT::GDEF &gdef;
314
    bool mark_set;
315
    bool has_glyph_classes;
316
    unsigned int mark;
317
    const ContextualSubtable *table;
318
    const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, 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> driver (machine, c->buffer, c->face);
328
0
    driver.drive (&dc, c);
329
330
0
    return_trace (dc.ret);
331
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
332
333
  bool sanitize (hb_sanitize_context_t *c) const
334
0
  {
335
0
    TRACE_SANITIZE (this);
336
337
0
    unsigned int num_entries = 0;
338
0
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
0
    if (!Types::extended)
341
0
      return_trace (substitutionTables.sanitize (c, this, 0));
342
343
0
    unsigned int num_lookups = 0;
344
345
0
    const Entry<EntryData> *entries = machine.get_entries ();
346
0
    for (unsigned int i = 0; i < num_entries; i++)
347
0
    {
348
0
      const EntryData &data = entries[i].data;
349
350
0
      if (data.markIndex != 0xFFFF)
351
0
  num_lookups = hb_max (num_lookups, 1u + data.markIndex);
352
0
      if (data.currentIndex != 0xFFFF)
353
0
  num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
354
0
    }
355
356
0
    return_trace (substitutionTables.sanitize (c, this, num_lookups));
357
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
358
359
  protected:
360
  StateTable<Types, EntryData>
361
    machine;
362
  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false>, HBUINT>
363
    substitutionTables;
364
  public:
365
  DEFINE_SIZE_STATIC (20);
366
};
367
368
369
template <bool extended>
370
struct LigatureEntry;
371
372
template <>
373
struct LigatureEntry<true>
374
{
375
  enum Flags
376
  {
377
    SetComponent  = 0x8000, /* Push this glyph onto the component stack for
378
           * eventual processing. */
379
    DontAdvance   = 0x4000, /* Leave the glyph pointer at this glyph for the
380
             next iteration. */
381
    PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature
382
           * group. */
383
    Reserved    = 0x1FFF, /* These bits are reserved and should be set to 0. */
384
  };
385
386
  struct EntryData
387
  {
388
    HBUINT16  ligActionIndex; /* Index to the first ligActionTable entry
389
         * for processing this group, if indicated
390
         * by the flags. */
391
    public:
392
    DEFINE_SIZE_STATIC (2);
393
  };
394
395
  static bool performAction (const Entry<EntryData> &entry)
396
0
  { return entry.flags & PerformAction; }
397
398
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
399
0
  { return entry.data.ligActionIndex; }
400
};
401
template <>
402
struct LigatureEntry<false>
403
{
404
  enum Flags
405
  {
406
    SetComponent  = 0x8000, /* Push this glyph onto the component stack for
407
           * eventual processing. */
408
    DontAdvance   = 0x4000, /* Leave the glyph pointer at this glyph for the
409
             next iteration. */
410
    Offset    = 0x3FFF, /* Byte offset from beginning of subtable to the
411
           * ligature action list. This value must be a
412
           * multiple of 4. */
413
  };
414
415
  typedef void EntryData;
416
417
  static bool performAction (const Entry<EntryData> &entry)
418
0
  { return entry.flags & Offset; }
419
420
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
421
0
  { return entry.flags & Offset; }
422
};
423
424
425
template <typename Types>
426
struct LigatureSubtable
427
{
428
  typedef typename Types::HBUINT HBUINT;
429
430
  typedef LigatureEntry<Types::extended> LigatureEntryT;
431
  typedef typename LigatureEntryT::EntryData EntryData;
432
433
  struct driver_context_t
434
  {
435
    static constexpr bool in_place = false;
436
    enum
437
    {
438
      DontAdvance = LigatureEntryT::DontAdvance,
439
    };
440
    enum LigActionFlags
441
    {
442
      LigActionLast = 0x80000000, /* This is the last action in the list. This also
443
           * implies storage. */
444
      LigActionStore  = 0x40000000, /* Store the ligature at the current cumulated index
445
           * in the ligature table in place of the marked
446
           * (i.e. currently-popped) glyph. */
447
      LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits
448
           * and added to the glyph ID, resulting in an index
449
           * into the component table. */
450
    };
451
452
    driver_context_t (const LigatureSubtable *table_,
453
          hb_aat_apply_context_t *c_) :
454
  ret (false),
455
  c (c_),
456
  table (table_),
457
  ligAction (table+table->ligAction),
458
  component (table+table->component),
459
  ligature (table+table->ligature),
460
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*)
461
462
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
463
      const Entry<EntryData> &entry)
464
0
    {
465
0
      return LigatureEntryT::performAction (entry);
466
0
    }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::LigatureEntry<true>::EntryData>*, AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&)
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
467
    void transition (StateTableDriver<Types, EntryData> *driver,
468
         const Entry<EntryData> &entry)
469
0
    {
470
0
      hb_buffer_t *buffer = driver->buffer;
471
472
0
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
0
      if (entry.flags & LigatureEntryT::SetComponent)
474
0
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
0
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
0
    match_length--;
478
479
0
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
0
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
0
      }
482
483
0
      if (LigatureEntryT::performAction (entry))
484
0
      {
485
0
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
0
  unsigned int end = buffer->out_len;
487
488
0
  if (unlikely (!match_length))
489
0
    return;
490
491
0
  if (buffer->idx >= buffer->len)
492
0
    return; /* TODO Work on previous instead? */
493
494
0
  unsigned int cursor = match_length;
495
496
0
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
0
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
0
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
0
  unsigned int ligature_idx = 0;
501
0
  unsigned int action;
502
0
  do
503
0
  {
504
0
    if (unlikely (!cursor))
505
0
    {
506
      /* Stack underflow.  Clear the stack. */
507
0
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
0
      match_length = 0;
509
0
      break;
510
0
    }
511
512
0
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
0
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
0
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
0
    action = *actionData;
517
518
0
    uint32_t uoffset = action & LigActionOffset;
519
0
    if (uoffset & 0x20000000)
520
0
      uoffset |= 0xC0000000; /* Sign-extend. */
521
0
    int32_t offset = (int32_t) uoffset;
522
0
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
0
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
0
    const HBUINT16 &componentData = component[component_idx];
525
0
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
0
    ligature_idx += componentData;
527
528
0
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
0
         bool (action & LigActionStore),
530
0
         bool (action & LigActionLast));
531
0
    if (action & (LigActionStore | LigActionLast))
532
0
    {
533
0
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
0
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
0
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
0
      hb_codepoint_t lig = ligatureData;
537
538
0
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
0
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
0
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
0
      while (match_length - 1u > cursor)
544
0
      {
545
0
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546
0
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547
0
        if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548
0
      }
549
550
0
      if (unlikely (!buffer->move_to (lig_end))) return;
551
0
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
0
    }
553
554
0
    actionData++;
555
0
  }
556
0
  while (!(action & LigActionLast));
557
0
  if (unlikely (!buffer->move_to (end))) return;
558
0
      }
559
0
    }
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::LigatureEntry<true>::EntryData>*, AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&)
Unexecuted instantiation: AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
560
561
    public:
562
    bool ret;
563
    private:
564
    hb_aat_apply_context_t *c;
565
    const LigatureSubtable *table;
566
    const UnsizedArrayOf<HBUINT32> &ligAction;
567
    const UnsizedArrayOf<HBUINT16> &component;
568
    const UnsizedArrayOf<HBGlyphID16> &ligature;
569
    unsigned int match_length;
570
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
571
  };
572
573
  bool apply (hb_aat_apply_context_t *c) const
574
0
  {
575
0
    TRACE_APPLY (this);
576
577
0
    driver_context_t dc (this, c);
578
579
0
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
0
    driver.drive (&dc, c);
581
582
0
    return_trace (dc.ret);
583
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
584
585
  bool sanitize (hb_sanitize_context_t *c) const
586
0
  {
587
0
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
0
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
0
      ligAction && component && ligature);
591
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
592
593
  protected:
594
  StateTable<Types, EntryData>
595
    machine;
596
  NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
597
    ligAction;  /* Offset to the ligature action table. */
598
  NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
599
    component;  /* Offset to the component table. */
600
  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
601
    ligature; /* Offset to the actual ligature lists. */
602
  public:
603
  DEFINE_SIZE_STATIC (28);
604
};
605
606
template <typename Types>
607
struct NoncontextualSubtable
608
{
609
  bool apply (hb_aat_apply_context_t *c) const
610
0
  {
611
0
    TRACE_APPLY (this);
612
613
0
    const OT::GDEF &gdef (*c->gdef_table);
614
0
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
0
    bool ret = false;
617
0
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
0
    hb_glyph_info_t *info = c->buffer->info;
620
0
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
0
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
0
    for (unsigned int i = 0; i < count; i++)
624
0
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
0
      if (last_range)
627
0
      {
628
0
  auto *range = last_range;
629
0
  {
630
0
    unsigned cluster = info[i].cluster;
631
0
    while (cluster < range->cluster_first)
632
0
      range--;
633
0
    while (cluster > range->cluster_last)
634
0
      range++;
635
636
0
    last_range = range;
637
0
  }
638
0
  if (!(range->flags & c->subtable_flags))
639
0
    continue;
640
0
      }
641
642
0
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
0
      if (replacement)
644
0
      {
645
0
  info[i].codepoint = *replacement;
646
0
  if (has_glyph_classes)
647
0
    _hb_glyph_info_set_glyph_props (&info[i],
648
0
            gdef.get_glyph_props (*replacement));
649
0
  ret = true;
650
0
      }
651
0
    }
652
653
0
    return_trace (ret);
654
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
655
656
  bool sanitize (hb_sanitize_context_t *c) const
657
0
  {
658
0
    TRACE_SANITIZE (this);
659
0
    return_trace (substitute.sanitize (c));
660
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
661
662
  protected:
663
  Lookup<HBGlyphID16> substitute;
664
  public:
665
  DEFINE_SIZE_MIN (2);
666
};
667
668
template <typename Types>
669
struct InsertionSubtable
670
{
671
  typedef typename Types::HBUINT HBUINT;
672
673
  struct EntryData
674
  {
675
    HBUINT16  currentInsertIndex; /* Zero-based index into the insertion glyph table.
676
           * The number of glyphs to be inserted is contained
677
           * in the currentInsertCount field in the flags.
678
           * A value of 0xFFFF indicates no insertion is to
679
           * be done. */
680
    HBUINT16  markedInsertIndex;  /* Zero-based index into the insertion glyph table.
681
           * The number of glyphs to be inserted is contained
682
           * in the markedInsertCount field in the flags.
683
           * A value of 0xFFFF indicates no insertion is to
684
           * be done. */
685
    public:
686
    DEFINE_SIZE_STATIC (4);
687
  };
688
689
  struct driver_context_t
690
  {
691
    static constexpr bool in_place = false;
692
    enum Flags
693
    {
694
      SetMark   = 0x8000, /* If set, mark the current glyph. */
695
      DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
696
           * going to the new state.  This does not mean
697
           * that the glyph pointed to is the same one as
698
           * before. If you've made insertions immediately
699
           * downstream of the current glyph, the next glyph
700
           * processed would in fact be the first one
701
           * inserted. */
702
      CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
703
           * then the specified glyph list will be inserted
704
           * as a kashida-like insertion, either before or
705
           * after the current glyph (depending on the state
706
           * of the currentInsertBefore flag). If clear, and
707
           * the currentInsertList is nonzero, then the
708
           * specified glyph list will be inserted as a
709
           * split-vowel-like insertion, either before or
710
           * after the current glyph (depending on the state
711
           * of the currentInsertBefore flag). */
712
      MarkedIsKashidaLike= 0x1000,  /* If set, and the markedInsertList is nonzero,
713
           * then the specified glyph list will be inserted
714
           * as a kashida-like insertion, either before or
715
           * after the marked glyph (depending on the state
716
           * of the markedInsertBefore flag). If clear, and
717
           * the markedInsertList is nonzero, then the
718
           * specified glyph list will be inserted as a
719
           * split-vowel-like insertion, either before or
720
           * after the marked glyph (depending on the state
721
           * of the markedInsertBefore flag). */
722
      CurrentInsertBefore= 0x0800,  /* If set, specifies that insertions are to be made
723
           * to the left of the current glyph. If clear,
724
           * they're made to the right of the current glyph. */
725
      MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
726
           * made to the left of the marked glyph. If clear,
727
           * they're made to the right of the marked glyph. */
728
      CurrentInsertCount= 0x3E0,  /* This 5-bit field is treated as a count of the
729
           * number of glyphs to insert at the current
730
           * position. Since zero means no insertions, the
731
           * largest number of insertions at any given
732
           * current location is 31 glyphs. */
733
      MarkedInsertCount= 0x001F,  /* This 5-bit field is treated as a count of the
734
           * number of glyphs to insert at the marked
735
           * position. Since zero means no insertions, the
736
           * largest number of insertions at any given
737
           * marked location is 31 glyphs. */
738
    };
739
740
    driver_context_t (const InsertionSubtable *table,
741
          hb_aat_apply_context_t *c_) :
742
  ret (false),
743
  c (c_),
744
  mark (0),
745
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*)
746
747
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
748
      const Entry<EntryData> &entry)
749
0
    {
750
0
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
0
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
0
    }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData>*, AAT::Entry<AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData> const&)
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData>*, AAT::Entry<AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData> const&)
753
    void transition (StateTableDriver<Types, EntryData> *driver,
754
         const Entry<EntryData> &entry)
755
0
    {
756
0
      hb_buffer_t *buffer = driver->buffer;
757
0
      unsigned int flags = entry.flags;
758
759
0
      unsigned mark_loc = buffer->out_len;
760
761
0
      if (entry.data.markedInsertIndex != 0xFFFF)
762
0
      {
763
0
  unsigned int count = (flags & MarkedInsertCount);
764
0
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
0
  unsigned int start = entry.data.markedInsertIndex;
766
0
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
0
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
0
  bool before = flags & MarkedInsertBefore;
770
771
0
  unsigned int end = buffer->out_len;
772
0
  if (unlikely (!buffer->move_to (mark))) return;
773
774
0
  if (buffer->idx < buffer->len && !before)
775
0
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
0
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
0
  if (buffer->idx < buffer->len && !before)
779
0
    buffer->skip_glyph ();
780
781
0
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
0
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
0
      }
785
786
0
      if (flags & SetMark)
787
0
  mark = mark_loc;
788
789
0
      if (entry.data.currentInsertIndex != 0xFFFF)
790
0
      {
791
0
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
0
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
0
  unsigned int start = entry.data.currentInsertIndex;
794
0
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
0
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
0
  bool before = flags & CurrentInsertBefore;
798
799
0
  unsigned int end = buffer->out_len;
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 (!buffer->replace_glyphs (0, count, glyphs))) return;
805
0
  if (buffer->idx < buffer->len && !before)
806
0
    buffer->skip_glyph ();
807
808
  /* Humm. Not sure where to move to.  There's this wording under
809
   * DontAdvance flag:
810
   *
811
   * "If set, don't update the glyph index before going to the new state.
812
   * This does not mean that the glyph pointed to is the same one as
813
   * before. If you've made insertions immediately downstream of the
814
   * current glyph, the next glyph processed would in fact be the first
815
   * one inserted."
816
   *
817
   * This suggests that if DontAdvance is NOT set, we should move to
818
   * end+count.  If it *was*, then move to end, such that newly inserted
819
   * glyphs are now visible.
820
   *
821
   * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
822
   */
823
0
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
0
      }
825
0
    }
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData>*, AAT::Entry<AAT::InsertionSubtable<AAT::ExtendedTypes>::EntryData> const&)
Unexecuted instantiation: AAT::InsertionSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData>*, AAT::Entry<AAT::InsertionSubtable<AAT::ObsoleteTypes>::EntryData> const&)
826
827
    public:
828
    bool ret;
829
    private:
830
    hb_aat_apply_context_t *c;
831
    unsigned int mark;
832
    const UnsizedArrayOf<HBGlyphID16> &insertionAction;
833
  };
834
835
  bool apply (hb_aat_apply_context_t *c) const
836
0
  {
837
0
    TRACE_APPLY (this);
838
839
0
    driver_context_t dc (this, c);
840
841
0
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
0
    driver.drive (&dc, c);
843
844
0
    return_trace (dc.ret);
845
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
846
847
  bool sanitize (hb_sanitize_context_t *c) const
848
0
  {
849
0
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
0
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
0
      insertionAction);
853
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
854
855
  protected:
856
  StateTable<Types, EntryData>
857
    machine;
858
  NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT>
859
    insertionAction;  /* Byte offset from stateHeader to the start of
860
           * the insertion glyph table. */
861
  public:
862
  DEFINE_SIZE_STATIC (20);
863
};
864
865
866
struct Feature
867
{
868
  bool sanitize (hb_sanitize_context_t *c) const
869
0
  {
870
0
    TRACE_SANITIZE (this);
871
0
    return_trace (c->check_struct (this));
872
0
  }
873
874
  public:
875
  HBUINT16  featureType;  /* The type of feature. */
876
  HBUINT16  featureSetting; /* The feature's setting (aka selector). */
877
  HBUINT32  enableFlags;  /* Flags for the settings that this feature
878
         * and setting enables. */
879
  HBUINT32  disableFlags; /* Complement of flags for the settings that this
880
         * feature and setting disable. */
881
882
  public:
883
  DEFINE_SIZE_STATIC (12);
884
};
885
886
template <typename Types>
887
struct ChainSubtable
888
{
889
  typedef typename Types::HBUINT HBUINT;
890
891
  template <typename T>
892
  friend struct Chain;
893
894
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
895
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
896
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
897
898
  enum Coverage
899
  {
900
    Vertical    = 0x80, /* If set, this subtable will only be applied
901
         * to vertical text. If clear, this subtable
902
         * will only be applied to horizontal text. */
903
    Backwards   = 0x40, /* If set, this subtable will process glyphs
904
         * in descending order. If clear, it will
905
         * process the glyphs in ascending order. */
906
    AllDirections = 0x20, /* If set, this subtable will be applied to
907
         * both horizontal and vertical text (i.e.
908
         * the state of bit 0x80000000 is ignored). */
909
    Logical   = 0x10, /* If set, this subtable will process glyphs
910
         * in logical order (or reverse logical order,
911
         * depending on the value of bit 0x80000000). */
912
  };
913
  enum Type
914
  {
915
    Rearrangement = 0,
916
    Contextual    = 1,
917
    Ligature    = 2,
918
    Noncontextual = 4,
919
    Insertion   = 5
920
  };
921
922
  template <typename context_t, typename ...Ts>
923
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
924
0
  {
925
0
    unsigned int subtable_type = get_type ();
926
0
    TRACE_DISPATCH (this, subtable_type);
927
0
    switch (subtable_type) {
928
0
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
0
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
0
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
0
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
0
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
0
    default:      return_trace (c->default_return_value ());
934
0
    }
935
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_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_aat_apply_context_t::return_t AAT::ChainSubtable<AAT::ObsoleteTypes>::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const
936
937
  bool apply (hb_aat_apply_context_t *c) const
938
0
  {
939
0
    TRACE_APPLY (this);
940
0
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
0
    return_trace (dispatch (c));
942
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
943
944
  bool sanitize (hb_sanitize_context_t *c) const
945
0
  {
946
0
    TRACE_SANITIZE (this);
947
0
    if (!length.sanitize (c) ||
948
0
  length <= min_size ||
949
0
  !c->check_range (this, length))
950
0
      return_trace (false);
951
952
0
    hb_sanitize_with_object_t with (c, this);
953
0
    return_trace (dispatch (c));
954
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
955
956
  protected:
957
  HBUINT  length;   /* Total subtable length, including this header. */
958
  HBUINT  coverage; /* Coverage flags and subtable type. */
959
  HBUINT32  subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
960
  union {
961
  RearrangementSubtable<Types>  rearrangement;
962
  ContextualSubtable<Types> contextual;
963
  LigatureSubtable<Types> ligature;
964
  NoncontextualSubtable<Types>  noncontextual;
965
  InsertionSubtable<Types>  insertion;
966
  } u;
967
  public:
968
  DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4);
969
};
970
971
template <typename Types>
972
struct Chain
973
{
974
  typedef typename Types::HBUINT HBUINT;
975
976
  hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const
977
0
  {
978
0
    hb_mask_t flags = defaultFlags;
979
0
    {
980
0
      unsigned int count = featureCount;
981
0
      for (unsigned i = 0; i < count; i++)
982
0
      {
983
0
  const Feature &feature = featureZ[i];
984
0
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
0
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
0
      retry:
987
  // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
988
  // (The search here only looks at the type and setting fields of feature_info_t.)
989
0
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
0
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
0
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
0
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
0
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
0
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
0
    goto retry;
1001
0
  }
1002
0
#ifndef HB_NO_AAT
1003
0
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
0
     hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language))
1006
0
  {
1007
0
    flags &= feature.disableFlags;
1008
0
    flags |= feature.enableFlags;
1009
0
  }
1010
0
#endif
1011
0
      }
1012
0
    }
1013
0
    return flags;
1014
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
1015
1016
  void apply (hb_aat_apply_context_t *c) const
1017
0
  {
1018
0
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
0
    unsigned int count = subtableCount;
1020
0
    for (unsigned int i = 0; i < count; i++)
1021
0
    {
1022
0
      bool reverse;
1023
1024
0
      if (hb_none (hb_iter (c->range_flags) |
1025
0
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) 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*) const::{lambda(hb_aat_map_t::range_flags_t)#1}::operator()(hb_aat_map_t::range_flags_t) const
1026
0
  goto skip;
1027
0
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
0
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
0
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
0
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
0
  goto skip;
1033
1034
      /* Buffer contents is always in logical direction.  Determine if
1035
       * we need to reverse before applying this subtable.  We reverse
1036
       * back after if we did reverse indeed.
1037
       *
1038
       * Quoting the spac:
1039
       * """
1040
       * Bits 28 and 30 of the coverage field control the order in which
1041
       * glyphs are processed when the subtable is run by the layout engine.
1042
       * Bit 28 is used to indicate if the glyph processing direction is
1043
       * the same as logical order or layout order. Bit 30 is used to
1044
       * indicate whether glyphs are processed forwards or backwards within
1045
       * that order.
1046
1047
    Bit 30  Bit 28  Interpretation for Horizontal Text
1048
    0 0 The subtable is processed in layout order
1049
        (the same order as the glyphs, which is
1050
        always left-to-right).
1051
    1 0 The subtable is processed in reverse layout order
1052
        (the order opposite that of the glyphs, which is
1053
        always right-to-left).
1054
    0 1 The subtable is processed in logical order
1055
        (the same order as the characters, which may be
1056
        left-to-right or right-to-left).
1057
    1 1 The subtable is processed in reverse logical order
1058
        (the order opposite that of the characters, which
1059
        may be right-to-left or left-to-right).
1060
       */
1061
0
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
0
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
0
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
0
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
0
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
0
      if (reverse)
1070
0
  c->buffer->reverse ();
1071
1072
0
      subtable->apply (c);
1073
1074
0
      if (reverse)
1075
0
  c->buffer->reverse ();
1076
1077
0
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
0
      if (unlikely (!c->buffer->successful)) return;
1080
1081
0
    skip:
1082
0
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
0
      c->set_lookup_index (c->lookup_index + 1);
1084
0
    }
1085
0
  }
Unexecuted instantiation: AAT::Chain<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Unexecuted instantiation: AAT::Chain<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
1086
1087
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
1088
1089
  bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
1090
0
  {
1091
0
    TRACE_SANITIZE (this);
1092
0
    if (!length.sanitize (c) ||
1093
0
  length < min_size ||
1094
0
  !c->check_range (this, length))
1095
0
      return_trace (false);
1096
1097
0
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
0
      return_trace (false);
1099
1100
0
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
0
    unsigned int count = subtableCount;
1102
0
    for (unsigned int i = 0; i < count; i++)
1103
0
    {
1104
0
      if (!subtable->sanitize (c))
1105
0
  return_trace (false);
1106
0
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
0
    }
1108
1109
0
    return_trace (true);
1110
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
1111
1112
  protected:
1113
  HBUINT32  defaultFlags; /* The default specification for subtables. */
1114
  HBUINT32  length;   /* Total byte count, including this header. */
1115
  HBUINT  featureCount; /* Number of feature subtable entries. */
1116
  HBUINT  subtableCount;  /* The number of subtables in the chain. */
1117
1118
  UnsizedArrayOf<Feature> featureZ; /* Features. */
1119
/*ChainSubtable firstSubtable;*//* Subtables. */
1120
/*subtableGlyphCoverageArray*/  /* Only if version >= 3. We don't use. */
1121
1122
  public:
1123
  DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT));
1124
};
1125
1126
1127
/*
1128
 * The 'mort'/'morx' Table
1129
 */
1130
1131
template <typename Types, hb_tag_t TAG>
1132
struct mortmorx
1133
{
1134
  static constexpr hb_tag_t tableTag = TAG;
1135
1136
26
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::has_data() const
Line
Count
Source
1136
13
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::has_data() const
Line
Count
Source
1136
13
  bool has_data () const { return version != 0; }
1137
1138
  void compile_flags (const hb_aat_map_builder_t *mapper,
1139
          hb_aat_map_t *map) const
1140
0
  {
1141
0
    const Chain<Types> *chain = &firstChain;
1142
0
    unsigned int count = chainCount;
1143
0
    if (unlikely (!map->chain_flags.resize (count)))
1144
0
      return;
1145
0
    for (unsigned int i = 0; i < count; i++)
1146
0
    {
1147
0
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
0
                   mapper->range_first,
1149
0
                   mapper->range_last});
1150
0
      chain = &StructAfter<Chain<Types>> (*chain);
1151
0
    }
1152
0
  }
Unexecuted instantiation: AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
Unexecuted instantiation: AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
1153
1154
  void apply (hb_aat_apply_context_t *c,
1155
        const hb_aat_map_t &map) const
1156
0
  {
1157
0
    if (unlikely (!c->buffer->successful)) return;
1158
1159
0
    c->buffer->unsafe_to_concat ();
1160
1161
0
    c->set_lookup_index (0);
1162
0
    const Chain<Types> *chain = &firstChain;
1163
0
    unsigned int count = chainCount;
1164
0
    for (unsigned int i = 0; i < count; i++)
1165
0
    {
1166
0
      c->range_flags = &map.chain_flags[i];
1167
0
      chain->apply (c);
1168
0
      if (unlikely (!c->buffer->successful)) return;
1169
0
      chain = &StructAfter<Chain<Types>> (*chain);
1170
0
    }
1171
0
  }
Unexecuted instantiation: AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&) const
Unexecuted instantiation: AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&) const
1172
1173
  bool sanitize (hb_sanitize_context_t *c) const
1174
0
  {
1175
0
    TRACE_SANITIZE (this);
1176
0
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
0
      return_trace (false);
1178
1179
0
    const Chain<Types> *chain = &firstChain;
1180
0
    unsigned int count = chainCount;
1181
0
    for (unsigned int i = 0; i < count; i++)
1182
0
    {
1183
0
      if (!chain->sanitize (c, version))
1184
0
  return_trace (false);
1185
0
      chain = &StructAfter<Chain<Types>> (*chain);
1186
0
    }
1187
1188
0
    return_trace (true);
1189
0
  }
Unexecuted instantiation: AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::sanitize(hb_sanitize_context_t*) const
1190
1191
  protected:
1192
  HBUINT16  version;  /* Version number of the glyph metamorphosis table.
1193
         * 1, 2, or 3. */
1194
  HBUINT16  unused;   /* Set to 0. */
1195
  HBUINT32  chainCount; /* Number of metamorphosis chains contained in this
1196
         * table. */
1197
  Chain<Types>  firstChain; /* Chains. */
1198
1199
  public:
1200
  DEFINE_SIZE_MIN (8);
1201
};
1202
1203
struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
1204
struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
1205
1206
1207
} /* namespace AAT */
1208
1209
1210
#endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */