Coverage Report

Created: 2025-01-16 12:48

/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
25.2k
  start (0), end (0) {}
AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::driver_context_t(AAT::RearrangementSubtable<AAT::ExtendedTypes> const*)
Line
Count
Source
75
12.1k
  start (0), end (0) {}
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::driver_context_t(AAT::RearrangementSubtable<AAT::ObsoleteTypes> const*)
Line
Count
Source
75
13.1k
  start (0), end (0) {}
76
77
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
78
      const Entry<EntryData> &entry)
79
66.5M
    {
80
66.5M
      return (entry.flags & Verb) && start < end;
81
66.5M
    }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ExtendedTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
79
21.4M
    {
80
21.4M
      return (entry.flags & Verb) && start < end;
81
21.4M
    }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
79
45.1M
    {
80
45.1M
      return (entry.flags & Verb) && start < end;
81
45.1M
    }
82
    void transition (StateTableDriver<Types, EntryData> *driver,
83
         const Entry<EntryData> &entry)
84
47.8M
    {
85
47.8M
      hb_buffer_t *buffer = driver->buffer;
86
47.8M
      unsigned int flags = entry.flags;
87
88
47.8M
      if (flags & MarkFirst)
89
21.4M
  start = buffer->idx;
90
91
47.8M
      if (flags & MarkLast)
92
28.9M
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
47.8M
      if ((flags & Verb) && start < end)
95
30.3M
      {
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
30.3M
  const unsigned char map[16] =
101
30.3M
  {
102
30.3M
    0x00, /* 0  no change */
103
30.3M
    0x10, /* 1  Ax => xA */
104
30.3M
    0x01, /* 2  xD => Dx */
105
30.3M
    0x11, /* 3  AxD => DxA */
106
30.3M
    0x20, /* 4  ABx => xAB */
107
30.3M
    0x30, /* 5  ABx => xBA */
108
30.3M
    0x02, /* 6  xCD => CDx */
109
30.3M
    0x03, /* 7  xCD => DCx */
110
30.3M
    0x12, /* 8  AxCD => CDxA */
111
30.3M
    0x13, /* 9  AxCD => DCxA */
112
30.3M
    0x21, /* 10 ABxD => DxAB */
113
30.3M
    0x31, /* 11 ABxD => DxBA */
114
30.3M
    0x22, /* 12 ABxCD => CDxAB */
115
30.3M
    0x32, /* 13 ABxCD => CDxBA */
116
30.3M
    0x23, /* 14 ABxCD => DCxAB */
117
30.3M
    0x33, /* 15 ABxCD => DCxBA */
118
30.3M
  };
119
120
30.3M
  unsigned int m = map[flags & Verb];
121
30.3M
  unsigned int l = hb_min (2u, m >> 4);
122
30.3M
  unsigned int r = hb_min (2u, m & 0x0F);
123
30.3M
  bool reverse_l = 3 == (m >> 4);
124
30.3M
  bool reverse_r = 3 == (m & 0x0F);
125
126
30.3M
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
8.77M
  {
128
8.77M
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
8.77M
    buffer->merge_clusters (start, end);
130
131
8.77M
    hb_glyph_info_t *info = buffer->info;
132
8.77M
    hb_glyph_info_t buf[4];
133
134
8.77M
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
8.77M
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
8.77M
    if (l != r)
138
7.41M
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
8.77M
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
8.77M
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
8.77M
    if (reverse_l)
143
1.37M
    {
144
1.37M
      buf[0] = info[end - 1];
145
1.37M
      info[end - 1] = info[end - 2];
146
1.37M
      info[end - 2] = buf[0];
147
1.37M
    }
148
8.77M
    if (reverse_r)
149
388k
    {
150
388k
      buf[0] = info[start];
151
388k
      info[start] = info[start + 1];
152
388k
      info[start + 1] = buf[0];
153
388k
    }
154
8.77M
  }
155
30.3M
      }
156
47.8M
    }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ExtendedTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
84
12.2M
    {
85
12.2M
      hb_buffer_t *buffer = driver->buffer;
86
12.2M
      unsigned int flags = entry.flags;
87
88
12.2M
      if (flags & MarkFirst)
89
9.05M
  start = buffer->idx;
90
91
12.2M
      if (flags & MarkLast)
92
8.63M
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
12.2M
      if ((flags & Verb) && start < end)
95
4.18M
      {
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
4.18M
  const unsigned char map[16] =
101
4.18M
  {
102
4.18M
    0x00, /* 0  no change */
103
4.18M
    0x10, /* 1  Ax => xA */
104
4.18M
    0x01, /* 2  xD => Dx */
105
4.18M
    0x11, /* 3  AxD => DxA */
106
4.18M
    0x20, /* 4  ABx => xAB */
107
4.18M
    0x30, /* 5  ABx => xBA */
108
4.18M
    0x02, /* 6  xCD => CDx */
109
4.18M
    0x03, /* 7  xCD => DCx */
110
4.18M
    0x12, /* 8  AxCD => CDxA */
111
4.18M
    0x13, /* 9  AxCD => DCxA */
112
4.18M
    0x21, /* 10 ABxD => DxAB */
113
4.18M
    0x31, /* 11 ABxD => DxBA */
114
4.18M
    0x22, /* 12 ABxCD => CDxAB */
115
4.18M
    0x32, /* 13 ABxCD => CDxBA */
116
4.18M
    0x23, /* 14 ABxCD => DCxAB */
117
4.18M
    0x33, /* 15 ABxCD => DCxBA */
118
4.18M
  };
119
120
4.18M
  unsigned int m = map[flags & Verb];
121
4.18M
  unsigned int l = hb_min (2u, m >> 4);
122
4.18M
  unsigned int r = hb_min (2u, m & 0x0F);
123
4.18M
  bool reverse_l = 3 == (m >> 4);
124
4.18M
  bool reverse_r = 3 == (m & 0x0F);
125
126
4.18M
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
1.54M
  {
128
1.54M
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
1.54M
    buffer->merge_clusters (start, end);
130
131
1.54M
    hb_glyph_info_t *info = buffer->info;
132
1.54M
    hb_glyph_info_t buf[4];
133
134
1.54M
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
1.54M
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
1.54M
    if (l != r)
138
1.54M
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
1.54M
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
1.54M
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
1.54M
    if (reverse_l)
143
560
    {
144
560
      buf[0] = info[end - 1];
145
560
      info[end - 1] = info[end - 2];
146
560
      info[end - 2] = buf[0];
147
560
    }
148
1.54M
    if (reverse_r)
149
776
    {
150
776
      buf[0] = info[start];
151
776
      info[start] = info[start + 1];
152
776
      info[start + 1] = buf[0];
153
776
    }
154
1.54M
  }
155
4.18M
      }
156
12.2M
    }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
