Coverage Report

Created: 2024-06-09 08:56

/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
95.5k
  start (0), end (0) {}
AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::RearrangementSubtable<AAT::ExtendedTypes> const*)
Line
Count
Source
75
40.4k
  start (0), end (0) {}
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::RearrangementSubtable<AAT::ObsoleteTypes> const*)
Line
Count
Source
75
55.1k
  start (0), end (0) {}
76
77
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
78
      const Entry<EntryData> &entry)
79
293M
    {
80
293M
      return (entry.flags & Verb) && start < end;
81
293M
    }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
79
76.7M
    {
80
76.7M
      return (entry.flags & Verb) && start < end;
81
76.7M
    }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
79
216M
    {
80
216M
      return (entry.flags & Verb) && start < end;
81
216M
    }
82
    void transition (StateTableDriver<Types, EntryData> *driver,
83
         const Entry<EntryData> &entry)
84
215M
    {
85
215M
      hb_buffer_t *buffer = driver->buffer;
86
215M
      unsigned int flags = entry.flags;
87
88
215M
      if (flags & MarkFirst)
89
89.5M
  start = buffer->idx;
90
91
215M
      if (flags & MarkLast)
92
128M
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
215M
      if ((flags & Verb) && start < end)
95
142M
      {
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
142M
  const unsigned char map[16] =
101
142M
  {
102
142M
    0x00, /* 0  no change */
103
142M
    0x10, /* 1  Ax => xA */
104
142M
    0x01, /* 2  xD => Dx */
105
142M
    0x11, /* 3  AxD => DxA */
106
142M
    0x20, /* 4  ABx => xAB */
107
142M
    0x30, /* 5  ABx => xBA */
108
142M
    0x02, /* 6  xCD => CDx */
109
142M
    0x03, /* 7  xCD => DCx */
110
142M
    0x12, /* 8  AxCD => CDxA */
111
142M
    0x13, /* 9  AxCD => DCxA */
112
142M
    0x21, /* 10 ABxD => DxAB */
113
142M
    0x31, /* 11 ABxD => DxBA */
114
142M
    0x22, /* 12 ABxCD => CDxAB */
115
142M
    0x32, /* 13 ABxCD => CDxBA */
116
142M
    0x23, /* 14 ABxCD => DCxAB */
117
142M
    0x33, /* 15 ABxCD => DCxBA */
118
142M
  };
119
120
142M
  unsigned int m = map[flags & Verb];
121
142M
  unsigned int l = hb_min (2u, m >> 4);
122
142M
  unsigned int r = hb_min (2u, m & 0x0F);
123
142M
  bool reverse_l = 3 == (m >> 4);
124
142M
  bool reverse_r = 3 == (m & 0x0F);
125
126
142M
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
46.1M
  {
128
46.1M
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
46.1M
    buffer->merge_clusters (start, end);
130
131
46.1M
    hb_glyph_info_t *info = buffer->info;
132
46.1M
    hb_glyph_info_t buf[4];
133
134
46.1M
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
46.1M
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
46.1M
    if (l != r)
138
37.5M
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
46.1M
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
46.1M
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
46.1M
    if (reverse_l)
143
8.63M
    {
144
8.63M
      buf[0] = info[end - 1];
145
8.63M
      info[end - 1] = info[end - 2];
146
8.63M
      info[end - 2] = buf[0];
147
8.63M
    }
148
46.1M
    if (reverse_r)
149
925k
    {
150
925k
      buf[0] = info[start];
151
925k
      info[start] = info[start + 1];
152
925k
      info[start + 1] = buf[0];
153
925k
    }
154
46.1M
  }
155
142M
      }
156
215M
    }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
84
45.8M
    {
85
45.8M
      hb_buffer_t *buffer = driver->buffer;
86
45.8M
      unsigned int flags = entry.flags;
87
88
45.8M
      if (flags & MarkFirst)
89
27.6M
  start = buffer->idx;
90
91
45.8M
      if (flags & MarkLast)
92
28.0M
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
45.8M
      if ((flags & Verb) && start < end)
95
17.0M
      {
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
17.0M
  const unsigned char map[16] =
101
17.0M
  {
102
17.0M
    0x00, /* 0  no change */
103
17.0M
    0x10, /* 1  Ax => xA */
104
17.0M
    0x01, /* 2  xD => Dx */
105
17.0M
    0x11, /* 3  AxD => DxA */
106
17.0M
    0x20, /* 4  ABx => xAB */
107
17.0M
    0x30, /* 5  ABx => xBA */
108
17.0M
    0x02, /* 6  xCD => CDx */
109
17.0M
    0x03, /* 7  xCD => DCx */
110
17.0M
    0x12, /* 8  AxCD => CDxA */
111
17.0M
    0x13, /* 9  AxCD => DCxA */
112
17.0M
    0x21, /* 10 ABxD => DxAB */
113
17.0M
    0x31, /* 11 ABxD => DxBA */
114
17.0M
    0x22, /* 12 ABxCD => CDxAB */
115
17.0M
    0x32, /* 13 ABxCD => CDxBA */
116
17.0M
    0x23, /* 14 ABxCD => DCxAB */
117
17.0M
    0x33, /* 15 ABxCD => DCxBA */
118
17.0M
  };
119
120
17.0M
  unsigned int m = map[flags & Verb];
121
17.0M
  unsigned int l = hb_min (2u, m >> 4);
122
17.0M
  unsigned int r = hb_min (2u, m & 0x0F);
123
17.0M
  bool reverse_l = 3 == (m >> 4);
124
17.0M
  bool reverse_r = 3 == (m & 0x0F);
125
126
17.0M
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
6.43M
  {
128
6.43M
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
6.43M
    buffer->merge_clusters (start, end);
130
131
6.43M
    hb_glyph_info_t *info = buffer->info;
132
6.43M
    hb_glyph_info_t buf[4];
133
134
6.43M
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
6.43M
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
6.43M
    if (l != r)
138
6.33M
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
6.43M
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
6.43M
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
6.43M
    if (reverse_l)
143
120k
    {
144
120k
      buf[0] = info[end - 1];
145
120k
      info[end - 1] = info[end - 2];
146
120k
      info[end - 2] = buf[0];
147
120k
    }
148
6.43M
    if (reverse_r)
149
99.7k
    {
150
99.7k
      buf[0] = info[start];
151
99.7k
      info[start] = info[start + 1];
152
99.7k
      info[start + 1] = buf[0];
153
99.7k
    }
154
6.43M
  }
155
17.0M
      }
156
45.8M
    }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
