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