84
35.5M
    {
85
35.5M
      hb_buffer_t *buffer = driver->buffer;
86
35.5M
      unsigned int flags = entry.flags;
87
88
35.5M
      if (flags & MarkFirst)
89
12.3M
  start = buffer->idx;
90
91
35.5M
      if (flags & MarkLast)
92
20.3M
  end = hb_min (buffer->idx + 1, buffer->len);
93
94
35.5M
      if ((flags & Verb) && start < end)
95
26.1M
      {
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
26.1M
  const unsigned char map[16] =
101
26.1M
  {
102
26.1M
    0x00, /* 0  no change */
103
26.1M
    0x10, /* 1  Ax => xA */
104
26.1M
    0x01, /* 2  xD => Dx */
105
26.1M
    0x11, /* 3  AxD => DxA */
106
26.1M
    0x20, /* 4  ABx => xAB */
107
26.1M
    0x30, /* 5  ABx => xBA */
108
26.1M
    0x02, /* 6  xCD => CDx */
109
26.1M
    0x03, /* 7  xCD => DCx */
110
26.1M
    0x12, /* 8  AxCD => CDxA */
111
26.1M
    0x13, /* 9  AxCD => DCxA */
112
26.1M
    0x21, /* 10 ABxD => DxAB */
113
26.1M
    0x31, /* 11 ABxD => DxBA */
114
26.1M
    0x22, /* 12 ABxCD => CDxAB */
115
26.1M
    0x32, /* 13 ABxCD => CDxBA */
116
26.1M
    0x23, /* 14 ABxCD => DCxAB */
117
26.1M
    0x33, /* 15 ABxCD => DCxBA */
118
26.1M
  };
119
120
26.1M
  unsigned int m = map[flags & Verb];
121
26.1M
  unsigned int l = hb_min (2u, m >> 4);
122
26.1M
  unsigned int r = hb_min (2u, m & 0x0F);
123
26.1M
  bool reverse_l = 3 == (m >> 4);
124
26.1M
  bool reverse_r = 3 == (m & 0x0F);
125
126
26.1M
  if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH)
127
7.23M
  {
128
7.23M
    buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
129
7.23M
    buffer->merge_clusters (start, end);
130
131
7.23M
    hb_glyph_info_t *info = buffer->info;
132
7.23M
    hb_glyph_info_t buf[4];
133
134
7.23M
    hb_memcpy (buf, info + start, l * sizeof (buf[0]));
135
7.23M
    hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
136
137
7.23M
    if (l != r)
138
5.87M
      memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
139
140
7.23M
    hb_memcpy (info + start, buf + 2, r * sizeof (buf[0]));
141
7.23M
    hb_memcpy (info + end - l, buf, l * sizeof (buf[0]));
142
7.23M
    if (reverse_l)
143
1.37M
    {
144
1.37M
      buf[0] = info[end - 1];
145
1.37M
      info[end - 1] = info[end - 2];
146
1.37M
      info[end - 2] = buf[0];
147
1.37M
    }
148
7.23M
    if (reverse_r)
149
388k
    {
150
388k
      buf[0] = info[start];
151
388k
      info[start] = info[start + 1];
152
388k
      info[start + 1] = buf[0];
153
388k
    }
154
7.23M
  }
155
26.1M
      }
156
35.5M
    }
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
25.2k
  {
167
25.2k
    TRACE_APPLY (this);
168
169
25.2k
    driver_context_t dc (this);
170
171
25.2k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
25.2k
    driver.drive (&dc, c);
173
174
25.2k
    return_trace (dc.ret);
175
25.2k
  }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
166
12.1k
  {
167
12.1k
    TRACE_APPLY (this);
168
169
12.1k
    driver_context_t dc (this);
170
171
12.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
12.1k
    driver.drive (&dc, c);
173
174
12.1k
    return_trace (dc.ret);
175
12.1k
  }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
166
13.1k
  {
167
13.1k
    TRACE_APPLY (this);
168
169
13.1k
    driver_context_t dc (this);
170
171
13.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
172
13.1k
    driver.drive (&dc, c);
173
174
13.1k
    return_trace (dc.ret);
175
13.1k
  }
176
177
  bool sanitize (hb_sanitize_context_t *c) const
178
5.92k
  {
179
5.92k
    TRACE_SANITIZE (this);
180
5.92k
    return_trace (machine.sanitize (c));
181
5.92k
  }
AAT::RearrangementSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
178
1.47k
  {
179
1.47k
    TRACE_SANITIZE (this);
180
1.47k
    return_trace (machine.sanitize (c));
181
1.47k
  }
AAT::RearrangementSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
178
4.45k
  {
179
4.45k
    TRACE_SANITIZE (this);
180
4.45k
    return_trace (machine.sanitize (c));
181
4.45k
  }
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
24.3k
  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
20.7k
  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
3.55k
  subs (table+table->substitutionTables) {}
225
226
    bool is_actionable (StateTableDriver<Types, EntryData> *driver,
227
      const Entry<EntryData> &entry)
228
35.9M
    {
229
35.9M
      hb_buffer_t *buffer = driver->buffer;
230
231
35.9M
      if (buffer->idx == buffer->len && !mark_set)
232
43.9k
  return false;
233
234
35.9M
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
35.9M
    }
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
20.1M
    {
229
20.1M
      hb_buffer_t *buffer = driver->buffer;
230
231
20.1M
      if (buffer->idx == buffer->len && !mark_set)
232
38.3k
  return false;
233
234
20.1M
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
20.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
15.7M
    {
229
15.7M
      hb_buffer_t *buffer = driver->buffer;
230
231
15.7M
      if (buffer->idx == buffer->len && !mark_set)
232
5.59k
  return false;
233
234
15.7M
      return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
235
15.7M
    }
236
    void transition (StateTableDriver<Types, EntryData> *driver,
237
         const Entry<EntryData> &entry)
238
27.0M
    {
239
27.0M
      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
27.0M
      if (buffer->idx == buffer->len && !mark_set)
244
21.5k
  return;
245
246
27.0M
      const HBGlyphID16 *replacement;
247
248
27.0M
      replacement = nullptr;
249
27.0M
      if (Types::extended)
250
12.9M
      {
251
12.9M
  if (entry.data.markIndex != 0xFFFF)
252
2.96M
  {
253
2.96M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
254
2.96M
    replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
255
2.96M
  }
256
12.9M
      }
257
14.0M
      else
258
14.0M
      {
259
14.0M
  unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
260
14.0M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
261
14.0M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
262
14.0M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
263
14.0M
    replacement = nullptr;
264
14.0M
      }
265
27.0M
      if (replacement)
266
797k
      {
267
797k
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
797k
  buffer->info[mark].codepoint = *replacement;
269
797k
  if (has_glyph_classes)
270
466
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
466
            gdef.get_glyph_props (*replacement));
272
797k
  ret = true;
273
797k
      }
274
275
27.0M
      replacement = nullptr;
276
27.0M
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
27.0M
      if (Types::extended)
278
12.9M
      {
279
12.9M
  if (entry.data.currentIndex != 0xFFFF)
280
3.68M
  {
281
3.68M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
282
3.68M
    replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
283
3.68M
  }
284
12.9M
      }
285
14.0M
      else
286
14.0M
      {
287
14.0M
  unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
288
14.0M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
289
14.0M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
290
14.0M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
291
13.8M
    replacement = nullptr;
292
14.0M
      }
293
27.0M
      if (replacement)
294
1.79M
      {
295
1.79M
  buffer->info[idx].codepoint = *replacement;
296
1.79M
  if (has_glyph_classes)
297
413
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
413
            gdef.get_glyph_props (*replacement));
299
1.79M
  ret = true;
300
1.79M
      }
301
302
27.0M
      if (entry.flags & SetMark)
303
20.0M
      {
304
20.0M
  mark_set = true;
305
20.0M
  mark = buffer->idx;
306
20.0M
      }
307
27.0M
    }
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
12.9M
    {
239
12.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
12.9M
      if (buffer->idx == buffer->len && !mark_set)
244
19.0k
  return;
245
246
12.9M
      const HBGlyphID16 *replacement;
247
248
12.9M
      replacement = nullptr;
249
12.9M
      if (Types::extended)
250
12.9M
      {
251
12.9M
  if (entry.data.markIndex != 0xFFFF)
252
2.96M
  {
253
2.96M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex];
254
2.96M
    replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
255
2.96M
  }
256
12.9M
      }
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
12.9M
      if (replacement)
266
751k
      {
267
751k
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
751k
  buffer->info[mark].codepoint = *replacement;
269
751k
  if (has_glyph_classes)
270
81
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
81
            gdef.get_glyph_props (*replacement));
272
751k
  ret = true;
273
751k
      }
274
275
12.9M
      replacement = nullptr;
276
12.9M
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
12.9M
      if (Types::extended)
278
12.9M
      {
279
12.9M
  if (entry.data.currentIndex != 0xFFFF)
280
3.68M
  {
281
3.68M
    const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex];
282
3.68M
    replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
283
3.68M
  }
284
12.9M
      }
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
12.9M
      if (replacement)
294
1.62M
      {
295
1.62M
  buffer->info[idx].codepoint = *replacement;
296
1.62M
  if (has_glyph_classes)
297
66
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
66
            gdef.get_glyph_props (*replacement));
299
1.62M
  ret = true;
300
1.62M
      }
301
302
12.9M
      if (entry.flags & SetMark)
303
7.62M
      {
304
7.62M
  mark_set = true;
305
7.62M
  mark = buffer->idx;
306
7.62M
      }