84
170M
    {
85
170M
      hb_buffer_t *buffer = driver->buffer;
86
170M
      unsigned int flags = entry.flags;
87
88
170M
      if (flags & MarkFirst)
89
61.9M
  start = buffer->idx;
90
91
170M
      if (flags & MarkLast)
92
100M
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
170M
      if ((flags & Verb) && start < end)
95
125M
      {
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
125M
  const unsigned char map[16] =
101
125M
  {
102
125M
    0x00, /* 0  no change */
103
125M
    0x10, /* 1  Ax => xA */
104
125M
    0x01, /* 2  xD => Dx */
105
125M
    0x11, /* 3  AxD => DxA */
106
125M
    0x20, /* 4  ABx => xAB */
107
125M
    0x30, /* 5  ABx => xBA */
108
125M
    0x02, /* 6  xCD => CDx */
109
125M
    0x03, /* 7  xCD => DCx */
110
125M
    0x12, /* 8  AxCD => CDxA */
111
125M
    0x13, /* 9  AxCD => DCxA */
112
125M
    0x21, /* 10 ABxD => DxAB */
113
125M
    0x31, /* 11 ABxD => DxBA */
114
125M
    0x22, /* 12 ABxCD => CDxAB */
115
125M
    0x32, /* 13 ABxCD => CDxBA */
116
125M
    0x23, /* 14 ABxCD => DCxAB */
117
125M
    0x33, /* 15 ABxCD => DCxBA */
118
125M
  };
119
120
125M
  unsigned int m = map[flags & Verb];
121
125M
  unsigned int l = hb_min (2u, m >> 4);
122
125M
  unsigned int r = hb_min (2u, m & 0x0F);
123
125M
  bool reverse_l = 3 == (m >> 4);
124
125M
  bool reverse_r = 3 == (m & 0x0F);
125
126
125M
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
39.7M
  {
128
39.7M
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
39.7M
    buffer->merge_clusters (start, end);
130
131
39.7M
    hb_glyph_info_t *info = buffer->info;
132
39.7M
    hb_glyph_info_t buf[4];
133
134
39.7M
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
39.7M
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
39.7M
    if (l != r)
138
31.2M
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
39.7M
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
39.7M
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
39.7M
    if (reverse_l)
143
8.51M
    {
144
8.51M
      buf[0] = info[end - 1];
145
8.51M
      info[end - 1] = info[end - 2];
146
8.51M
      info[end - 2] = buf[0];
147
8.51M
    }
148
39.7M
    if (reverse_r)
149
825k
    {
150
825k
      buf[0] = info[start];
151
825k
      info[start] = info[start + 1];
152
825k
      info[start + 1] = buf[0];
153
825k
    }
154
39.7M
  }
155
125M
      }
156
170M
    }
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
95.5k
  {
167
95.5k
    TRACE_APPLY (this);
168
169
95.5k
    driver_context_t dc (this);
170
171
95.5k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
95.5k
    driver.drive (&dc, c);
173
174
95.5k
    return_trace (dc.ret);
175
95.5k
  }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
166
40.4k
  {
167
40.4k
    TRACE_APPLY (this);
168
169
40.4k
    driver_context_t dc (this);
170
171
40.4k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
40.4k
    driver.drive (&dc, c);
173
174
40.4k
    return_trace (dc.ret);
175
40.4k
  }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
166
55.1k
  {
167
55.1k
    TRACE_APPLY (this);
168
169
55.1k
    driver_context_t dc (this);
170
171
55.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
55.1k
    driver.drive (&dc, c);
173
174
55.1k
    return_trace (dc.ret);
175
55.1k
  }
176
177
  bool sanitize (hb_sanitize_context_t *c) const
178
22.0k
  {
179
22.0k
    TRACE_SANITIZE (this);
180
22.0k
    return_trace (machine.sanitize (c));
181
22.0k
  }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
178
5.55k
  {
179
5.55k
    TRACE_SANITIZE (this);
180
5.55k
    return_trace (machine.sanitize (c));
181
5.55k
  }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
178
16.5k
  {
179
16.5k
    TRACE_SANITIZE (this);
180
16.5k
    return_trace (machine.sanitize (c));
181
16.5k
  }
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
98.1k
  subs (table+table->substitutionTables) {}
AAT::ContextualSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::ContextualSubtable<AAT::ExtendedTypes> const*, AAT::hb_aat_apply_context_t*)
Line
Count
Source
224
67.8k
  subs (table+table->substitutionTables) {}
AAT::ContextualSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::ContextualSubtable<AAT::ObsoleteTypes> const*, AAT::hb_aat_apply_context_t*)
Line
Count
Source
224
30.3k
  subs (table+table->substitutionTables) {}
225
226
    bool is_actionable (StateTableDriver<Types, EntryData> *driver,
227
      const Entry<EntryData> &entry)
228
200M
    {
229
200M
      hb_buffer_t *buffer = driver->buffer;
230
231
200M
      if (buffer->idx == buffer->len && !mark_set)
232
166k
  return false;
233
234
200M
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
200M
    }
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&)
Line
Count
Source
228
96.1M
    {
229
96.1M
      hb_buffer_t *buffer = driver->buffer;
230
231
96.1M
      if (buffer->idx == buffer->len && !mark_set)
232
122k
  return false;
233
234
96.0M
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
96.1M
    }
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&)
Line
Count
Source
228
104M
    {
229
104M
      hb_buffer_t *buffer = driver->buffer;
230
231
104M
      if (buffer->idx == buffer->len && !mark_set)
232
43.5k
  return false;
233
234
104M
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
104M
    }
236
    void transition (StateTableDriver<Types, EntryData> *driver,
237
         const Entry<EntryData> &entry)
238
146M
    {
239
146M
      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
146M
      if (buffer->idx == buffer->len && !mark_set)
244
80.9k
  return;
245
246
146M
      const HBGlyphID16 *replacement;
247
248
146M
      replacement = nullptr;
249
146M
      if (Types::extended)
250
53.4M
      {
251
53.4M
  if (entry.data.markIndex != 0xFFFF)
252
7.12M
  {
253
7.12M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
254
7.12M
    replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
255
7.12M
  }
256
53.4M
      }
257
92.8M
      else
258
92.8M
      {
259
92.8M
  unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
260
92.8M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
261
92.8M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
262
92.8M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
263
87.9M
    replacement = nullptr;
264
92.8M
      }
265
146M
      if (replacement)
266
8.19M
      {
267
8.19M
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
8.19M
  buffer->info[mark].codepoint = *replacement;
269
8.19M
  if (has_glyph_classes)
270
252k
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
252k
            gdef.get_glyph_props (*replacement));
272
8.19M
  ret = true;
273
8.19M
      }
274
275
146M
      replacement = nullptr;
276
146M
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
146M
      if (Types::extended)
278
53.4M
      {
279
53.4M
  if (entry.data.currentIndex != 0xFFFF)
280
12.9M
  {
281
12.9M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
282
12.9M
    replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
283
12.9M
  }
284
53.4M
      }
285
92.8M
      else
286
92.8M
      {
287
92.8M
  unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
288
92.8M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
289
92.8M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
290
92.8M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
291
88.5M
    replacement = nullptr;
292
92.8M
      }
293
146M
      if (replacement)
294
10.3M
      {
295
10.3M
  buffer->info[idx].codepoint = *replacement;
296
10.3M
  if (has_glyph_classes)
297
394k
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
394k
            gdef.get_glyph_props (*replacement));
299
10.3M
  ret = true;
300
10.3M
      }
301
302
146M
      if (entry.flags & SetMark)
303
105M
      {
304
105M
  mark_set = true;
305
105M
  mark = buffer->idx;
306
105M
      }
307
146M
    }
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&)
Line
Count
Source
238
53.5M
    {
239
53.5M
      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
53.5M
      if (buffer->idx == buffer->len && !mark_set)
244
60.5k
  return;
245
246
53.4M
      const HBGlyphID16 *replacement;
247
248
53.4M
      replacement = nullptr;
249
53.4M
      if (Types::extended)
250
53.4M
      {
251
53.4M
  if (entry.data.markIndex != 0xFFFF)
252
7.12M
  {
253
7.12M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
254
7.12M
    replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
255
7.12M
  }
256
53.4M
      }
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
53.4M
      if (replacement)
266
3.22M
      {
267
3.22M
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
3.22M
  buffer->info[mark].codepoint = *replacement;
269
3.22M
  if (has_glyph_classes)
270
560
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
560
            gdef.get_glyph_props (*replacement));
272
3.22M
  ret = true;
273
3.22M
      }
274
275
53.4M
      replacement = nullptr;
276
53.4M
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
53.4M
      if (Types::extended)
278
53.4M
      {
279
53.4M
  if (entry.data.currentIndex != 0xFFFF)
280
12.9M
  {
281
12.9M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
282
12.9M
    replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
283
12.9M
  }
284
53.4M
      }
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
53.4M
      if (replacement)
294
6.01M
      {
295
6.01M
  buffer->info[idx].codepoint = *replacement;
296
6.01M
  if (has_glyph_classes)
297
56.2k
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
56.2k
            gdef.get_glyph_props (*replacement));