307
12.9M
    }
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
14.0M
    {
239
14.0M
      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
14.0M
      if (buffer->idx == buffer->len && !mark_set)
244
2.55k
  return;
245
246
14.0M
      const HBGlyphID16 *replacement;
247
248
14.0M
      replacement = nullptr;
249
14.0M
      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
14.0M
      else
258
14.0M
      {
259
14.0M
  unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
260
14.0M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
261
14.0M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
262
14.0M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
263
14.0M
    replacement = nullptr;
264
14.0M
      }
265
14.0M
      if (replacement)
266
45.4k
      {
267
45.4k
  buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
268
45.4k
  buffer->info[mark].codepoint = *replacement;
269
45.4k
  if (has_glyph_classes)
270
385
    _hb_glyph_info_set_glyph_props (&buffer->info[mark],
271
385
            gdef.get_glyph_props (*replacement));
272
45.4k
  ret = true;
273
45.4k
      }
274
275
14.0M
      replacement = nullptr;
276
14.0M
      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
277
14.0M
      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
14.0M
      else
286
14.0M
      {
287
14.0M
  unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
288
14.0M
  const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
289
14.0M
  replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
290
14.0M
  if (!replacement->sanitize (&c->sanitizer) || !*replacement)
291
13.8M
    replacement = nullptr;
292
14.0M
      }
293
14.0M
      if (replacement)
294
169k
      {
295
169k
  buffer->info[idx].codepoint = *replacement;
296
169k
  if (has_glyph_classes)
297
347
    _hb_glyph_info_set_glyph_props (&buffer->info[idx],
298
347
            gdef.get_glyph_props (*replacement));
299
169k
  ret = true;
300
169k
      }
301
302
14.0M
      if (entry.flags & SetMark)
303
12.4M
      {
304
12.4M
  mark_set = true;
305
12.4M
  mark = buffer->idx;
306
12.4M
      }
307
14.0M
    }
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
24.3k
  {
323
24.3k
    TRACE_APPLY (this);
324
325
24.3k
    driver_context_t dc (this, c);
326
327
24.3k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328
24.3k
    driver.drive (&dc, c);
329
330
24.3k
    return_trace (dc.ret);
331
24.3k
  }
AAT::ContextualSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
322
20.7k
  {
323
20.7k
    TRACE_APPLY (this);
324
325
20.7k
    driver_context_t dc (this, c);
326
327
20.7k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328
20.7k
    driver.drive (&dc, c);
329
330
20.7k
    return_trace (dc.ret);
331
20.7k
  }
AAT::ContextualSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
322
3.55k
  {
323
3.55k
    TRACE_APPLY (this);
324
325
3.55k
    driver_context_t dc (this, c);
326
327
3.55k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
328
3.55k
    driver.drive (&dc, c);
329
330
3.55k
    return_trace (dc.ret);
331
3.55k
  }
332
333
  bool sanitize (hb_sanitize_context_t *c) const
334
3.65k
  {
335
3.65k
    TRACE_SANITIZE (this);
336
337
3.65k
    unsigned int num_entries = 0;
338
3.65k
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
3.31k
    if (!Types::extended)
341
1.06k
      return_trace (substitutionTables.sanitize (c, this, 0));
342
343
2.25k
    unsigned int num_lookups = 0;
344
345
2.25k
    const Entry<EntryData> *entries = machine.get_entries ();
346
8.76k
    for (unsigned int i = 0; i < num_entries; i++)
347
6.51k
    {
348
6.51k
      const EntryData &data = entries[i].data;
349
350
6.51k
      if (data.markIndex != 0xFFFF)
351
2.13k
  num_lookups = hb_max (num_lookups, 1u + data.markIndex);
352
6.51k
      if (data.currentIndex != 0xFFFF)
353
1.25k
  num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
354
6.51k
    }
355
356
2.25k
    return_trace (substitutionTables.sanitize (c, this, num_lookups));
357
3.31k
  }
AAT::ContextualSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
334
2.42k
  {
335
2.42k
    TRACE_SANITIZE (this);
336
337
2.42k
    unsigned int num_entries = 0;
338
2.42k
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
2.25k
    if (!Types::extended)
341
0
      return_trace (substitutionTables.sanitize (c, this, 0));
342
343
2.25k
    unsigned int num_lookups = 0;
344
345
2.25k
    const Entry<EntryData> *entries = machine.get_entries ();
346
8.76k
    for (unsigned int i = 0; i < num_entries; i++)
347
6.51k
    {
348
6.51k
      const EntryData &data = entries[i].data;
349
350
6.51k
      if (data.markIndex != 0xFFFF)
351
2.13k
  num_lookups = hb_max (num_lookups, 1u + data.markIndex);
352
6.51k
      if (data.currentIndex != 0xFFFF)
353
1.25k
  num_lookups = hb_max (num_lookups, 1u + data.currentIndex);
354
6.51k
    }
355
356
2.25k
    return_trace (substitutionTables.sanitize (c, this, num_lookups));
357
2.25k
  }
AAT::ContextualSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
334
1.23k
  {
335
1.23k
    TRACE_SANITIZE (this);
336
337
1.23k
    unsigned int num_entries = 0;
338
1.23k
    if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
339
340
1.06k
    if (!Types::extended)
341
1.06k
      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
1.06k
  }
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
14.4M
  { return entry.flags & PerformAction; }
397
398
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
399
4.01M
  { 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
16.2M
  { return entry.flags & Offset; }
419
420
  static unsigned int ligActionIndex (const Entry<EntryData> &entry)
421
5.92M
  { 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
17.4k
  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
14.5k
  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
2.92k
  match_length (0) {}
461
462
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
463
      const Entry<EntryData> &entry)
464
16.3M
    {
465
16.3M
      return LigatureEntryT::performAction (entry);
466
16.3M
    }
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
8.09M
    {
465
8.09M
      return LigatureEntryT::performAction (entry);
466
8.09M
    }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::is_actionable(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
464
8.27M
    {
465
8.27M
      return LigatureEntryT::performAction (entry);
466
8.27M
    }
467
    void transition (StateTableDriver<Types, EntryData> *driver,
468
         const Entry<EntryData> &entry)
469
14.2M
    {
470
14.2M
      hb_buffer_t *buffer = driver->buffer;
471
472
14.2M
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
14.2M
      if (entry.flags & LigatureEntryT::SetComponent)
474
9.79M
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
9.79M
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
9.27M
    match_length--;
478
479
9.79M
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
9.79M
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
9.79M
      }
482
483
14.2M
      if (LigatureEntryT::performAction (entry))
484
12.4M
      {
485
12.4M
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
12.4M
  unsigned int end = buffer->out_len;
487
488
12.4M
  if (unlikely (!match_length))
489
2.54M
    return;
490
491
9.93M
  if (buffer->idx >= buffer->len)
492
1.19k
    return; /* TODO Work on previous instead? */
493
494
9.93M
  unsigned int cursor = match_length;
495
496
9.93M
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
9.93M
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
9.93M
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
9.93M
  unsigned int ligature_idx = 0;
501
9.93M
  unsigned int action;
502
9.93M
  do
503
10.9M
  {
504
10.9M
    if (unlikely (!cursor))
505
238k
    {
506
      /* Stack underflow.  Clear the stack. */
507
238k
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
238k
      match_length = 0;
509
238k
      break;
510
238k
    }
511
512
10.7M
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
10.7M
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
10.7M
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
4.07M
    action = *actionData;
517
518
4.07M
    uint32_t uoffset = action & LigActionOffset;
519
4.07M
    if (uoffset & 0x20000000)
520
3.30M
      uoffset |= 0xC0000000; /* Sign-extend. */
521
4.07M
    int32_t offset = (int32_t) uoffset;
522
4.07M
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
4.07M
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
4.07M
    const HBUINT16 &componentData = component[component_idx];
525
4.07M
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
1.17M
    ligature_idx += componentData;
527
528
1.17M
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
1.17M
         bool (action & LigActionStore),
530
1.17M
         bool (action & LigActionLast));
531
1.17M
    if (action & (LigActionStore | LigActionLast))
532
228k
    {
533
228k
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
228k
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
228k
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
111k
      hb_codepoint_t lig = ligatureData;
537
538
111k
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
111k
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
111k
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
111k
      while (match_length - 1u > cursor)
544
173
      {
545
173
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546
173
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547
173
        if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548
173
      }
549
550
111k
      if (unlikely (!buffer->move_to (lig_end))) return;
551
111k
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
111k
    }
553
554
1.05M
    actionData++;
555
1.05M
  }
556
9.93M
  while (!(action & LigActionLast));
557
9.93M
  if (unlikely (!buffer->move_to (end))) return;
558
9.93M
      }
559
14.2M
    }
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
6.30M
    {
470
6.30M
      hb_buffer_t *buffer = driver->buffer;
471
472
6.30M
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
6.30M
      if (entry.flags & LigatureEntryT::SetComponent)
474
4.52M
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
4.52M
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
4.29M
    match_length--;
478
479
4.52M
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
4.52M
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
4.52M
      }
482
483
6.30M
      if (LigatureEntryT::performAction (entry))
484
4.85M
      {
485
4.85M
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
4.85M
  unsigned int end = buffer->out_len;
487
488
4.85M
  if (unlikely (!match_length))
489
846k
    return;
490
491
4.01M
  if (buffer->idx >= buffer->len)
492
384
    return; /* TODO Work on previous instead? */
493
494
4.01M
  unsigned int cursor = match_length;
495
496
4.01M
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
4.01M
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
4.01M
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
4.01M
  unsigned int ligature_idx = 0;
501
4.01M
  unsigned int action;
502
4.01M
  do
503
5.04M
  {
504
5.04M
    if (unlikely (!cursor))
505
221k
    {
506
      /* Stack underflow.  Clear the stack. */
507
221k
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
221k
      match_length = 0;
509
221k
      break;
510
221k
    }
511
512
4.82M
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
4.82M
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
4.82M
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
4.00M
    action = *actionData;
517
518
4.00M
    uint32_t uoffset = action & LigActionOffset;
519
4.00M
    if (uoffset & 0x20000000)
520
3.30M
      uoffset |= 0xC0000000; /* Sign-extend. */
521
4.00M
    int32_t offset = (int32_t) uoffset;
522
4.00M
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
4.00M
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
4.00M
    const HBUINT16 &componentData = component[component_idx];
525
4.00M
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
1.15M
    ligature_idx += componentData;
527
528
1.15M
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
1.15M
         bool (action & LigActionStore),
530
1.15M
         bool (action & LigActionLast));
531
1.15M
    if (action & (LigActionStore | LigActionLast))
532
228k
    {
533
228k
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
228k
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
228k
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
111k
      hb_codepoint_t lig = ligatureData;
537
538
111k
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
111k
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
111k
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
111k
      while (match_length - 1u > cursor)
544
173
      {
545
173
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546
173
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547
173
        if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548
173
      }
549
550
111k
      if (unlikely (!buffer->move_to (lig_end))) return;
551
111k
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
111k
    }
553
554
1.03M
    actionData++;
555
1.03M
  }
556
4.01M
  while (!(action & LigActionLast));
557
4.01M
  if (unlikely (!buffer->move_to (end))) return;
558
4.01M
      }
559
6.30M
    }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::driver_context_t::transition(AAT::StateTableDriver<AAT::ObsoleteTypes, void>*, AAT::Entry<void> const&)
Line
Count
Source
469
7.95M
    {
470
7.95M
      hb_buffer_t *buffer = driver->buffer;
471
472
7.95M
      DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
473
7.95M
      if (entry.flags & LigatureEntryT::SetComponent)
474
5.26M
      {
475
  /* Never mark same index twice, in case DontAdvance was used... */
476
5.26M
  if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
477
4.97M
    match_length--;
478
479
5.26M
  match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
480
5.26M
  DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
481
5.26M
      }
482
483
7.95M
      if (LigatureEntryT::performAction (entry))
484
7.62M
      {
485
7.62M
  DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length);
486
7.62M
  unsigned int end = buffer->out_len;
487
488
7.62M
  if (unlikely (!match_length))
489
1.70M
    return;
490
491
5.92M
  if (buffer->idx >= buffer->len)
492
815
    return; /* TODO Work on previous instead? */
493
494
5.92M
  unsigned int cursor = match_length;
495
496
5.92M
  unsigned int action_idx = LigatureEntryT::ligActionIndex (entry);
497
5.92M
  action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ);
498
5.92M
  const HBUINT32 *actionData = &ligAction[action_idx];
499
500
5.92M
  unsigned int ligature_idx = 0;
501
5.92M
  unsigned int action;
502
5.92M
  do
503
5.94M
  {
504
5.94M
    if (unlikely (!cursor))
505
16.8k
    {
506
      /* Stack underflow.  Clear the stack. */
507
16.8k
      DEBUG_MSG (APPLY, nullptr, "Stack underflow");
508
16.8k
      match_length = 0;
509
16.8k
      break;
510
16.8k
    }
511
512
5.92M
    DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
513
5.92M
    if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
514
515
5.92M
    if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
516
69.7k
    action = *actionData;
517
518
69.7k
    uint32_t uoffset = action & LigActionOffset;
519
69.7k
    if (uoffset & 0x20000000)
520
203
      uoffset |= 0xC0000000; /* Sign-extend. */
521
69.7k
    int32_t offset = (int32_t) uoffset;
522
69.7k
    unsigned int component_idx = buffer->cur().codepoint + offset;
523
69.7k
    component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
524
69.7k
    const HBUINT16 &componentData = component[component_idx];
525
69.7k
    if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
526
16.8k
    ligature_idx += componentData;
527
528
16.8k
    DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
529
16.8k
         bool (action & LigActionStore),
530
16.8k
         bool (action & LigActionLast));
531
16.8k
    if (action & (LigActionStore | LigActionLast))
532
57
    {
533
57
      ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
534
57
      const HBGlyphID16 &ligatureData = ligature[ligature_idx];
535
57
      if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
536
0
      hb_codepoint_t lig = ligatureData;
537
538
0
      DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
539
0
      if (unlikely (!buffer->replace_glyph (lig))) return;
540
541
0
      unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
542
      /* Now go and delete all subsequent components. */
543
0
      while (match_length - 1u > cursor)
544
0
      {
545
0
        DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
546
0
        if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
547
0
        if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
548
0
      }
549
550
0
      if (unlikely (!buffer->move_to (lig_end))) return;
551
0
      buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
552
0
    }
553
554
16.8k
    actionData++;
555
16.8k
  }
556
5.92M
  while (!(action & LigActionLast));
557
5.92M
  if (unlikely (!buffer->move_to (end))) return;
558
5.92M
      }
559
7.95M
    }
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
17.4k
  {
575
17.4k
    TRACE_APPLY (this);
576
577
17.4k
    driver_context_t dc (this, c);
578
579
17.4k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
17.4k
    driver.drive (&dc, c);
581
582
17.4k
    return_trace (dc.ret);
583
17.4k
  }
AAT::LigatureSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
574
14.5k
  {
575
14.5k
    TRACE_APPLY (this);
576
577
14.5k
    driver_context_t dc (this, c);
578
579
14.5k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
14.5k
    driver.drive (&dc, c);
581
582
14.5k
    return_trace (dc.ret);
583
14.5k
  }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
574
2.92k
  {
575
2.92k
    TRACE_APPLY (this);
576
577
2.92k
    driver_context_t dc (this, c);
578
579
2.92k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
580
2.92k
    driver.drive (&dc, c);
581
582
2.92k
    return_trace (dc.ret);
583
2.92k
  }
584
585
  bool sanitize (hb_sanitize_context_t *c) const
586
2.95k
  {
587
2.95k
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
2.95k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
2.95k
      ligAction && component && ligature);
591
2.95k
  }
AAT::LigatureSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
586
2.00k
  {
587
2.00k
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
2.00k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
2.00k
      ligAction && component && ligature);
591
2.00k
  }
AAT::LigatureSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
586
949
  {
587
949
    TRACE_SANITIZE (this);
588
    /* The rest of array sanitizations are done at run-time. */
589
949
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
590
949
      ligAction && component && ligature);