299
6.01M
  ret = true;
300
6.01M
      }
301
302
53.4M
      if (entry.flags & SetMark)
303
35.2M
      {
304
35.2M
  mark_set = true;
305
35.2M
  mark = buffer->idx;
306
35.2M
      }
307
53.4M
    }
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&)
Line
Count
Source
238
92.9M
    {
239
92.9M
      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
92.9M
      if (buffer->idx == buffer->len && !mark_set)
244
20.3k
  return;
245
246
92.8M
      const HBGlyphID16 *replacement;
247
248
92.8M
      replacement = nullptr;
249
92.8M
      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
92.8M
      else
258
92.8M
      {
259
92.8M
  unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
260
92.8M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
261
92.8M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
262
92.8M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
263
87.9M
    replacement = nullptr;
264
92.8M
      }
265
92.8M
      if (replacement)
266
4.96M
      {
267
4.96M
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
4.96M
  buffer->info[mark].codepoint = *replacement;
269
4.96M
  if (has_glyph_classes)
270
252k
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
252k
            gdef.get_glyph_props (*replacement));
272
4.96M
  ret = true;
273
4.96M
      }
274
275
92.8M
      replacement = nullptr;
276
92.8M
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
92.8M
      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
92.8M
      else
286
92.8M
      {
287
92.8M
  unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
288
92.8M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
289
92.8M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
290
92.8M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
291
88.5M
    replacement = nullptr;
292
92.8M
      }
293
92.8M
      if (replacement)
294
4.36M
      {
295
4.36M
  buffer->info[idx].codepoint = *replacement;
296
4.36M
  if (has_glyph_classes)
297
338k
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
338k
            gdef.get_glyph_props (*replacement));
299
4.36M
  ret = true;
300
4.36M
      }
301
302
92.8M
      if (entry.flags & SetMark)
303
70.1M
      {
304
70.1M
  mark_set = true;
305
70.1M
  mark = buffer->idx;
306
70.1M
      }
307
92.8M
    }
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
98.1k
  {
323
98.1k
    TRACE_APPLY (this);
324
325
98.1k
    driver_context_t dc (this, c);
326
327
98.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328
98.1k
    driver.drive (&dc, c);
329
330
98.1k
    return_trace (dc.ret);
331
98.1k
  }
AAT::ContextualSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
322
67.8k
  {
323
67.8k
    TRACE_APPLY (this);
324
325
67.8k
    driver_context_t dc (this, c);
326
327
67.8k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328
67.8k
    driver.drive (&dc, c);
329
330
67.8k
    return_trace (dc.ret);
331
67.8k
  }
AAT::ContextualSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
322
30.3k
  {
323
30.3k
    TRACE_APPLY (this);
324
325
30.3k
    driver_context_t dc (this, c);
326
327
30.3k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328
30.3k
    driver.drive (&dc, c);
329
330
30.3k
    return_trace (dc.ret);
331
30.3k
  }
332
333
  bool sanitize (hb_sanitize_context_t *c) const
334
16.6k
  {
335
16.6k
    TRACE_SANITIZE (this);
336
337
16.6k
    unsigned int num_entries = 0;
338
16.6k
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
15.5k
    if (!Types::extended)
341
6.94k
      return_trace (substitutionTables.sanitize (c, this, 0));
342
343
8.60k
    unsigned int num_lookups = 0;
344
345
8.60k
    const Entry<EntryData> *entries = machine.get_entries ();
346
34.5k
    for (unsigned int i = 0; i < num_entries; i++)
347
25.9k
    {
348
25.9k
      const EntryData &data = entries[i].data;
349
350
25.9k
      if (data.markIndex != 0xFFFF)
351
9.95k
  num_lookups = hb_max (num_lookups, 1u + data.markIndex);
352
25.9k
      if (data.currentIndex != 0xFFFF)
353
5.83k
  num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
354
25.9k
    }
355
356
8.60k
    return_trace (substitutionTables.sanitize (c, this, num_lookups));
357
15.5k
  }
AAT::ContextualSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
334
9.11k
  {
335
9.11k
    TRACE_SANITIZE (this);
336
337
9.11k
    unsigned int num_entries = 0;
338
9.11k
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
8.60k
    if (!Types::extended)
341
0
      return_trace (substitutionTables.sanitize (c, this, 0));
342
343
8.60k
    unsigned int num_lookups = 0;
344
345
8.60k
    const Entry<EntryData> *entries = machine.get_entries ();
346
34.5k
    for (unsigned int i = 0; i < num_entries; i++)
347
25.9k
    {
348
25.9k
      const EntryData &data = entries[i].data;
349
350
25.9k
      if (data.markIndex != 0xFFFF)
351
9.95k
  num_lookups = hb_max (num_lookups, 1u + data.markIndex);
352
25.9k
      if (data.currentIndex != 0xFFFF)
353
5.83k
  num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
354
25.9k
    }
355
356
8.60k
    return_trace (substitutionTables.sanitize (c, this, num_lookups));
357
8.60k
  }
AAT::ContextualSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
334
7.57k
  {
335
7.57k
    TRACE_SANITIZE (this);
336
337
7.57k
    unsigned int num_entries = 0;
338
7.57k
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
6.94k
    if (!Types::extended)
341
6.94k
      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
6.94k
  }
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
128M
  { return entry.flags & PerformAction; }
397
398
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
399
27.4M
  { 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
107M
  { return entry.flags & Offset; }
419
420
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
421
41.7M
  { 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
78.1k
  match_length (0) {}
AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::LigatureSubtable<AAT::ExtendedTypes> const*, AAT::hb_aat_apply_context_t*)
Line
Count
Source
460
55.3k
  match_length (0) {}
AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::LigatureSubtable<AAT::ObsoleteTypes> const*, AAT::hb_aat_apply_context_t*)
Line
Count
Source
460
22.8k
  match_length (0) {}
461
462
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
463
      const Entry<EntryData> &entry)
464
128M
    {
465
128M
      return LigatureEntryT::performAction (entry);
466
128M
    }
AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::LigatureEntry<true>::EntryData>*, AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&)
Line
Count
Source
464
72.7M
    {
465
72.7M
      return LigatureEntryT::performAction (entry);
466
72.7M
    }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
464
56.1M
    {
465
56.1M
      return LigatureEntryT::performAction (entry);
466
56.1M
    }
467
    void transition (StateTableDriver<Types, EntryData> *driver,
468
         const Entry<EntryData> &entry)
469
107M
    {
470
107M
      hb_buffer_t *buffer = driver->buffer;
471
472
107M
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
107M
      if (entry.flags & LigatureEntryT::SetComponent)
474
67.4M
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
67.4M
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
60.4M
    match_length--;
478
479
67.4M
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
67.4M
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
67.4M
      }
482
483
107M
      if (LigatureEntryT::performAction (entry))