591
949
  }
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
7.32k
  {
611
7.32k
    TRACE_APPLY (this);
612
613
7.32k
    const OT::GDEF &gdef (*c->gdef_table);
614
7.32k
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
7.32k
    bool ret = false;
617
7.32k
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
7.32k
    hb_glyph_info_t *info = c->buffer->info;
620
7.32k
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
7.32k
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
1.17M
    for (unsigned int i = 0; i < count; i++)
624
1.17M
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
1.17M
      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
1.17M
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
1.17M
      if (replacement)
644
775k
      {
645
775k
  info[i].codepoint = *replacement;
646
775k
  if (has_glyph_classes)
647
59.1k
    _hb_glyph_info_set_glyph_props (&info[i],
648
59.1k
            gdef.get_glyph_props (*replacement));
649
775k
  ret = true;
650
775k
      }
651
1.17M
    }
652
653
7.32k
    return_trace (ret);
654
7.32k
  }
AAT::NoncontextualSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
610
4.59k
  {
611
4.59k
    TRACE_APPLY (this);
612
613
4.59k
    const OT::GDEF &gdef (*c->gdef_table);
614
4.59k
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
4.59k
    bool ret = false;
617
4.59k
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
4.59k
    hb_glyph_info_t *info = c->buffer->info;
620
4.59k
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
4.59k
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
759k
    for (unsigned int i = 0; i < count; i++)
624
754k
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
754k
      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
754k
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
754k
      if (replacement)
644
649k
      {
645
649k
  info[i].codepoint = *replacement;
646
649k
  if (has_glyph_classes)
647
1.12k
    _hb_glyph_info_set_glyph_props (&info[i],
648
1.12k
            gdef.get_glyph_props (*replacement));
649
649k
  ret = true;
650
649k
      }
651
754k
    }
652
653
4.59k
    return_trace (ret);
654
4.59k
  }
AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
610
2.72k
  {
611
2.72k
    TRACE_APPLY (this);
612
613
2.72k
    const OT::GDEF &gdef (*c->gdef_table);
614
2.72k
    bool has_glyph_classes = gdef.has_glyph_classes ();
615
616
2.72k
    bool ret = false;
617
2.72k
    unsigned int num_glyphs = c->face->get_num_glyphs ();
618
619
2.72k
    hb_glyph_info_t *info = c->buffer->info;
620
2.72k
    unsigned int count = c->buffer->len;
621
    // If there's only one range, we already checked the flag.
622
2.72k
    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
623
418k
    for (unsigned int i = 0; i < count; i++)
624
415k
    {
625
      /* This block copied from StateTableDriver::drive. Keep in sync. */
626
415k
      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
415k
      const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
643
415k
      if (replacement)
644
126k
      {
645
126k
  info[i].codepoint = *replacement;
646
126k
  if (has_glyph_classes)
647
58.0k
    _hb_glyph_info_set_glyph_props (&info[i],
648
58.0k
            gdef.get_glyph_props (*replacement));
649
126k
  ret = true;
650
126k
      }
651
415k
    }
652
653
2.72k
    return_trace (ret);
654
2.72k
  }
655
656
  bool sanitize (hb_sanitize_context_t *c) const
657
1.23k
  {
658
1.23k
    TRACE_SANITIZE (this);
659
1.23k
    return_trace (substitute.sanitize (c));
660
1.23k
  }
AAT::NoncontextualSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
657
684
  {
658
684
    TRACE_SANITIZE (this);
659
684
    return_trace (substitute.sanitize (c));
660
684
  }
AAT::NoncontextualSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
657
555
  {
658
555
    TRACE_SANITIZE (this);
659
555
    return_trace (substitute.sanitize (c));
660
555
  }
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
36.8k
  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
28.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
8.69k
  insertionAction (table+table->insertionAction) {}
746
747
    bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
748
      const Entry<EntryData> &entry)
749
40.3M
    {
750
40.3M
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
40.3M
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
40.3M
    }
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
26.5M
    {
750
26.5M
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
26.5M
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
26.5M
    }
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
13.8M
    {
750
13.8M
      return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
751
13.8M
       (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
752
13.8M
    }
753
    void transition (StateTableDriver<Types, EntryData> *driver,
754
         const Entry<EntryData> &entry)
755
27.3M
    {
756
27.3M
      hb_buffer_t *buffer = driver->buffer;
757
27.3M
      unsigned int flags = entry.flags;
758
759
27.3M
      unsigned mark_loc = buffer->out_len;
760
761
27.3M
      if (entry.data.markedInsertIndex != 0xFFFF)
762
12.0M
      {
763
12.0M
  unsigned int count = (flags & MarkedInsertCount);
764
12.0M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
7.38M
  unsigned int start = entry.data.markedInsertIndex;
766
7.38M
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
7.38M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
7.38M
  bool before = flags & MarkedInsertBefore;
770
771
7.38M
  unsigned int end = buffer->out_len;
772
7.38M
  if (unlikely (!buffer->move_to (mark))) return;
773
774
7.38M
  if (buffer->idx < buffer->len && !before)
775
6.25M
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
7.38M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
7.38M
  if (buffer->idx < buffer->len && !before)
779
6.25M
    buffer->skip_glyph ();
780
781
7.38M
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
7.38M
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
7.38M
      }
785
786
22.7M
      if (flags & SetMark)
787
12.9M
  mark = mark_loc;
788
789
22.7M
      if (entry.data.currentInsertIndex != 0xFFFF)
790
11.8M
      {
791
11.8M
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
11.8M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
10.6M
  unsigned int start = entry.data.currentInsertIndex;
794
10.6M
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
10.6M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
10.6M
  bool before = flags & CurrentInsertBefore;
798
799
10.6M
  unsigned int end = buffer->out_len;
800
801
10.6M
  if (buffer->idx < buffer->len && !before)
802
3.82M
    if (unlikely (!buffer->copy_glyph ())) return;
803
  /* TODO We ignore KashidaLike setting. */
804
10.6M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
805
10.6M
  if (buffer->idx < buffer->len && !before)
806
3.82M
    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.6M
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
10.6M
      }
825
22.7M
    }
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
15.6M
    {
756
15.6M
      hb_buffer_t *buffer = driver->buffer;
757
15.6M
      unsigned int flags = entry.flags;
758
759
15.6M
      unsigned mark_loc = buffer->out_len;
760
761
15.6M
      if (entry.data.markedInsertIndex != 0xFFFF)
762
1.64M
      {
763
1.64M
  unsigned int count = (flags & MarkedInsertCount);
764
1.64M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
987k
  unsigned int start = entry.data.markedInsertIndex;
766
987k
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
987k
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
987k
  bool before = flags & MarkedInsertBefore;
770
771
987k
  unsigned int end = buffer->out_len;
772
987k
  if (unlikely (!buffer->move_to (mark))) return;
773
774
987k
  if (buffer->idx < buffer->len && !before)
775
657k
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
987k
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
987k
  if (buffer->idx < buffer->len && !before)
779
657k
    buffer->skip_glyph ();
780
781
987k
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
987k
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
987k
      }
785
786
14.9M
      if (flags & SetMark)
787
6.03M
  mark = mark_loc;
788
789
14.9M
      if (entry.data.currentInsertIndex != 0xFFFF)
790
4.66M
      {
791
4.66M
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
4.66M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
3.54M
  unsigned int start = entry.data.currentInsertIndex;
794
3.54M
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
3.54M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
3.54M
  bool before = flags & CurrentInsertBefore;
798
799
3.54M
  unsigned int end = buffer->out_len;
800
801
3.54M
  if (buffer->idx < buffer->len && !before)
802
2.90M
    if (unlikely (!buffer->copy_glyph ())) return;
803
  /* TODO We ignore KashidaLike setting. */
804
3.54M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
805
3.54M
  if (buffer->idx < buffer->len && !before)
806
2.90M
    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
3.54M
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
3.54M
      }
825
14.9M
    }
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
11.7M
    {
756
11.7M
      hb_buffer_t *buffer = driver->buffer;
757
11.7M
      unsigned int flags = entry.flags;
758
759
11.7M
      unsigned mark_loc = buffer->out_len;
760
761
11.7M
      if (entry.data.markedInsertIndex != 0xFFFF)
762
10.3M
      {
763
10.3M
  unsigned int count = (flags & MarkedInsertCount);
764
10.3M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
765
6.40M
  unsigned int start = entry.data.markedInsertIndex;
766
6.40M
  const HBGlyphID16 *glyphs = &insertionAction[start];
767
6.40M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
768
769
6.40M
  bool before = flags & MarkedInsertBefore;
770
771
6.40M
  unsigned int end = buffer->out_len;
772
6.40M
  if (unlikely (!buffer->move_to (mark))) return;
773
774
6.40M
  if (buffer->idx < buffer->len && !before)
775
5.59M
    if (unlikely (!buffer->copy_glyph ())) return;
776
  /* TODO We ignore KashidaLike setting. */
777
6.40M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
778
6.40M
  if (buffer->idx < buffer->len && !before)
779
5.59M
    buffer->skip_glyph ();
780
781
6.40M
  if (unlikely (!buffer->move_to (end + count))) return;
782
783
6.40M
  buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
784
6.40M
      }
785
786
7.77M
      if (flags & SetMark)
787
6.87M
  mark = mark_loc;
788
789
7.77M
      if (entry.data.currentInsertIndex != 0xFFFF)
790
7.16M
      {
791
7.16M
  unsigned int count = (flags & CurrentInsertCount) >> 5;
792
7.16M
  if (unlikely ((buffer->max_ops -= count) <= 0)) return;
793
7.06M
  unsigned int start = entry.data.currentInsertIndex;
794
7.06M
  const HBGlyphID16 *glyphs = &insertionAction[start];
795
7.06M
  if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
796
797
7.06M
  bool before = flags & CurrentInsertBefore;
798
799
7.06M
  unsigned int end = buffer->out_len;
800
801
7.06M
  if (buffer->idx < buffer->len && !before)
802
925k
    if (unlikely (!buffer->copy_glyph ())) return;
803
  /* TODO We ignore KashidaLike setting. */
804
7.06M
  if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
805
7.06M
  if (buffer->idx < buffer->len && !before)
806
925k
    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
7.06M
  if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return;
824
7.06M
      }
825
7.77M
    }
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
36.8k
  {
837
36.8k
    TRACE_APPLY (this);
838
839
36.8k
    driver_context_t dc (this, c);
840
841
36.8k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
36.8k
    driver.drive (&dc, c);
843
844
36.8k
    return_trace (dc.ret);
845
36.8k
  }
AAT::InsertionSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
836
28.1k
  {
837
28.1k
    TRACE_APPLY (this);
838
839
28.1k
    driver_context_t dc (this, c);
840
841
28.1k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
28.1k
    driver.drive (&dc, c);
843
844
28.1k
    return_trace (dc.ret);
845
28.1k
  }
AAT::InsertionSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
836
8.69k
  {
837
8.69k
    TRACE_APPLY (this);
838
839
8.69k
    driver_context_t dc (this, c);
840
841
8.69k
    StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
842
8.69k
    driver.drive (&dc, c);
843
844
8.69k
    return_trace (dc.ret);
845
8.69k
  }
846
847
  bool sanitize (hb_sanitize_context_t *c) const
848
6.95k
  {
849
6.95k
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
6.95k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
6.95k
      insertionAction);
853
6.95k
  }