484
87.2M
      {
485
87.2M
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
87.2M
  unsigned int end = buffer->out_len;
487
488
87.2M
  if (unlikely (!match_length))
489
18.0M
    return;
490
491
69.2M
  if (buffer->idx >= buffer->len)
492
8.17k
    return; /* TODO Work on previous instead? */
493
494
69.2M
  unsigned int cursor = match_length;
495
496
69.2M
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
69.2M
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
69.2M
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
69.2M
  unsigned int ligature_idx = 0;
501
69.2M
  unsigned int action;
502
69.2M
  do
503
77.8M
  {
504
77.8M
    if (unlikely (!cursor))
505
4.02M
    {
506
      /* Stack underflow.  Clear the stack. */
507
4.02M
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
4.02M
      match_length = 0;
509
4.02M
      break;
510
4.02M
    }
511
512
73.8M
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
73.8M
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
73.8M
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
34.2M
    action = *actionData;
517
518
34.2M
    uint32_t uoffset = action & LigActionOffset;
519
34.2M
    if (uoffset & 0x20000000)
520
20.4M
      uoffset |= 0xC0000000; /* Sign-extend. */
521
34.2M
    int32_t offset = (int32_t) uoffset;
522
34.2M
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
34.2M
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
34.2M
    const HBUINT16 &componentData = component[component_idx];
525
34.2M
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
10.8M
    ligature_idx += componentData;
527
528
10.8M
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
10.8M
         bool (action & LigActionStore),
530
10.8M
         bool (action & LigActionLast));
531
10.8M
    if (action & (LigActionStore | LigActionLast))
532
2.31M
    {
533
2.31M
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
2.31M
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
2.31M
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
66.8k
      hb_codepoint_t lig = ligatureData;
537
538
66.8k
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
66.8k
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
66.8k
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
68.7k
      while (match_length - 1u > cursor)
544
1.91k
      {
545
1.91k
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546
1.91k
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547
1.91k
        if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548
1.91k
      }
549
550
66.8k
      if (unlikely (!buffer->move_to (lig_end))) return;
551
66.8k
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
66.8k
    }
553
554
8.63M
    actionData++;
555
8.63M
  }
556
69.2M
  while (!(action & LigActionLast));
557
69.2M
  if (unlikely (!buffer->move_to (end))) return;
558
69.2M
      }
559
107M
    }
AAT::LigatureSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, AAT::LigatureEntry<true>::EntryData>*, AAT::Entry<AAT::LigatureEntry<true>::EntryData> const&)
Line
Count
Source
469
55.6M
    {
470
55.6M
      hb_buffer_t *buffer = driver->buffer;
471
472
55.6M
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
55.6M
      if (entry.flags & LigatureEntryT::SetComponent)
474
32.4M
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
32.4M
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
28.9M
    match_length--;
478
479
32.4M
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
32.4M
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
32.4M
      }
482
483
55.6M
      if (LigatureEntryT::performAction (entry))
484
39.6M
      {
485
39.6M
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
39.6M
  unsigned int end = buffer->out_len;
487
488
39.6M
  if (unlikely (!match_length))
489
12.2M
    return;
490
491
27.4M
  if (buffer->idx >= buffer->len)
492
2.41k
    return; /* TODO Work on previous instead? */
493
494
27.4M
  unsigned int cursor = match_length;
495
496
27.4M
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
27.4M
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
27.4M
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
27.4M
  unsigned int ligature_idx = 0;
501
27.4M
  unsigned int action;
502
27.4M
  do
503
34.8M
  {
504
34.8M
    if (unlikely (!cursor))
505
3.50M
    {
506
      /* Stack underflow.  Clear the stack. */
507
3.50M
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
3.50M
      match_length = 0;
509
3.50M
      break;
510
3.50M
    }
511
512
31.3M
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
31.3M
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
31.3M
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
26.6M
    action = *actionData;
517
518
26.6M
    uint32_t uoffset = action & LigActionOffset;
519
26.6M
    if (uoffset & 0x20000000)
520
18.2M
      uoffset |= 0xC0000000; /* Sign-extend. */
521
26.6M
    int32_t offset = (int32_t) uoffset;
522
26.6M
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
26.6M
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
26.6M
    const HBUINT16 &componentData = component[component_idx];
525
26.6M
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
9.37M
    ligature_idx += componentData;
527
528
9.37M
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
9.37M
         bool (action & LigActionStore),
530
9.37M
         bool (action & LigActionLast));
531
9.37M
    if (action & (LigActionStore | LigActionLast))
532
2.06M
    {
533
2.06M
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
2.06M
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
2.06M
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
62.9k
      hb_codepoint_t lig = ligatureData;
537
538
62.9k
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
62.9k
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
62.9k
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
64.8k
      while (match_length - 1u > cursor)
544
1.91k
      {
545
1.91k
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546
1.91k
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547
1.91k
        if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548
1.91k
      }
549
550
62.9k
      if (unlikely (!buffer->move_to (lig_end))) return;
551
62.9k
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
62.9k
    }
553
554
7.38M
    actionData++;
555
7.38M
  }
556
27.4M
  while (!(action & LigActionLast));
557
27.4M
  if (unlikely (!buffer->move_to (end))) return;
558
27.4M
      }
559
55.6M
    }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
469
51.8M
    {
470
51.8M
      hb_buffer_t *buffer = driver->buffer;
471
472
51.8M
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
51.8M
      if (entry.flags & LigatureEntryT::SetComponent)
474
34.9M
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
34.9M
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
31.5M
    match_length--;
478
479
34.9M
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
34.9M
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
34.9M
      }
482
483
51.8M
      if (LigatureEntryT::performAction (entry))
484
47.6M
      {
485
47.6M
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
47.6M
  unsigned int end = buffer->out_len;
487
488
47.6M
  if (unlikely (!match_length))
489
5.84M
    return;
490
491
41.7M
  if (buffer->idx >= buffer->len)
492
5.75k
    return; /* TODO Work on previous instead? */
493
494
41.7M
  unsigned int cursor = match_length;
495
496
41.7M
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
41.7M
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
41.7M
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
41.7M
  unsigned int ligature_idx = 0;
501
41.7M
  unsigned int action;
502
41.7M
  do
503
43.0M
  {
504
43.0M
    if (unlikely (!cursor))
505
521k
    {
506
      /* Stack underflow.  Clear the stack. */
507
521k
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
521k
      match_length = 0;
509
521k
      break;
510
521k
    }
511
512
42.4M
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
42.4M
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
42.4M
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
7.61M
    action = *actionData;
517
518
7.61M
    uint32_t uoffset = action & LigActionOffset;
519
7.61M
    if (uoffset & 0x20000000)
520
2.21M
      uoffset |= 0xC0000000; /* Sign-extend. */
521
7.61M
    int32_t offset = (int32_t) uoffset;
522
7.61M
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
7.61M
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
7.61M
    const HBUINT16 &componentData = component[component_idx];
525
7.61M
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
1.50M
    ligature_idx += componentData;
527
528
1.50M
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
1.50M
         bool (action & LigActionStore),
530
1.50M
         bool (action & LigActionLast));
531
1.50M
    if (action & (LigActionStore | LigActionLast))
532
253k
    {
533
253k
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
253k
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
253k
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
3.90k
      hb_codepoint_t lig = ligatureData;
537
538
3.90k
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
3.90k
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
3.90k
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
3.90k
      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
3.90k
      if (unlikely (!buffer->move_to (lig_end))) return;
551
3.90k
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
3.90k
    }
553
554
1.25M
    actionData++;
555
1.25M
  }
556
41.7M
  while (!(action & LigActionLast));
557
41.7M
  if (unlikely (!buffer->move_to (end))) return;
558
41.7M
      }
559
51.8M
    }
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
78.1k
  {
575
78.1k
    TRACE_APPLY (this);
576
577
78.1k
    driver_context_t dc (this, c);
578
579
78.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
78.1k
    driver.drive (&dc, c);
581
582
78.1k
    return_trace (dc.ret);
583
78.1k
  }
AAT::LigatureSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
574
55.3k
  {
575
55.3k
    TRACE_APPLY (this);
576
577
55.3k
    driver_context_t dc (this, c);
578
579
55.3k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
55.3k
    driver.drive (&dc, c);
581
582
55.3k
    return_trace (dc.ret);
583
55.3k
  }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
574
22.8k
  {
575
22.8k
    TRACE_APPLY (this);
576
577
22.8k
    driver_context_t dc (this, c);
578
579
22.8k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
22.8k
    driver.drive (&dc, c);
581
582
22.8k
    return_trace (dc.ret);
583
22.8k
  }
584
585
  bool sanitize (hb_sanitize_context_t *c) const
586
13.5k
  {
587
13.5k
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
13.5k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
13.5k
      ligAction && component && ligature);
591
13.5k
  }
AAT::LigatureSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
586
8.04k
  {
587
8.04k
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
8.04k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
8.04k
      ligAction && component && ligature);
591
8.04k
  }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
586
5.46k
  {
587
5.46k
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
5.46k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
5.46k
      ligAction && component && ligature);
591
5.46k
  }
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
44.5k
  {
611
44.5k
    TRACE_APPLY (this);
612
613
44.5k
    const OT::GDEF &gdef (*c->gdef_table);
614
44.5k
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
44.5k
    bool ret = false;
617
44.5k
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
44.5k
    hb_glyph_info_t *info = c->buffer->info;
620
44.5k
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
44.5k
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
10.1M
    for (unsigned int i = 0; i < count; i++)
624
10.1M
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
10.1M
      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
10.1M
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
10.1M
      if (replacement)
644
3.25M
      {
645
3.25M
  info[i].codepoint = *replacement;
646
3.25M
  if (has_glyph_classes)
647
858k
    _hb_glyph_info_set_glyph_props (&info[i],
648
858k
            gdef.get_glyph_props (*replacement));
649
3.25M
  ret = true;
650
3.25M
      }
651
10.1M
    }
652
653
44.5k
    return_trace (ret);
654
44.5k
  }
AAT::NoncontextualSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
610
14.3k
  {
611
14.3k
    TRACE_APPLY (this);
612
613
14.3k
    const OT::GDEF &gdef (*c->gdef_table);
614
14.3k
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
14.3k
    bool ret = false;
617
14.3k
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
14.3k
    hb_glyph_info_t *info = c->buffer->info;
620
14.3k
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
14.3k
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
2.24M
    for (unsigned int i = 0; i < count; i++)
624
2.23M
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
2.23M
      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
2.23M
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
2.23M
      if (replacement)
644
1.68M
      {
645
1.68M
  info[i].codepoint = *replacement;
646
1.68M
  if (has_glyph_classes)
647
392k
    _hb_glyph_info_set_glyph_props (&info[i],
648
392k
            gdef.get_glyph_props (*replacement));
649
1.68M
  ret = true;
650
1.68M
      }
651
2.23M
    }
652
653
14.3k
    return_trace (ret);
654
14.3k
  }
AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
610
30.1k
  {
611
30.1k
    TRACE_APPLY (this);
612
613
30.1k
    const OT::GDEF &gdef (*c->gdef_table);
614
30.1k
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
30.1k
    bool ret = false;
617
30.1k
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
30.1k
    hb_glyph_info_t *info = c->buffer->info;
620
30.1k
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
30.1k
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
7.93M
    for (unsigned int i = 0; i < count; i++)
624
7.90M
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
7.90M
      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
7.90M
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
7.90M
      if (replacement)
644
1.56M
      {
645
1.56M
  info[i].codepoint = *replacement;
646
1.56M
  if (has_glyph_classes)
647
465k
    _hb_glyph_info_set_glyph_props (&info[i],
648
465k
            gdef.get_glyph_props (*replacement));
649
1.56M
  ret = true;
650
1.56M
      }
651
7.90M
    }
652
653
30.1k
    return_trace (ret);
654
30.1k
  }
655
656
  bool sanitize (hb_sanitize_context_t *c) const
657
9.31k
  {
658
9.31k
    TRACE_SANITIZE (this);
659
9.31k
    return_trace (substitute.sanitize (c));
660
9.31k
  }
AAT::NoncontextualSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
657
2.27k
  {
658
2.27k
    TRACE_SANITIZE (this);
659
2.27k
    return_trace (substitute.sanitize (c));
660
2.27k
  }
AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
657
7.04k
  {
658
7.04k
    TRACE_SANITIZE (this);
659
7.04k
    return_trace (substitute.sanitize (c));
660
7.04k
  }
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
147k
  insertionAction (table+table->insertionAction) {}
AAT::InsertionSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::InsertionSubtable<AAT::ExtendedTypes> const*, AAT::hb_aat_apply_context_t*)
Line
Count
Source
745
90.1k
  insertionAction (table+table->insertionAction) {}
AAT::InsertionSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::InsertionSubtable<AAT::ObsoleteTypes> const*, AAT::hb_aat_apply_context_t*)
Line
Count
Source
745
57.5k
  insertionAction (table+table->insertionAction) {}
746
747
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
748
      const Entry<EntryData> &entry)
749
212M
    {
750
212M
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
212M
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
212M
    }
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&)
Line
Count
Source
749
103M
    {
750
103M
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
103M
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
103M
    }
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&)
Line
Count
Source
749
109M
    {
750
109M
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
109M
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
109M
    }
753
    void transition (StateTableDriver<Types, EntryData> *driver,
754
         const Entry<EntryData> &entry)
755
144M
    {
756
144M
      hb_buffer_t *buffer = driver->buffer;
757
144M
      unsigned int flags = entry.flags;
758
759
144M
      unsigned mark_loc = buffer->out_len;
760
761
144M
      if (entry.data.markedInsertIndex != 0xFFFF)
762
80.2M
      {
763
80.2M
  unsigned int count = (flags & MarkedInsertCount);
764
80.2M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
42.7M
  unsigned int start = entry.data.markedInsertIndex;
766
42.7M
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
42.7M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
42.7M
  bool before = flags & MarkedInsertBefore;
770
771
42.7M
  unsigned int end = buffer->out_len;
772
42.7M
  if (unlikely (!buffer->move_to (mark))) return;
773
774
42.7M
  if (buffer->idx < buffer->len && !before)
775
33.1M
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
42.7M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
42.7M
  if (buffer->idx < buffer->len && !before)
779
33.1M
    buffer->skip_glyph ();
780
781
42.7M
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
42.7M
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
42.7M
      }
785
786
106M
      if (flags & SetMark)
787
54.9M
  mark = mark_loc;
788
789
106M
      if (entry.data.currentInsertIndex != 0xFFFF)
790
58.5M
      {
791
58.5M
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
58.5M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
49.5M
  unsigned int start = entry.data.currentInsertIndex;
794
49.5M
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
49.5M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
49.5M
  bool before = flags & CurrentInsertBefore;
798
799
49.5M
  unsigned int end = buffer->out_len;
800
801
49.5M
  if (buffer->idx < buffer->len && !before)
802
20.8M
    if (unlikely (!buffer->copy_glyph ())) return;
803
  /* TODO We ignore KashidaLike setting. */
804
49.5M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
805
49.5M
  if (buffer->idx < buffer->len && !before)
806
20.8M
    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
49.5M
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
49.5M
      }
825
106M
    }
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&)
Line
Count
Source
755
59.8M
    {
756
59.8M
      hb_buffer_t *buffer = driver->buffer;
757
59.8M
      unsigned int flags = entry.flags;
758
759
59.8M
      unsigned mark_loc = buffer->out_len;
760
761
59.8M
      if (entry.data.markedInsertIndex != 0xFFFF)
762
8.59M
      {
763
8.59M
  unsigned int count = (flags & MarkedInsertCount);
764
8.59M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
6.87M
  unsigned int start = entry.data.markedInsertIndex;
766
6.87M
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
6.87M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
6.87M
  bool before = flags & MarkedInsertBefore;
770
771
6.87M
  unsigned int end = buffer->out_len;
772
6.87M
  if (unlikely (!buffer->move_to (mark))) return;
773
774
6.87M
  if (buffer->idx < buffer->len && !before)
775
3.34M
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
6.87M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
6.87M
  if (buffer->idx < buffer->len && !before)
779
3.34M
    buffer->skip_glyph ();
780
781
6.87M
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
6.87M
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
6.87M
      }
785
786
58.1M
      if (flags & SetMark)
787
23.3M
  mark = mark_loc;
788
789
58.1M
      if (entry.data.currentInsertIndex != 0xFFFF)
790
19.1M
      {
791
19.1M
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
19.1M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
10.9M
  unsigned int start = entry.data.currentInsertIndex;
794
10.9M
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
10.9M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
10.9M
  bool before = flags & CurrentInsertBefore;
798
799
10.9M
  unsigned int end = buffer->out_len;
800
801
10.9M
  if (buffer->idx < buffer->len && !before)
802
7.67M
    if (unlikely (!buffer->copy_glyph ())) return;
803
  /* TODO We ignore KashidaLike setting. */
804
10.9M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
805
10.9M
  if (buffer->idx < buffer->len && !before)
806
7.67M
    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
10.9M
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
10.9M
      }
825
58.1M
    }
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&)
Line
Count
Source
755
84.3M
    {
756
84.3M
      hb_buffer_t *buffer = driver->buffer;
757
84.3M
      unsigned int flags = entry.flags;
758
759
84.3M
      unsigned mark_loc = buffer->out_len;
760
761
84.3M
      if (entry.data.markedInsertIndex != 0xFFFF)
762
71.6M
      {
763
71.6M
  unsigned int count = (flags & MarkedInsertCount);
764
71.6M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
35.9M
  unsigned int start = entry.data.markedInsertIndex;
766
35.9M
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
35.9M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
35.9M
  bool before = flags & MarkedInsertBefore;
770
771
35.9M
  unsigned int end = buffer->out_len;
772
35.9M
  if (unlikely (!buffer->move_to (mark))) return;
773
774
35.9M
  if (buffer->idx < buffer->len && !before)
775
29.8M
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
35.9M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
35.9M
  if (buffer->idx < buffer->len && !before)
779
29.8M
    buffer->skip_glyph ();
780
781
35.9M
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
35.9M
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
35.9M
      }
785
786
48.5M
      if (flags & SetMark)
787
31.6M
  mark = mark_loc;
788
789
48.5M
      if (entry.data.currentInsertIndex != 0xFFFF)
790
39.3M
      {
791
39.3M
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
39.3M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
38.5M
  unsigned int start = entry.data.currentInsertIndex;
794
38.5M
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
38.5M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
38.5M
  bool before = flags & CurrentInsertBefore;
798
799
38.5M
  unsigned int end = buffer->out_len;
800
801
38.5M
  if (buffer->idx < buffer->len && !before)
802
13.1M
    if (unlikely (!buffer->copy_glyph ())) return;
803
  /* TODO We ignore KashidaLike setting. */
804
38.5M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
805
38.5M
  if (buffer->idx < buffer->len && !before)
806
13.1M
    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
38.5M
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
38.5M
      }
825
48.5M
    }
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
147k
  {
837
147k
    TRACE_APPLY (this);
838
839
147k
    driver_context_t dc (this, c);
840
841
147k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
147k
    driver.drive (&dc, c);
843
844
147k
    return_trace (dc.ret);
845
147k
  }