AAT::InsertionSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
848
3.97k
  {
849
3.97k
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
3.97k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
3.97k
      insertionAction);
853
3.97k
  }
AAT::InsertionSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
848
2.98k
  {
849
2.98k
    TRACE_SANITIZE (this);
850
    /* The rest of array sanitizations are done at run-time. */
851
2.98k
    return_trace (c->check_struct (this) && machine.sanitize (c) &&
852
2.98k
      insertionAction);
853
2.98k
  }
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
322k
  unsigned int get_size () const     { return length; }
AAT::ChainSubtable<AAT::ExtendedTypes>::get_size() const
Line
Count
Source
894
188k
  unsigned int get_size () const     { return length; }
AAT::ChainSubtable<AAT::ObsoleteTypes>::get_size() const
Line
Count
Source
894
134k
  unsigned int get_size () const     { return length; }
895
148k
  unsigned int get_type () const     { return coverage & 0xFF; }
AAT::ChainSubtable<AAT::ExtendedTypes>::get_type() const
Line
Count
Source
895
92.2k
  unsigned int get_type () const     { return coverage & 0xFF; }
AAT::ChainSubtable<AAT::ObsoleteTypes>::get_type() const
Line
Count
Source
895
56.7k
  unsigned int get_type () const     { return coverage & 0xFF; }
896
377k
  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
AAT::ChainSubtable<AAT::ExtendedTypes>::get_coverage() const
Line
Count
Source
896
246k
  unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); }
AAT::ChainSubtable<AAT::ObsoleteTypes>::get_coverage() const
Line
Count
Source
896
130k
  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
148k
  {
925
148k
    unsigned int subtable_type = get_type ();
926
148k
    TRACE_DISPATCH (this, subtable_type);
927
148k
    switch (subtable_type) {
928
31.2k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
27.9k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
20.4k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
8.56k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
43.7k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
16.9k
    default:      return_trace (c->default_return_value ());
934
148k
    }
935
148k
  }
hb_sanitize_context_t::return_t AAT::ChainSubtable<AAT::ExtendedTypes>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
924
10.8k
  {
925
10.8k
    unsigned int subtable_type = get_type ();
926
10.8k
    TRACE_DISPATCH (this, subtable_type);
927
10.8k
    switch (subtable_type) {
928
1.47k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
2.42k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
2.00k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
684
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
3.97k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
331
    default:      return_trace (c->default_return_value ());
934
10.8k
    }
935
10.8k
  }
hb_sanitize_context_t::return_t AAT::ChainSubtable<AAT::ObsoleteTypes>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
924
16.0k
  {
925
16.0k
    unsigned int subtable_type = get_type ();
926
16.0k
    TRACE_DISPATCH (this, subtable_type);
927
16.0k
    switch (subtable_type) {
928
4.45k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
1.23k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
949
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
555
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
2.98k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
5.91k
    default:      return_trace (c->default_return_value ());
934
16.0k
    }
935
16.0k
  }
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
81.3k
  {
925
81.3k
    unsigned int subtable_type = get_type ();
926
81.3k
    TRACE_DISPATCH (this, subtable_type);
927
81.3k
    switch (subtable_type) {
928
12.1k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
20.7k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
14.5k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
4.59k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
28.1k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
1.17k
    default:      return_trace (c->default_return_value ());
934
81.3k
    }
935
81.3k
  }
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
40.6k
  {
925
40.6k
    unsigned int subtable_type = get_type ();
926
40.6k
    TRACE_DISPATCH (this, subtable_type);
927
40.6k
    switch (subtable_type) {
928
13.1k
    case Rearrangement:   return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...));
929
3.55k
    case Contextual:    return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...));
930
2.92k
    case Ligature:    return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...));
931
2.72k
    case Noncontextual:   return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...));
932
8.69k
    case Insertion:   return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...));
933
9.54k
    default:      return_trace (c->default_return_value ());
934
40.6k
    }
935
40.6k
  }
936
937
  bool apply (hb_aat_apply_context_t *c) const
938
121k
  {
939
121k
    TRACE_APPLY (this);
940
121k
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
121k
    return_trace (dispatch (c));
942
121k
  }
AAT::ChainSubtable<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
938
81.3k
  {
939
81.3k
    TRACE_APPLY (this);
940
81.3k
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
81.3k
    return_trace (dispatch (c));
942
81.3k
  }
AAT::ChainSubtable<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
938
40.6k
  {
939
40.6k
    TRACE_APPLY (this);
940
40.6k
    hb_sanitize_with_object_t with (&c->sanitizer, this);
941
40.6k
    return_trace (dispatch (c));
942
40.6k
  }
943
944
  bool sanitize (hb_sanitize_context_t *c) const
945
27.1k
  {
946
27.1k
    TRACE_SANITIZE (this);
947
27.1k
    if (!length.sanitize (c) ||
948
27.1k
  length <= min_size ||
949
27.1k
  !c->check_range (this, length))
950
161
      return_trace (false);
951
952
26.9k
    hb_sanitize_with_object_t with (c, this);
953
26.9k
    return_trace (dispatch (c));
954
27.1k
  }
AAT::ChainSubtable<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
945
10.9k
  {
946
10.9k
    TRACE_SANITIZE (this);
947
10.9k
    if (!length.sanitize (c) ||
948
10.9k
  length <= min_size ||
949
10.9k
  !c->check_range (this, length))
950
97
      return_trace (false);
951
952
10.8k
    hb_sanitize_with_object_t with (c, this);
953
10.8k
    return_trace (dispatch (c));
954
10.9k
  }