AAT::InsertionSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
836
90.1k
  {
837
90.1k
    TRACE_APPLY (this);
838
839
90.1k
    driver_context_t dc (this, c);
840
841
90.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
90.1k
    driver.drive (&dc, c);
843
844
90.1k
    return_trace (dc.ret);
845
90.1k
  }
AAT::InsertionSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
836
57.5k
  {
837
57.5k
    TRACE_APPLY (this);
838
839
57.5k
    driver_context_t dc (this, c);
840
841
57.5k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
57.5k
    driver.drive (&dc, c);
843
844
57.5k
    return_trace (dc.ret);
845
57.5k
  }
846
847
  bool sanitize (hb_sanitize_context_t *c) const
848
31.3k
  {
849
31.3k
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
31.3k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
31.3k
      insertionAction);
853
31.3k
  }
AAT::InsertionSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
848
15.1k
  {
849
15.1k
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
15.1k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
15.1k
      insertionAction);
853
15.1k
  }
AAT::InsertionSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
848
16.1k
  {
849
16.1k
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
16.1k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
16.1k
      insertionAction);
853
16.1k
  }
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
1.41M
  unsigned int get_size () const     { return length; }
AAT::ChainSubtable<AAT::ExtendedTypes>::get_size() const
Line
Count
Source
894
670k
  unsigned int get_size () const     { return length; }
AAT::ChainSubtable<AAT::ObsoleteTypes>::get_size() const
Line
Count
Source
894
740k
  unsigned int get_size () const     { return length; }
895
628k
  unsigned int get_type () const     { return coverage & 0xFF; }
AAT::ChainSubtable<AAT::ExtendedTypes>::get_type() const
Line
Count
Source
895
320k
  unsigned int get_type () const     { return coverage & 0xFF; }
AAT::ChainSubtable<AAT::ObsoleteTypes>::get_type() const
Line
Count
Source
895
307k
  unsigned int get_type () const     { return coverage & 0xFF; }
896
1.58M
  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
AAT::ChainSubtable<AAT::ExtendedTypes>::get_coverage() const
Line
Count
Source
896
845k
  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
AAT::ChainSubtable<AAT::ObsoleteTypes>::get_coverage() const
Line
Count
Source
896
736k
  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
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
628k
  {
925
628k
    unsigned int subtable_type = get_type ();
926
628k
    TRACE_DISPATCH (this, subtable_type);
927
628k
    switch (subtable_type) {
928
117k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
114k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
91.6k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
53.8k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
179k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
71.6k
    default:      return_trace (c->default_return_value ());
934
628k
    }
935
628k
  }
hb_sanitize_context_t::return_t AAT::ChainSubtable<AAT::ExtendedTypes>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
924
42.5k
  {
925
42.5k
    unsigned int subtable_type = get_type ();
926
42.5k
    TRACE_DISPATCH (this, subtable_type);
927
42.5k
    switch (subtable_type) {
928
5.55k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
9.11k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
8.04k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
2.27k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
15.1k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
2.47k
    default:      return_trace (c->default_return_value ());
934
42.5k
    }
935
42.5k
  }
hb_sanitize_context_t::return_t AAT::ChainSubtable<AAT::ObsoleteTypes>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
924
79.4k
  {
925
79.4k
    unsigned int subtable_type = get_type ();
926
79.4k
    TRACE_DISPATCH (this, subtable_type);
927
79.4k
    switch (subtable_type) {
928
16.5k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
7.57k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
5.46k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
7.04k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
16.1k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
26.6k
    default:      return_trace (c->default_return_value ());
934
79.4k
    }
935
79.4k
  }
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
Line
Count
Source
924
278k
  {
925
278k
    unsigned int subtable_type = get_type ();
926
278k
    TRACE_DISPATCH (this, subtable_type);
927
278k
    switch (subtable_type) {
928
40.4k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
67.8k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
55.3k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
14.3k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
90.1k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
10.1k
    default:      return_trace (c->default_return_value ());
934
278k
    }
935
278k
  }
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
Line
Count
Source
924
228k
  {
925
228k
    unsigned int subtable_type = get_type ();
926
228k
    TRACE_DISPATCH (this, subtable_type);
927
228k
    switch (subtable_type) {
928
55.1k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
30.3k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
22.8k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
30.1k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
57.5k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
32.3k
    default:      return_trace (c->default_return_value ());
934
228k
    }
935
228k
  }
936
937
  bool apply (hb_aat_apply_context_t *c) const
938
506k
  {
939
506k
    TRACE_APPLY (this);
940
506k
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
506k
    return_trace (dispatch (c));
942
506k
  }
AAT::ChainSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
938
278k
  {
939
278k
    TRACE_APPLY (this);
940
278k
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
278k
    return_trace (dispatch (c));
942
278k
  }
AAT::ChainSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
938
228k
  {
939
228k
    TRACE_APPLY (this);
940
228k
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
228k
    return_trace (dispatch (c));
942
228k
  }
943
944
  bool sanitize (hb_sanitize_context_t *c) const
945
122k
  {
946
122k
    TRACE_SANITIZE (this);
947
122k
    if (!length.sanitize (c) ||
948
122k
  length <= min_size ||
949
122k
  !c->check_range (this, length))
950
690
      return_trace (false);
951
952
122k
    hb_sanitize_with_object_t with (c, this);
953
122k
    return_trace (dispatch (c));
954
122k
  }
AAT::ChainSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
945
42.8k
  {
946
42.8k
    TRACE_SANITIZE (this);
947
42.8k
    if (!length.sanitize (c) ||
948
42.8k
  length <= min_size ||
949
42.8k
  !c->check_range (this, length))
950
283
      return_trace (false);
951
952
42.5k
    hb_sanitize_with_object_t with (c, this);
953
42.5k
    return_trace (dispatch (c));
954
42.8k
  }
AAT::ChainSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
945
79.8k
  {
946
79.8k
    TRACE_SANITIZE (this);
947
79.8k
    if (!length.sanitize (c) ||
948
79.8k
  length <= min_size ||
949
79.8k
  !c->check_range (this, length))
950
407
      return_trace (false);
951
952
79.4k
    hb_sanitize_with_object_t with (c, this);
953
79.4k
    return_trace (dispatch (c));
954
79.8k
  }
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
467k
  {
978
467k
    hb_mask_t flags = defaultFlags;
979
467k
    {
980
467k
      unsigned int count = featureCount;
981
6.40M
      for (unsigned i = 0; i < count; i++)
982
5.93M
      {
983
5.93M
  const Feature &feature = featureZ[i];
984
5.93M
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
5.93M
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
5.93M
      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
5.93M
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
5.93M
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
5.93M
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
1.17k
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
1.17k
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
1.17k
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
1.17k
    goto retry;
1001
1.17k
  }
1002
5.93M
#ifndef HB_NO_AAT
1003
5.93M
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
5.93M
     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
5.93M
#endif
1011
5.93M
      }
1012
467k
    }
1013
467k
    return flags;
1014
467k
  }
AAT::Chain<AAT::ExtendedTypes>::compile_flags(hb_aat_map_builder_t const*) const
Line
Count
Source
977
139k
  {
978
139k
    hb_mask_t flags = defaultFlags;
979
139k
    {
980
139k
      unsigned int count = featureCount;
981
2.10M
      for (unsigned i = 0; i < count; i++)
982
1.96M
      {
983
1.96M
  const Feature &feature = featureZ[i];
984
1.96M
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
1.96M
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
1.96M
      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
1.96M
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
1.96M
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
1.96M
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
454
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
454
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
454
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
454
    goto retry;
1001
454
  }
1002
1.96M
#ifndef HB_NO_AAT
1003
1.96M
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
1.96M
     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
1.96M
#endif
1011
1.96M
      }
1012
139k
    }
1013
139k
    return flags;
1014
139k
  }
AAT::Chain<AAT::ObsoleteTypes>::compile_flags(hb_aat_map_builder_t const*) const
Line
Count
Source
977
327k
  {
978
327k
    hb_mask_t flags = defaultFlags;
979
327k
    {
980
327k
      unsigned int count = featureCount;
981
4.30M
      for (unsigned i = 0; i < count; i++)
982
3.97M
      {
983
3.97M
  const Feature &feature = featureZ[i];
984
3.97M
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
3.97M
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
3.97M
      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
3.97M
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
3.97M
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
3.97M
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
725
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
725
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
725
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
725
    goto retry;
1001
725
  }
1002
3.97M
#ifndef HB_NO_AAT
1003
3.97M
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
3.97M
     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
3.97M
#endif
1011
3.97M
      }
1012
327k
    }
1013
327k
    return flags;
1014
327k
  }
1015
1016
  void apply (hb_aat_apply_context_t *c) const
1017
507k
  {
1018
507k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
507k
    unsigned int count = subtableCount;
1020
1.17M
    for (unsigned int i = 0; i < count; i++)
1021
670k
    {
1022
670k
      bool reverse;
1023
1024
670k
      if (hb_none (hb_iter (c->range_flags) |
1025
670k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
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
Line
Count
Source
1025
291k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
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
Line
Count
Source
1025
306k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1026
160k
  goto skip;
1027
510k
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
510k
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
510k
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
58.2k
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
4.12k
  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
506k
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
128k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
506k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
378k
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
506k
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
506k
      if (reverse)
1070
185k
  c->buffer->reverse ();
1071
1072
506k
      subtable->apply (c);
1073
1074
506k
      if (reverse)
1075
185k
  c->buffer->reverse ();
1076
1077
506k
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
506k
      if (unlikely (!c->buffer->successful)) return;
1080
1081
665k
    skip:
1082
665k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
665k
      c->set_lookup_index (c->lookup_index + 1);
1084
665k
    }
1085
507k
  }
AAT::Chain<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
1017
145k
  {
1018
145k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
145k
    unsigned int count = subtableCount;
1020
454k
    for (unsigned int i = 0; i < count; i++)
1021
310k
    {
1022
310k
      bool reverse;
1023
1024
310k
      if (hb_none (hb_iter (c->range_flags) |
1025
310k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1026
29.8k
  goto skip;
1027
280k
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
280k
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
280k
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
8.73k
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
2.56k
  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
278k
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
13.6k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
278k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
264k
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
278k
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
278k
      if (reverse)
1070
14.8k
  c->buffer->reverse ();
1071
1072
278k
      subtable->apply (c);
1073
1074
278k
      if (reverse)
1075
14.8k
  c->buffer->reverse ();
1076
1077
278k
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
278k
      if (unlikely (!c->buffer->successful)) return;
1080
1081
309k
    skip:
1082
309k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
309k
      c->set_lookup_index (c->lookup_index + 1);
1084
309k
    }
1085
145k
  }
AAT::Chain<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
1017
362k
  {
1018
362k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
362k
    unsigned int count = subtableCount;
1020
717k
    for (unsigned int i = 0; i < count; i++)
1021
360k
    {
1022
360k
      bool reverse;
1023
1024
360k
      if (hb_none (hb_iter (c->range_flags) |
1025
360k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1026
130k
  goto skip;
1027
229k
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
229k
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
229k
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
49.5k
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
1.55k
  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
228k
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
114k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
228k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
113k
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
228k
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
228k
      if (reverse)
1070
170k
  c->buffer->reverse ();
1071
1072
228k
      subtable->apply (c);
1073
1074
228k
      if (reverse)
1075
170k
  c->buffer->reverse ();
1076
1077
228k
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
228k
      if (unlikely (!c->buffer->successful)) return;
1080
1081
355k
    skip:
1082
355k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
355k
      c->set_lookup_index (c->lookup_index + 1);
1084
355k
    }
1085
362k
  }
1086
1087
1.05M
  unsigned int get_size () const { return length; }
AAT::Chain<AAT::ExtendedTypes>::get_size() const
Line
Count
Source
1087
299k
  unsigned int get_size () const { return length; }
AAT::Chain<AAT::ObsoleteTypes>::get_size() const
Line
Count
Source
1087
756k
  unsigned int get_size () const { return length; }
1088
1089
  bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
1090
95.7k
  {
1091
95.7k
    TRACE_SANITIZE (this);
1092
95.7k
    if (!length.sanitize (c) ||
1093
95.7k
  length < min_size ||
1094
95.7k
  !c->check_range (this, length))
1095
3.87k
      return_trace (false);
1096
1097
91.9k
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
108
      return_trace (false);
1099
1100
91.8k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
91.8k
    unsigned int count = subtableCount;
1102
209k
    for (unsigned int i = 0; i < count; i++)
1103
122k
    {
1104
122k
      if (!subtable->sanitize (c))
1105
5.38k
  return_trace (false);
1106
117k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
117k
    }
1108
1109
91.8k
    return_trace (true);
1110
91.8k
  }
AAT::Chain<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*, unsigned int) const
Line
Count
Source
1090
22.0k
  {
1091
22.0k
    TRACE_SANITIZE (this);
1092
22.0k
    if (!length.sanitize (c) ||
1093
22.0k
  length < min_size ||
1094
22.0k
  !c->check_range (this, length))
1095
3.55k
      return_trace (false);
1096
1097
18.5k
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
54
      return_trace (false);
1099
1100
18.4k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
18.4k
    unsigned int count = subtableCount;
1102
58.5k
    for (unsigned int i = 0; i < count; i++)
1103
42.8k
    {
1104
42.8k
      if (!subtable->sanitize (c))
1105
2.73k
  return_trace (false);
1106
40.1k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
40.1k
    }
1108
1109
15.7k
    return_trace (true);
1110
18.4k
  }
AAT::Chain<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*, unsigned int) const
Line
Count
Source
1090
73.7k
  {
1091
73.7k
    TRACE_SANITIZE (this);
1092
73.7k
    if (!length.sanitize (c) ||
1093
73.7k
  length < min_size ||
1094
73.7k
  !c->check_range (this, length))
1095
313
      return_trace (false);
1096
1097
73.4k
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
54
      return_trace (false);
1099
1100
73.3k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
73.3k
    unsigned int count = subtableCount;
1102
150k
    for (unsigned int i = 0; i < count; i++)
1103
79.8k
    {
1104
79.8k
      if (!subtable->sanitize (c))
1105
2.64k
  return_trace (false);
1106
77.2k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
77.2k
    }
1108
1109
70.6k
    return_trace (true);
1110
73.3k
  }
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
2.26M
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::has_data() const
Line
Count
Source
1136
1.37M
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::has_data() const
Line
Count
Source
1136
892k
  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
321k
  {
1141
321k
    const Chain<Types> *chain = &firstChain;
1142
321k
    unsigned int count = chainCount;
1143
321k
    if (unlikely (!map->chain_flags.resize (count)))
1144
7.72k
      return;
1145
782k
    for (unsigned int i = 0; i < count; i++)
1146
467k
    {
1147
467k
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
467k
                   mapper->range_first,
1149
467k
                   mapper->range_last});
1150
467k
      chain = &StructAfter<Chain<Types>> (*chain);
1151
467k
    }
1152
314k
  }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
Line
Count
Source
1140
225k
  {
1141
225k
    const Chain<Types> *chain = &firstChain;
1142
225k
    unsigned int count = chainCount;
1143
225k
    if (unlikely (!map->chain_flags.resize (count)))
1144
2.50k
      return;
1145
363k
    for (unsigned int i = 0; i < count; i++)
1146
139k
    {
1147
139k
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
139k
                   mapper->range_first,
1149
139k
                   mapper->range_last});
1150
139k
      chain = &StructAfter<Chain<Types>> (*chain);
1151
139k
    }
1152
223k
  }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