AAT::ChainSubtable<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
945
16.1k
  {
946
16.1k
    TRACE_SANITIZE (this);
947
16.1k
    if (!length.sanitize (c) ||
948
16.1k
  length <= min_size ||
949
16.1k
  !c->check_range (this, length))
950
64
      return_trace (false);
951
952
16.0k
    hb_sanitize_with_object_t with (c, this);
953
16.0k
    return_trace (dispatch (c));
954
16.1k
  }
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
104k
  {
978
104k
    hb_mask_t flags = defaultFlags;
979
104k
    {
980
104k
      unsigned int count = featureCount;
981
963k
      for (unsigned i = 0; i < count; i++)
982
858k
      {
983
858k
  const Feature &feature = featureZ[i];
984
858k
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
858k
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
858k
      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
858k
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
858k
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
858k
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
41
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
41
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
41
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
41
    goto retry;
1001
41
  }
1002
858k
#ifndef HB_NO_AAT
1003
858k
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
858k
     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
858k
#endif
1011
858k
      }
1012
104k
    }
1013
104k
    return flags;
1014
104k
  }
AAT::Chain<AAT::ExtendedTypes>::compile_flags(hb_aat_map_builder_t const*) const
Line
Count
Source
977
46.2k
  {
978
46.2k
    hb_mask_t flags = defaultFlags;
979
46.2k
    {
980
46.2k
      unsigned int count = featureCount;
981
146k
      for (unsigned i = 0; i < count; i++)
982
99.8k
      {
983
99.8k
  const Feature &feature = featureZ[i];
984
99.8k
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
99.8k
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
99.8k
      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
99.8k
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
99.8k
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
99.8k
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
0
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
0
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
0
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
0
    goto retry;
1001
0
  }
1002
99.8k
#ifndef HB_NO_AAT
1003
99.8k
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
99.8k
     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
99.8k
#endif
1011
99.8k
      }
1012
46.2k
    }
1013
46.2k
    return flags;
1014
46.2k
  }
AAT::Chain<AAT::ObsoleteTypes>::compile_flags(hb_aat_map_builder_t const*) const
Line
Count
Source
977
58.3k
  {
978
58.3k
    hb_mask_t flags = defaultFlags;
979
58.3k
    {
980
58.3k
      unsigned int count = featureCount;
981
817k
      for (unsigned i = 0; i < count; i++)
982
758k
      {
983
758k
  const Feature &feature = featureZ[i];
984
758k
  hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
985
758k
  hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
986
758k
      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
758k
  hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
990
758k
  if (map->current_features.bsearch (info))
991
0
  {
992
0
    flags &= feature.disableFlags;
993
0
    flags |= feature.enableFlags;
994
0
  }
995
758k
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS)
996
41
  {
997
    /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */
998
41
    type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE;
999
41
    setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS;
1000
41
    goto retry;
1001
41
  }
1002
758k
#ifndef HB_NO_AAT
1003
758k
  else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting &&
1004
     /* TODO: Rudimentary language matching. */
1005
758k
     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
758k
#endif
1011
758k
      }
1012
58.3k
    }
1013
58.3k
    return flags;
1014
58.3k
  }
1015
1016
  void apply (hb_aat_apply_context_t *c) const
1017
109k
  {
1018
109k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
109k
    unsigned int count = subtableCount;
1020
258k
    for (unsigned int i = 0; i < count; i++)
1021
149k
    {
1022
149k
      bool reverse;
1023
1024
149k
      if (hb_none (hb_iter (c->range_flags) |
1025
149k
       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
83.5k
       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
56.0k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1026
26.7k
  goto skip;
1027
122k
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
122k
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
122k
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
10.9k
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
712
  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
121k
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
24.1k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
121k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
97.8k
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
121k
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
121k
      if (reverse)
1070
34.1k
  c->buffer->reverse ();
1071
1072
121k
      subtable->apply (c);
1073
1074
121k
      if (reverse)
1075
34.1k
  c->buffer->reverse ();
1076
1077
121k
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
121k
      if (unlikely (!c->buffer->successful)) return;
1080
1081
148k
    skip:
1082
148k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
148k
      c->set_lookup_index (c->lookup_index + 1);
1084
148k
    }
1085
109k
  }
AAT::Chain<AAT::ExtendedTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
1017
47.2k
  {
1018
47.2k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
47.2k
    unsigned int count = subtableCount;
1020
133k
    for (unsigned int i = 0; i < count; i++)
1021
85.9k
    {
1022
85.9k
      bool reverse;
1023
1024
85.9k
      if (hb_none (hb_iter (c->range_flags) |
1025
85.9k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1026
4.29k
  goto skip;
1027
81.6k
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
81.6k
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
81.6k
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
2.32k
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
327
  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
81.3k
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
2.41k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
81.3k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
78.9k
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
81.3k
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
81.3k
      if (reverse)
1070
3.54k
  c->buffer->reverse ();
1071
1072
81.3k
      subtable->apply (c);
1073
1074
81.3k
      if (reverse)
1075
3.54k
  c->buffer->reverse ();
1076
1077
81.3k
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
81.3k
      if (unlikely (!c->buffer->successful)) return;
1080
1081
85.7k
    skip:
1082
85.7k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
85.7k
      c->set_lookup_index (c->lookup_index + 1);
1084
85.7k
    }
1085
47.2k
  }
AAT::Chain<AAT::ObsoleteTypes>::apply(AAT::hb_aat_apply_context_t*) const
Line
Count
Source
1017
62.6k
  {
1018
62.6k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1019
62.6k
    unsigned int count = subtableCount;
1020
125k
    for (unsigned int i = 0; i < count; i++)
1021
63.4k
    {
1022
63.4k
      bool reverse;
1023
1024
63.4k
      if (hb_none (hb_iter (c->range_flags) |
1025
63.4k
       hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
1026
22.4k
  goto skip;
1027
41.0k
      c->subtable_flags = subtable->subFeatureFlags;
1028
1029
41.0k
      if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
1030
41.0k
    HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
1031
8.59k
    bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
1032
385
  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
40.6k
      reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
1062
21.7k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
1063
40.6k
    bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
1064
18.8k
    HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
1065
1066
40.6k
      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
1067
0
  goto skip;
1068
1069
40.6k
      if (reverse)
1070
30.5k
  c->buffer->reverse ();
1071
1072
40.6k
      subtable->apply (c);
1073
1074
40.6k
      if (reverse)
1075
30.5k
  c->buffer->reverse ();
1076
1077
40.6k
      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
1078
1079
40.6k
      if (unlikely (!c->buffer->successful)) return;
1080
1081
62.5k
    skip:
1082
62.5k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1083
62.5k
      c->set_lookup_index (c->lookup_index + 1);
1084
62.5k
    }
1085
62.6k
  }
1086
1087
232k
  unsigned int get_size () const { return length; }
AAT::Chain<AAT::ExtendedTypes>::get_size() const
Line
Count
Source
1087
97.9k
  unsigned int get_size () const { return length; }
AAT::Chain<AAT::ObsoleteTypes>::get_size() const
Line
Count
Source
1087
134k
  unsigned int get_size () const { return length; }
1088
1089
  bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
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
1.39k
      return_trace (false);
1096
1097
20.6k
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
37
      return_trace (false);
1099
1100
20.6k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
20.6k
    unsigned int count = subtableCount;
1102
46.1k
    for (unsigned int i = 0; i < count; i++)
1103
27.1k
    {
1104
27.1k
      if (!subtable->sanitize (c))
1105
1.58k
  return_trace (false);
1106
25.5k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
25.5k
    }
1108
1109
20.6k
    return_trace (true);
1110
20.6k
  }
AAT::Chain<AAT::ExtendedTypes>::sanitize(hb_sanitize_context_t*, unsigned int) const
Line
Count
Source
1090
6.89k
  {
1091
6.89k
    TRACE_SANITIZE (this);
1092
6.89k
    if (!length.sanitize (c) ||
1093
6.89k
  length < min_size ||
1094
6.89k
  !c->check_range (this, length))
1095
1.32k
      return_trace (false);
1096
1097
5.57k
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
15
      return_trace (false);
1099
1100
5.56k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
5.56k
    unsigned int count = subtableCount;
1102
15.6k
    for (unsigned int i = 0; i < count; i++)
1103
10.9k
    {
1104
10.9k
      if (!subtable->sanitize (c))
1105
950
  return_trace (false);
1106
10.0k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
10.0k
    }
1108
1109
4.61k
    return_trace (true);
1110
5.56k
  }
AAT::Chain<AAT::ObsoleteTypes>::sanitize(hb_sanitize_context_t*, unsigned int) const
Line
Count
Source
1090
15.1k
  {
1091
15.1k
    TRACE_SANITIZE (this);
1092
15.1k
    if (!length.sanitize (c) ||
1093
15.1k
  length < min_size ||
1094
15.1k
  !c->check_range (this, length))
1095
74
      return_trace (false);
1096
1097
15.0k
    if (!c->check_array (featureZ.arrayZ, featureCount))
1098
22
      return_trace (false);
1099
1100
15.0k
    const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
1101
15.0k
    unsigned int count = subtableCount;
1102
30.5k
    for (unsigned int i = 0; i < count; i++)
1103
16.1k
    {
1104
16.1k
      if (!subtable->sanitize (c))
1105
636
  return_trace (false);
1106
15.5k
      subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
1107
15.5k
    }
1108
1109
14.4k
    return_trace (true);
1110
15.0k
  }
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
515k
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::has_data() const
Line
Count
Source
1136
324k
  bool has_data () const { return version != 0; }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::has_data() const
Line
Count
Source
1136
191k
  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
80.7k
  {
1141
80.7k
    const Chain<Types> *chain = &firstChain;
1142
80.7k
    unsigned int count = chainCount;
1143
80.7k
    if (unlikely (!map->chain_flags.resize (count)))
1144
1.24k
      return;
1145
184k
    for (unsigned int i = 0; i < count; i++)
1146
104k
    {
1147
104k
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
104k
                   mapper->range_first,
1149
104k
                   mapper->range_last});
1150
104k
      chain = &StructAfter<Chain<Types>> (*chain);
1151
104k
    }
1152
79.5k
  }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
Line
Count
Source
1140
62.9k
  {
1141
62.9k
    const Chain<Types> *chain = &firstChain;
1142
62.9k
    unsigned int count = chainCount;
1143
62.9k
    if (unlikely (!map->chain_flags.resize (count)))
1144
491
      return;
1145
108k
    for (unsigned int i = 0; i < count; i++)
1146
46.2k
    {
1147
46.2k
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
46.2k
                   mapper->range_first,
1149
46.2k
                   mapper->range_last});
1150
46.2k
      chain = &StructAfter<Chain<Types>> (*chain);
1151
46.2k
    }
1152
62.4k
  }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::compile_flags(hb_aat_map_builder_t const*, hb_aat_map_t*) const
Line
Count
Source
1140
17.8k
  {
1141
17.8k
    const Chain<Types> *chain = &firstChain;
1142
17.8k
    unsigned int count = chainCount;
1143
17.8k
    if (unlikely (!map->chain_flags.resize (count)))
1144
749
      return;
1145
75.4k
    for (unsigned int i = 0; i < count; i++)
1146
58.3k
    {
1147
58.3k
      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
1148
58.3k
                   mapper->range_first,
1149
58.3k
                   mapper->range_last});
1150
58.3k
      chain = &StructAfter<Chain<Types>> (*chain);
1151
58.3k
    }