Line
Count
Source
1140
96.3k
  {
1141
96.3k
    const Chain<Types> *chain = &firstChain;
1142
96.3k
    unsigned int count = chainCount;
1143
96.3k
    if (unlikely (!map->chain_flags.resize (count)))
1144
5.22k
      return;
1145
418k
    for (unsigned int i = 0; i < count; i++)
1146
327k
    {
1147
327k
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
327k
                   mapper->range_first,
1149
327k
                   mapper->range_last});
1150
327k
      chain = &StructAfter<Chain<Types>> (*chain);
1151
327k
    }
1152
91.1k
  }
1153
1154
  void apply (hb_aat_apply_context_t *c,
1155
        const hb_aat_map_t &map) const
1156
330k
  {
1157
330k
    if (unlikely (!c->buffer->successful)) return;
1158
1159
330k
    c->buffer->unsafe_to_concat ();
1160
1161
330k
    c->set_lookup_index (0);
1162
330k
    const Chain<Types> *chain = &firstChain;
1163
330k
    unsigned int count = chainCount;
1164
832k
    for (unsigned int i = 0; i < count; i++)
1165
507k
    {
1166
507k
      c->range_flags = &map.chain_flags[i];
1167
507k
      chain->apply (c);
1168
507k
      if (unlikely (!c->buffer->successful)) return;
1169
501k
      chain = &StructAfter<Chain<Types>> (*chain);
1170
501k
    }
1171
330k
  }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&) const
Line
Count
Source
1156
228k
  {
1157
228k
    if (unlikely (!c->buffer->successful)) return;
1158
1159
228k
    c->buffer->unsafe_to_concat ();
1160
1161
228k
    c->set_lookup_index (0);
1162
228k
    const Chain<Types> *chain = &firstChain;
1163
228k
    unsigned int count = chainCount;
1164
372k
    for (unsigned int i = 0; i < count; i++)
1165
145k
    {
1166
145k
      c->range_flags = &map.chain_flags[i];
1167
145k
      chain->apply (c);
1168
145k
      if (unlikely (!c->buffer->successful)) return;
1169
144k
      chain = &StructAfter<Chain<Types>> (*chain);
1170
144k
    }
1171
228k
  }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&) const
Line
Count
Source
1156
101k
  {
1157
101k
    if (unlikely (!c->buffer->successful)) return;
1158
1159
101k
    c->buffer->unsafe_to_concat ();
1160
1161
101k
    c->set_lookup_index (0);
1162
101k
    const Chain<Types> *chain = &firstChain;
1163
101k
    unsigned int count = chainCount;
1164
459k
    for (unsigned int i = 0; i < count; i++)
1165
362k
    {
1166
362k
      c->range_flags = &map.chain_flags[i];
1167
362k
      chain->apply (c);
1168
362k
      if (unlikely (!c->buffer->successful)) return;
1169
357k
      chain = &StructAfter<Chain<Types>> (*chain);
1170
357k
    }
1171
101k
  }
1172
1173
  bool sanitize (hb_sanitize_context_t *c) const
1174
48.7k
  {
1175
48.7k
    TRACE_SANITIZE (this);
1176
48.7k
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
1.69k
      return_trace (false);
1178
1179
47.0k
    const Chain<Types> *chain = &firstChain;
1180
47.0k
    unsigned int count = chainCount;
1181
133k
    for (unsigned int i = 0; i < count; i++)
1182
95.7k
    {
1183
95.7k
      if (!chain->sanitize (c, version))
1184
9.36k
  return_trace (false);
1185
86.4k
      chain = &StructAfter<Chain<Types>> (*chain);
1186
86.4k
    }
1187
1188
37.6k
    return_trace (true);
1189
47.0k
  }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
1174
27.7k
  {
1175
27.7k
    TRACE_SANITIZE (this);
1176
27.7k
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
1.62k
      return_trace (false);
1178
1179
26.1k
    const Chain<Types> *chain = &firstChain;
1180
26.1k
    unsigned int count = chainCount;
1181
41.8k
    for (unsigned int i = 0; i < count; i++)
1182
22.0k
    {
1183
22.0k
      if (!chain->sanitize (c, version))
1184
6.35k
  return_trace (false);
1185
15.7k
      chain = &StructAfter<Chain<Types>> (*chain);
1186
15.7k
    }
1187
1188
19.7k
    return_trace (true);
1189
26.1k
  }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
1174
20.9k
  {
1175
20.9k
    TRACE_SANITIZE (this);
1176
20.9k
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
69
      return_trace (false);
1178
1179
20.8k
    const Chain<Types> *chain = &firstChain;
1180
20.8k
    unsigned int count = chainCount;
1181
91.5k
    for (unsigned int i = 0; i < count; i++)
1182
73.7k
    {
1183
73.7k
      if (!chain->sanitize (c, version))
1184
3.01k
  return_trace (false);
1185
70.6k
      chain = &StructAfter<Chain<Types>> (*chain);
1186
70.6k
    }
1187
1188
17.8k
    return_trace (true);
1189
20.8k
  }
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 */