1152
17.0k
  }
1153
1154
  void apply (hb_aat_apply_context_t *c,
1155
        const hb_aat_map_t &map) const
1156
82.2k
  {
1157
82.2k
    if (unlikely (!c->buffer->successful)) return;
1158
1159
82.2k
    c->buffer->unsafe_to_concat ();
1160
1161
82.2k
    c->set_lookup_index (0);
1162
82.2k
    const Chain<Types> *chain = &firstChain;
1163
82.2k
    unsigned int count = chainCount;
1164
191k
    for (unsigned int i = 0; i < count; i++)
1165
109k
    {
1166
109k
      c->range_flags = &map.chain_flags[i];
1167
109k
      chain->apply (c);
1168
109k
      if (unlikely (!c->buffer->successful)) return;
1169
108k
      chain = &StructAfter<Chain<Types>> (*chain);
1170
108k
    }
1171
82.2k
  }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&) const
Line
Count
Source
1156
63.6k
  {
1157
63.6k
    if (unlikely (!c->buffer->successful)) return;
1158
1159
63.6k
    c->buffer->unsafe_to_concat ();
1160
1161
63.6k
    c->set_lookup_index (0);
1162
63.6k
    const Chain<Types> *chain = &firstChain;
1163
63.6k
    unsigned int count = chainCount;
1164
110k
    for (unsigned int i = 0; i < count; i++)
1165
47.2k
    {
1166
47.2k
      c->range_flags = &map.chain_flags[i];
1167
47.2k
      chain->apply (c);
1168
47.2k
      if (unlikely (!c->buffer->successful)) return;
1169
47.0k
      chain = &StructAfter<Chain<Types>> (*chain);
1170
47.0k
    }
1171
63.6k
  }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::apply(AAT::hb_aat_apply_context_t*, hb_aat_map_t const&) const
Line
Count
Source
1156
18.6k
  {
1157
18.6k
    if (unlikely (!c->buffer->successful)) return;
1158
1159
18.6k
    c->buffer->unsafe_to_concat ();
1160
1161
18.6k
    c->set_lookup_index (0);
1162
18.6k
    const Chain<Types> *chain = &firstChain;
1163
18.6k
    unsigned int count = chainCount;
1164
80.3k
    for (unsigned int i = 0; i < count; i++)
1165
62.6k
    {
1166
62.6k
      c->range_flags = &map.chain_flags[i];
1167
62.6k
      chain->apply (c);
1168
62.6k
      if (unlikely (!c->buffer->successful)) return;
1169
61.7k
      chain = &StructAfter<Chain<Types>> (*chain);
1170
61.7k
    }
1171
18.6k
  }
1172
1173
  bool sanitize (hb_sanitize_context_t *c) const
1174
12.6k
  {
1175
12.6k
    TRACE_SANITIZE (this);
1176
12.6k
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
526
      return_trace (false);
1178
1179
12.1k
    const Chain<Types> *chain = &firstChain;
1180
12.1k
    unsigned int count = chainCount;
1181
31.1k
    for (unsigned int i = 0; i < count; i++)
1182
22.0k
    {
1183
22.0k
      if (!chain->sanitize (c, version))
1184
3.01k
  return_trace (false);
1185
19.0k
      chain = &StructAfter<Chain<Types>> (*chain);
1186
19.0k
    }
1187
1188
9.12k
    return_trace (true);
1189
12.1k
  }
AAT::mortmorx<AAT::ExtendedTypes, 1836020344u>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
1174
8.19k
  {
1175
8.19k
    TRACE_SANITIZE (this);
1176
8.19k
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
494
      return_trace (false);
1178
1179
7.69k
    const Chain<Types> *chain = &firstChain;
1180
7.69k
    unsigned int count = chainCount;
1181
12.3k
    for (unsigned int i = 0; i < count; i++)
1182
6.89k
    {
1183
6.89k
      if (!chain->sanitize (c, version))
1184
2.28k
  return_trace (false);
1185
4.61k
      chain = &StructAfter<Chain<Types>> (*chain);
1186
4.61k
    }
1187
1188
5.41k
    return_trace (true);
1189
7.69k
  }
AAT::mortmorx<AAT::ObsoleteTypes, 1836020340u>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
1174
4.47k
  {
1175
4.47k
    TRACE_SANITIZE (this);
1176
4.47k
    if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
1177
32
      return_trace (false);
1178
1179
4.44k
    const Chain<Types> *chain = &firstChain;
1180
4.44k
    unsigned int count = chainCount;
1181
18.8k
    for (unsigned int i = 0; i < count; i++)
1182
15.1k
    {
1183
15.1k
      if (!chain->sanitize (c, version))
1184
732
  return_trace (false);
1185
14.4k
      chain = &StructAfter<Chain<Types>> (*chain);
1186
14.4k
    }
1187
1188
3.70k
    return_trace (true);
1189
4.44k
  }
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 */