/work/workdir/UnpackedTarball/harfbuzz/src/hb-aat-layout-kerx-table.hh
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright © 2018 Ebrahim Byagowi |
3 | | * Copyright © 2018 Google, Inc. |
4 | | * |
5 | | * This is part of HarfBuzz, a text shaping library. |
6 | | * |
7 | | * Permission is hereby granted, without written agreement and without |
8 | | * license or royalty fees, to use, copy, modify, and distribute this |
9 | | * software and its documentation for any purpose, provided that the |
10 | | * above copyright notice and the following two paragraphs appear in |
11 | | * all copies of this software. |
12 | | * |
13 | | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | | * DAMAGE. |
18 | | * |
19 | | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | | * |
25 | | * Google Author(s): Behdad Esfahbod |
26 | | */ |
27 | | |
28 | | #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH |
29 | | #define HB_AAT_LAYOUT_KERX_TABLE_HH |
30 | | |
31 | | #include "hb-kern.hh" |
32 | | #include "hb-aat-layout-ankr-table.hh" |
33 | | #include "hb-set-digest.hh" |
34 | | |
35 | | /* |
36 | | * kerx -- Extended Kerning |
37 | | * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html |
38 | | */ |
39 | | #define HB_AAT_TAG_kerx HB_TAG('k','e','r','x') |
40 | | |
41 | | |
42 | | namespace AAT { |
43 | | |
44 | | using namespace OT; |
45 | | |
46 | | |
47 | | static inline int |
48 | | kerxTupleKern (int value, |
49 | | unsigned int tupleCount, |
50 | | const void *base, |
51 | | hb_aat_apply_context_t *c) |
52 | 218k | { |
53 | 218k | if (likely (!tupleCount || !c)) return value; |
54 | | |
55 | 0 | unsigned int offset = value; |
56 | 0 | const FWORD *pv = &StructAtOffset<FWORD> (base, offset); |
57 | 0 | if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0; |
58 | 0 | hb_barrier (); |
59 | 0 | return *pv; |
60 | 0 | } Unexecuted instantiation: hb-aat-layout.cc:AAT::kerxTupleKern(int, unsigned int, void const*, AAT::hb_aat_apply_context_t*) Unexecuted instantiation: hb-ot-face.cc:AAT::kerxTupleKern(int, unsigned int, void const*, AAT::hb_aat_apply_context_t*) hb-ot-layout.cc:AAT::kerxTupleKern(int, unsigned int, void const*, AAT::hb_aat_apply_context_t*) Line | Count | Source | 52 | 218k | { | 53 | 218k | if (likely (!tupleCount || !c)) return value; | 54 | | | 55 | 0 | unsigned int offset = value; | 56 | 0 | const FWORD *pv = &StructAtOffset<FWORD> (base, offset); | 57 | 0 | if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0; | 58 | 0 | hb_barrier (); | 59 | 0 | return *pv; | 60 | 0 | } |
|
61 | | |
62 | | |
63 | | struct hb_glyph_pair_t |
64 | | { |
65 | | hb_codepoint_t left; |
66 | | hb_codepoint_t right; |
67 | | }; |
68 | | |
69 | | struct KernPair |
70 | | { |
71 | 218k | int get_kerning () const { return value; } |
72 | | |
73 | | int cmp (const hb_glyph_pair_t &o) const |
74 | 2.09M | { |
75 | 2.09M | int ret = left.cmp (o.left); |
76 | 2.09M | if (ret) return ret; |
77 | 393k | return right.cmp (o.right); |
78 | 2.09M | } |
79 | | |
80 | | bool sanitize (hb_sanitize_context_t *c) const |
81 | 0 | { |
82 | 0 | TRACE_SANITIZE (this); |
83 | 0 | return_trace (c->check_struct (this)); |
84 | 0 | } |
85 | | |
86 | | public: |
87 | | HBGlyphID16 left; |
88 | | HBGlyphID16 right; |
89 | | FWORD value; |
90 | | public: |
91 | | DEFINE_SIZE_STATIC (6); |
92 | | }; |
93 | | |
94 | | template <typename KernSubTableHeader> |
95 | | struct KerxSubTableFormat0 |
96 | | { |
97 | | int get_kerning (hb_codepoint_t left, hb_codepoint_t right, |
98 | | hb_aat_apply_context_t *c = nullptr) const |
99 | 218k | { |
100 | 218k | hb_glyph_pair_t pair = {left, right}; |
101 | 218k | int v = pairs.bsearch (pair).get_kerning (); |
102 | 218k | return kerxTupleKern (v, header.tuple_count (), this, c); |
103 | 218k | } Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const Line | Count | Source | 99 | 218k | { | 100 | 218k | hb_glyph_pair_t pair = {left, right}; | 101 | 218k | int v = pairs.bsearch (pair).get_kerning (); | 102 | 218k | return kerxTupleKern (v, header.tuple_count (), this, c); | 103 | 218k | } |
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const |
104 | | |
105 | | bool apply (hb_aat_apply_context_t *c) const |
106 | 2.46M | { |
107 | 2.46M | TRACE_APPLY (this); |
108 | | |
109 | 2.46M | if (!c->plan->requested_kerning) |
110 | 1.58M | return_trace (false); |
111 | | |
112 | 883k | if (header.coverage & header.Backwards) |
113 | 0 | return_trace (false); |
114 | | |
115 | 883k | accelerator_t accel (*this, c); |
116 | 883k | hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); |
117 | 883k | machine.kern (c->font, c->buffer, c->plan->kern_mask); |
118 | | |
119 | 883k | return_trace (true); |
120 | 883k | } Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const Line | Count | Source | 106 | 2.46M | { | 107 | 2.46M | TRACE_APPLY (this); | 108 | | | 109 | 2.46M | if (!c->plan->requested_kerning) | 110 | 1.58M | return_trace (false); | 111 | | | 112 | 883k | if (header.coverage & header.Backwards) | 113 | 0 | return_trace (false); | 114 | | | 115 | 883k | accelerator_t accel (*this, c); | 116 | 883k | hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); | 117 | 883k | machine.kern (c->font, c->buffer, c->plan->kern_mask); | 118 | | | 119 | 883k | return_trace (true); | 120 | 883k | } |
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const |
121 | | |
122 | | template <typename set_t> |
123 | | void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const |
124 | 60 | { |
125 | 60 | for (const KernPair& pair : pairs) |
126 | 53.2k | { |
127 | 53.2k | left_set.add (pair.left); |
128 | 53.2k | right_set.add (pair.right); |
129 | 53.2k | } |
130 | 60 | } Unexecuted instantiation: void AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const void AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const Line | Count | Source | 124 | 60 | { | 125 | 60 | for (const KernPair& pair : pairs) | 126 | 53.2k | { | 127 | 53.2k | left_set.add (pair.left); | 128 | 53.2k | right_set.add (pair.right); | 129 | 53.2k | } | 130 | 60 | } |
Unexecuted instantiation: void AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const |
131 | | |
132 | | struct accelerator_t |
133 | | { |
134 | | const KerxSubTableFormat0 &table; |
135 | | hb_aat_apply_context_t *c; |
136 | | |
137 | | accelerator_t (const KerxSubTableFormat0 &table_, |
138 | | hb_aat_apply_context_t *c_) : |
139 | 883k | table (table_), c (c_) {} Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader> const&, AAT::hb_aat_apply_context_t*) AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader> const&, AAT::hb_aat_apply_context_t*) Line | Count | Source | 139 | 883k | table (table_), c (c_) {} |
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader> const&, AAT::hb_aat_apply_context_t*) |
140 | | |
141 | | int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const |
142 | 2.99M | { |
143 | 2.99M | if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; |
144 | 218k | return table.get_kerning (left, right, c); |
145 | 2.99M | } Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const Line | Count | Source | 142 | 2.99M | { | 143 | 2.99M | if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; | 144 | 218k | return table.get_kerning (left, right, c); | 145 | 2.99M | } |
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const |
146 | | }; |
147 | | |
148 | | |
149 | | bool sanitize (hb_sanitize_context_t *c) const |
150 | 60 | { |
151 | 60 | TRACE_SANITIZE (this); |
152 | 60 | return_trace (likely (pairs.sanitize (c))); |
153 | 60 | } Unexecuted instantiation: AAT::KerxSubTableFormat0<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const AAT::KerxSubTableFormat0<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const Line | Count | Source | 150 | 60 | { | 151 | 60 | TRACE_SANITIZE (this); | 152 | 60 | return_trace (likely (pairs.sanitize (c))); | 153 | 60 | } |
Unexecuted instantiation: AAT::KerxSubTableFormat0<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const |
154 | | |
155 | | protected: |
156 | | KernSubTableHeader header; |
157 | | BinSearchArrayOf<KernPair, typename KernSubTableHeader::Types::HBUINT> |
158 | | pairs; /* Sorted kern records. */ |
159 | | public: |
160 | | DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 16, pairs); |
161 | | }; |
162 | | |
163 | | |
164 | | template <bool extended> |
165 | | struct Format1Entry; |
166 | | |
167 | | template <> |
168 | | struct Format1Entry<true> |
169 | | { |
170 | | enum Flags |
171 | | { |
172 | | Push = 0x8000, /* If set, push this glyph on the kerning stack. */ |
173 | | DontAdvance = 0x4000, /* If set, don't advance to the next glyph |
174 | | * before going to the new state. */ |
175 | | Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */ |
176 | | Reserved = 0x1FFF, /* Not used; set to 0. */ |
177 | | }; |
178 | | |
179 | | struct EntryData |
180 | | { |
181 | | HBUINT16 kernActionIndex;/* Index into the kerning value array. If |
182 | | * this index is 0xFFFF, then no kerning |
183 | | * is to be performed. */ |
184 | | public: |
185 | | DEFINE_SIZE_STATIC (2); |
186 | | }; |
187 | | |
188 | | static bool initiateAction (const Entry<EntryData> &entry) |
189 | 0 | { return entry.flags & Push; } |
190 | | |
191 | | static bool performAction (const Entry<EntryData> &entry) |
192 | 0 | { return entry.data.kernActionIndex != 0xFFFF; } |
193 | | |
194 | | static unsigned int kernActionIndex (const Entry<EntryData> &entry) |
195 | 0 | { return entry.data.kernActionIndex; } |
196 | | }; |
197 | | template <> |
198 | | struct Format1Entry<false> |
199 | | { |
200 | | enum Flags |
201 | | { |
202 | | Push = 0x8000, /* If set, push this glyph on the kerning stack. */ |
203 | | DontAdvance = 0x4000, /* If set, don't advance to the next glyph |
204 | | * before going to the new state. */ |
205 | | Offset = 0x3FFF, /* Byte offset from beginning of subtable to the |
206 | | * value table for the glyphs on the kerning stack. */ |
207 | | |
208 | | Reset = 0x0000, /* Not supported? */ |
209 | | }; |
210 | | |
211 | | typedef void EntryData; |
212 | | |
213 | | static bool initiateAction (const Entry<EntryData> &entry) |
214 | 0 | { return entry.flags & Push; } |
215 | | |
216 | | static bool performAction (const Entry<EntryData> &entry) |
217 | 0 | { return entry.flags & Offset; } |
218 | | |
219 | | static unsigned int kernActionIndex (const Entry<EntryData> &entry) |
220 | 0 | { return entry.flags & Offset; } |
221 | | }; |
222 | | |
223 | | template <typename KernSubTableHeader> |
224 | | struct KerxSubTableFormat1 |
225 | | { |
226 | | typedef typename KernSubTableHeader::Types Types; |
227 | | typedef typename Types::HBUINT HBUINT; |
228 | | |
229 | | typedef Format1Entry<Types::extended> Format1EntryT; |
230 | | typedef typename Format1EntryT::EntryData EntryData; |
231 | | |
232 | | enum Flags |
233 | | { |
234 | | DontAdvance = Format1EntryT::DontAdvance, |
235 | | }; |
236 | | |
237 | | bool is_action_initiable (const Entry<EntryData> &entry) const |
238 | 0 | { |
239 | 0 | return Format1EntryT::initiateAction (entry); |
240 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::is_action_initiable(AAT::Entry<AAT::Format1Entry<true>::EntryData> const&) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::is_action_initiable(AAT::Entry<void> const&) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::is_action_initiable(AAT::Entry<void> const&) const |
241 | | bool is_actionable (const Entry<EntryData> &entry) const |
242 | 0 | { |
243 | 0 | return Format1EntryT::performAction (entry); |
244 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::is_actionable(AAT::Entry<AAT::Format1Entry<true>::EntryData> const&) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::is_actionable(AAT::Entry<void> const&) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::is_actionable(AAT::Entry<void> const&) const |
245 | | |
246 | | struct driver_context_t |
247 | | { |
248 | | static constexpr bool in_place = true; |
249 | | |
250 | | driver_context_t (const KerxSubTableFormat1 *table_, |
251 | | hb_aat_apply_context_t *c_) : |
252 | 0 | c (c_), |
253 | 0 | table (table_), |
254 | | /* Apparently the offset kernAction is from the beginning of the state-machine, |
255 | | * similar to offsets in morx table, NOT from beginning of this table, like |
256 | | * other subtables in kerx. Discovered via testing. */ |
257 | 0 | kernAction (&table->machine + table->kernAction), |
258 | 0 | depth (0), |
259 | 0 | crossStream (table->header.coverage & table->header.CrossStream) {} Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader> const*, AAT::hb_aat_apply_context_t*) Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader> const*, AAT::hb_aat_apply_context_t*) Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::driver_context_t::driver_context_t(AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader> const*, AAT::hb_aat_apply_context_t*) |
260 | | |
261 | | void transition (hb_buffer_t *buffer, |
262 | | StateTableDriver<Types, EntryData, Flags> *driver, |
263 | | const Entry<EntryData> &entry) |
264 | 0 | { |
265 | 0 | unsigned int flags = entry.flags; |
266 | |
|
267 | 0 | if (flags & Format1EntryT::Reset) |
268 | 0 | depth = 0; |
269 | |
|
270 | 0 | if (flags & Format1EntryT::Push) |
271 | 0 | { |
272 | 0 | if (likely (depth < ARRAY_LENGTH (stack))) |
273 | 0 | stack[depth++] = buffer->idx; |
274 | 0 | else |
275 | 0 | depth = 0; /* Probably not what CoreText does, but better? */ |
276 | 0 | } |
277 | |
|
278 | 0 | if (Format1EntryT::performAction (entry) && depth) |
279 | 0 | { |
280 | 0 | unsigned int tuple_count = hb_max (1u, table->header.tuple_count ()); |
281 | |
|
282 | 0 | unsigned int kern_idx = Format1EntryT::kernActionIndex (entry); |
283 | 0 | kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ); |
284 | 0 | const FWORD *actions = &kernAction[kern_idx]; |
285 | 0 | if (!c->sanitizer.check_array (actions, depth, tuple_count)) |
286 | 0 | { |
287 | 0 | depth = 0; |
288 | 0 | return; |
289 | 0 | } |
290 | 0 | hb_barrier (); |
291 | |
|
292 | 0 | hb_mask_t kern_mask = c->plan->kern_mask; |
293 | | |
294 | | /* From Apple 'kern' spec: |
295 | | * "Each pops one glyph from the kerning stack and applies the kerning value to it. |
296 | | * The end of the list is marked by an odd value... */ |
297 | 0 | bool last = false; |
298 | 0 | while (!last && depth) |
299 | 0 | { |
300 | 0 | unsigned int idx = stack[--depth]; |
301 | 0 | int v = *actions; |
302 | 0 | actions += tuple_count; |
303 | 0 | if (idx >= buffer->len) continue; |
304 | | |
305 | | /* "The end of the list is marked by an odd value..." */ |
306 | 0 | last = v & 1; |
307 | 0 | v &= ~1; |
308 | |
|
309 | 0 | hb_glyph_position_t &o = buffer->pos[idx]; |
310 | |
|
311 | 0 | if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) |
312 | 0 | { |
313 | 0 | if (crossStream) |
314 | 0 | { |
315 | | /* The following flag is undocumented in the spec, but described |
316 | | * in the 'kern' table example. */ |
317 | 0 | if (v == -0x8000) |
318 | 0 | { |
319 | 0 | o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE; |
320 | 0 | o.attach_chain() = 0; |
321 | 0 | o.y_offset = 0; |
322 | 0 | } |
323 | 0 | else if (o.attach_type()) |
324 | 0 | { |
325 | 0 | o.y_offset += c->font->em_scale_y (v); |
326 | 0 | buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; |
327 | 0 | } |
328 | 0 | } |
329 | 0 | else if (buffer->info[idx].mask & kern_mask) |
330 | 0 | { |
331 | 0 | auto scaled = c->font->em_scale_x (v); |
332 | 0 | o.x_advance += scaled; |
333 | 0 | o.x_offset += scaled; |
334 | 0 | } |
335 | 0 | } |
336 | 0 | else |
337 | 0 | { |
338 | 0 | if (crossStream) |
339 | 0 | { |
340 | | /* CoreText doesn't do crossStream kerning in vertical. We do. */ |
341 | 0 | if (v == -0x8000) |
342 | 0 | { |
343 | 0 | o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE; |
344 | 0 | o.attach_chain() = 0; |
345 | 0 | o.x_offset = 0; |
346 | 0 | } |
347 | 0 | else if (o.attach_type()) |
348 | 0 | { |
349 | 0 | o.x_offset += c->font->em_scale_x (v); |
350 | 0 | buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; |
351 | 0 | } |
352 | 0 | } |
353 | 0 | else if (buffer->info[idx].mask & kern_mask) |
354 | 0 | { |
355 | 0 | o.y_advance += c->font->em_scale_y (v); |
356 | 0 | o.y_offset += c->font->em_scale_y (v); |
357 | 0 | } |
358 | 0 | } |
359 | 0 | } |
360 | 0 | } |
361 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ExtendedTypes, AAT::Format1Entry<true>::EntryData, AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::Flags>*, AAT::Entry<AAT::Format1Entry<true>::EntryData> const&) Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, void, AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::Flags>*, AAT::Entry<void> const&) Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::driver_context_t::transition(hb_buffer_t*, AAT::StateTableDriver<AAT::ObsoleteTypes, void, AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::Flags>*, AAT::Entry<void> const&) |
362 | | |
363 | | public: |
364 | | hb_aat_apply_context_t *c; |
365 | | const KerxSubTableFormat1 *table; |
366 | | private: |
367 | | const UnsizedArrayOf<FWORD> &kernAction; |
368 | | unsigned int stack[8]; |
369 | | unsigned int depth; |
370 | | bool crossStream; |
371 | | }; |
372 | | |
373 | | bool apply (hb_aat_apply_context_t *c) const |
374 | 0 | { |
375 | 0 | TRACE_APPLY (this); |
376 | |
|
377 | 0 | if (!c->plan->requested_kerning && |
378 | 0 | !(header.coverage & header.CrossStream)) |
379 | 0 | return false; |
380 | | |
381 | 0 | driver_context_t dc (this, c); |
382 | |
|
383 | 0 | StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face); |
384 | |
|
385 | 0 | driver.drive (&dc, c); |
386 | |
|
387 | 0 | return_trace (true); |
388 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const |
389 | | |
390 | | bool sanitize (hb_sanitize_context_t *c) const |
391 | 0 | { |
392 | 0 | TRACE_SANITIZE (this); |
393 | | /* The rest of array sanitizations are done at run-time. */ |
394 | 0 | return_trace (likely (c->check_struct (this) && |
395 | 0 | machine.sanitize (c))); |
396 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const |
397 | | |
398 | | template <typename set_t> |
399 | | void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const |
400 | 0 | { |
401 | 0 | machine.collect_initial_glyphs (left_set, num_glyphs, *this); |
402 | | //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning |
403 | 0 | } Unexecuted instantiation: void AAT::KerxSubTableFormat1<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const Unexecuted instantiation: void AAT::KerxSubTableFormat1<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const Unexecuted instantiation: void AAT::KerxSubTableFormat1<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const |
404 | | |
405 | | protected: |
406 | | KernSubTableHeader header; |
407 | | StateTable<Types, EntryData> machine; |
408 | | NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction; |
409 | | public: |
410 | | DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT::static_size)); |
411 | | }; |
412 | | |
413 | | template <typename KernSubTableHeader> |
414 | | struct KerxSubTableFormat2 |
415 | | { |
416 | | typedef typename KernSubTableHeader::Types Types; |
417 | | typedef typename Types::HBUINT HBUINT; |
418 | | |
419 | | int get_kerning (hb_codepoint_t left, hb_codepoint_t right, |
420 | | hb_aat_apply_context_t *c) const |
421 | 0 | { |
422 | 0 | unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); |
423 | 0 | unsigned int l = (this+leftClassTable).get_class (left, num_glyphs, 0); |
424 | 0 | unsigned int r = (this+rightClassTable).get_class (right, num_glyphs, 0); |
425 | |
|
426 | 0 | const UnsizedArrayOf<FWORD> &arrayZ = this+array; |
427 | 0 | unsigned int kern_idx = l + r; |
428 | 0 | kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ); |
429 | 0 | const FWORD *v = &arrayZ[kern_idx]; |
430 | 0 | if (unlikely (!v->sanitize (&c->sanitizer))) return 0; |
431 | 0 | hb_barrier (); |
432 | |
|
433 | 0 | return kerxTupleKern (*v, header.tuple_count (), this, c); |
434 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::get_kerning(unsigned int, unsigned int, AAT::hb_aat_apply_context_t*) const |
435 | | |
436 | | bool apply (hb_aat_apply_context_t *c) const |
437 | 0 | { |
438 | 0 | TRACE_APPLY (this); |
439 | |
|
440 | 0 | if (!c->plan->requested_kerning) |
441 | 0 | return_trace (false); |
442 | | |
443 | 0 | if (header.coverage & header.Backwards) |
444 | 0 | return_trace (false); |
445 | | |
446 | 0 | accelerator_t accel (*this, c); |
447 | 0 | hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); |
448 | 0 | machine.kern (c->font, c->buffer, c->plan->kern_mask); |
449 | |
|
450 | 0 | return_trace (true); |
451 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::apply(AAT::hb_aat_apply_context_t*) const |
452 | | |
453 | | template <typename set_t> |
454 | | void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const |
455 | 0 | { |
456 | 0 | (this+leftClassTable).collect_glyphs (left_set, num_glyphs); |
457 | 0 | (this+rightClassTable).collect_glyphs (right_set, num_glyphs); |
458 | 0 | } Unexecuted instantiation: void AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const Unexecuted instantiation: void AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const Unexecuted instantiation: void AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::collect_glyphs<hb_bit_set_t>(hb_bit_set_t&, hb_bit_set_t&, unsigned int) const |
459 | | |
460 | | struct accelerator_t |
461 | | { |
462 | | const KerxSubTableFormat2 &table; |
463 | | hb_aat_apply_context_t *c; |
464 | | |
465 | | accelerator_t (const KerxSubTableFormat2 &table_, |
466 | | hb_aat_apply_context_t *c_) : |
467 | 0 | table (table_), c (c_) {} Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader> const&, AAT::hb_aat_apply_context_t*) Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader> const&, AAT::hb_aat_apply_context_t*) Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::accelerator_t::accelerator_t(AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader> const&, AAT::hb_aat_apply_context_t*) |
468 | | |
469 | | int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const |
470 | 0 | { |
471 | 0 | if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; |
472 | 0 | return table.get_kerning (left, right, c); |
473 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::accelerator_t::get_kerning(unsigned int, unsigned int) const |
474 | | }; |
475 | | |
476 | | bool sanitize (hb_sanitize_context_t *c) const |
477 | 0 | { |
478 | 0 | TRACE_SANITIZE (this); |
479 | 0 | return_trace (likely (c->check_struct (this) && |
480 | 0 | leftClassTable.sanitize (c, this) && |
481 | 0 | rightClassTable.sanitize (c, this) && |
482 | 0 | hb_barrier () && |
483 | 0 | c->check_range (this, array))); |
484 | 0 | } Unexecuted instantiation: AAT::KerxSubTableFormat2<AAT::KerxSubTableHeader>::sanitize(hb_sanitize_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernOTSubTableHeader>::sanitize(hb_sanitize_context_t*) const Unexecuted instantiation: AAT::KerxSubTableFormat2<OT::KernAATSubTableHeader>::sanitize(hb_sanitize_context_t*) const |
485 | | |
486 | | protected: |
487 | | KernSubTableHeader header; |
488 | | HBUINT rowWidth; /* The width, in bytes, of a row in the table. */ |
489 | | NNOffsetTo<typename Types::ClassTypeWide, HBUINT> |
490 | | leftClassTable; /* Offset from beginning of this subtable to |
491 | | * left-hand class table. */ |
492 | | NNOffsetTo<typename Types::ClassTypeWide, HBUINT> |
493 | | rightClassTable;/* Offset from beginning of this subtable to |
494 | | * right-hand class table. */ |
495 | | NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> |
496 | | array; /* Offset from beginning of this subtable to |
497 | | * the start of the kerning array. */ |
498 | | public: |
499 | | DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 4 * sizeof (HBUINT)); |
500 | | }; |
501 | | |
502 | | template <typename KernSubTableHeader> |
503 | | struct KerxSubTableFormat4 |
504 | | { |
505 | | typedef ExtendedTypes Types; |
506 | | |
507 | | struct EntryData |
508 | | { |
509 | | HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of |
510 | | * the action to perform. */ |
511 | | public: |
512 | | DEFINE_SIZE_STATIC (2); |
513 | | }; |
514 | | |
515 | | enum Flags |
516 | | { |
517 | | Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */ |
518 | | DontAdvance = 0x4000, /* If set, don't advance to the next glyph before |
519 | | * going to the new state. */ |
520 | | Reserved = 0x3FFF, /* Not used; set to 0. */ |
521 | | }; |
522 | | |
523 | | bool is_action_initiable (const Entry<EntryData> &entry) const |
524 | 0 | { |
525 | 0 | return (entry.flags & Mark); |
526 | 0 | } |
527 | | bool is_actionable (const Entry<EntryData> &entry) const |
528 | 0 | { |
529 | 0 | return entry.data.ankrActionIndex != 0xFFFF; |
530 | 0 | } |
531 | | |
532 | | struct driver_context_t |
533 | | { |
534 | | static constexpr bool in_place = true; |
535 | | enum SubTableFlags |
536 | | { |
537 | | ActionType = 0xC0000000, /* A two-bit field containing the action type. */ |
538 | | Unused = 0x3F000000, /* Unused - must be zero. */ |
539 | | Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning |
540 | | * of the subtable to the beginning of the control |
541 | | * point table. */ |
542 | | }; |
543 | | |
544 | | driver_context_t (const KerxSubTableFormat4 *table_, |
545 | | hb_aat_apply_context_t *c_) : |
546 | 0 | c (c_), |
547 | 0 | table (table_), |
548 | 0 | action_type ((table->flags & ActionType) >> 30), |
549 | 0 | ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))), |
550 | 0 | mark_set (false), |
551 | 0 | mark (0) {} |
552 | | |
553 | | void transition (hb_buffer_t *buffer, |
554 | | StateTableDriver<Types, EntryData, Flags> *driver, |
555 | | const Entry<EntryData> &entry) |
556 | 0 | { |
557 | 0 | if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len) |
558 | 0 | { |
559 | 0 | hb_glyph_position_t &o = buffer->cur_pos(); |
560 | 0 | switch (action_type) |
561 | 0 | { |
562 | 0 | case 0: /* Control Point Actions.*/ |
563 | 0 | { |
564 | | /* Indexed into glyph outline. */ |
565 | | /* Each action (record in ankrData) contains two 16-bit fields, so we must |
566 | | double the ankrActionIndex to get the correct offset here. */ |
567 | 0 | const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; |
568 | 0 | if (!c->sanitizer.check_array (data, 2)) return; |
569 | 0 | hb_barrier (); |
570 | 0 | unsigned int markControlPoint = *data++; |
571 | 0 | unsigned int currControlPoint = *data++; |
572 | 0 | hb_position_t markX = 0; |
573 | 0 | hb_position_t markY = 0; |
574 | 0 | hb_position_t currX = 0; |
575 | 0 | hb_position_t currY = 0; |
576 | 0 | if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint, |
577 | 0 | markControlPoint, |
578 | 0 | HB_DIRECTION_LTR /*XXX*/, |
579 | 0 | &markX, &markY) || |
580 | 0 | !c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint, |
581 | 0 | currControlPoint, |
582 | 0 | HB_DIRECTION_LTR /*XXX*/, |
583 | 0 | &currX, &currY)) |
584 | 0 | return; |
585 | | |
586 | 0 | o.x_offset = markX - currX; |
587 | 0 | o.y_offset = markY - currY; |
588 | 0 | } |
589 | 0 | break; |
590 | | |
591 | 0 | case 1: /* Anchor Point Actions. */ |
592 | 0 | { |
593 | | /* Indexed into 'ankr' table. */ |
594 | | /* Each action (record in ankrData) contains two 16-bit fields, so we must |
595 | | double the ankrActionIndex to get the correct offset here. */ |
596 | 0 | const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; |
597 | 0 | if (!c->sanitizer.check_array (data, 2)) return; |
598 | 0 | hb_barrier (); |
599 | 0 | unsigned int markAnchorPoint = *data++; |
600 | 0 | unsigned int currAnchorPoint = *data++; |
601 | 0 | const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint, |
602 | 0 | markAnchorPoint, |
603 | 0 | c->sanitizer.get_num_glyphs ()); |
604 | 0 | const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint, |
605 | 0 | currAnchorPoint, |
606 | 0 | c->sanitizer.get_num_glyphs ()); |
607 | |
|
608 | 0 | o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate); |
609 | 0 | o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate); |
610 | 0 | } |
611 | 0 | break; |
612 | | |
613 | 0 | case 2: /* Control Point Coordinate Actions. */ |
614 | 0 | { |
615 | | /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex |
616 | | by 4 to get the correct offset for the given action. */ |
617 | 0 | const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4]; |
618 | 0 | if (!c->sanitizer.check_array (data, 4)) return; |
619 | 0 | hb_barrier (); |
620 | 0 | int markX = *data++; |
621 | 0 | int markY = *data++; |
622 | 0 | int currX = *data++; |
623 | 0 | int currY = *data++; |
624 | |
|
625 | 0 | o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX); |
626 | 0 | o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY); |
627 | 0 | } |
628 | 0 | break; |
629 | 0 | } |
630 | 0 | o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK; |
631 | 0 | o.attach_chain() = (int) mark - (int) buffer->idx; |
632 | 0 | buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; |
633 | 0 | } |
634 | | |
635 | 0 | if (entry.flags & Mark) |
636 | 0 | { |
637 | 0 | mark_set = true; |
638 | 0 | mark = buffer->idx; |
639 | 0 | } |
640 | 0 | } |
641 | | |
642 | | public: |
643 | | hb_aat_apply_context_t *c; |
644 | | const KerxSubTableFormat4 *table; |
645 | | private: |
646 | | unsigned int action_type; |
647 | | const HBUINT16 *ankrData; |
648 | | bool mark_set; |
649 | | unsigned int mark; |
650 | | }; |
651 | | |
652 | | bool apply (hb_aat_apply_context_t *c) const |
653 | 0 | { |
654 | 0 | TRACE_APPLY (this); |
655 | |
|
656 | 0 | driver_context_t dc (this, c); |
657 | |
|
658 | 0 | StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face); |
659 | |
|
660 | 0 | driver.drive (&dc, c); |
661 | |
|
662 | 0 | return_trace (true); |
663 | 0 | } |
664 | | |
665 | | bool sanitize (hb_sanitize_context_t *c) const |
666 | 0 | { |
667 | 0 | TRACE_SANITIZE (this); |
668 | | /* The rest of array sanitizations are done at run-time. */ |
669 | 0 | return_trace (likely (c->check_struct (this) && |
670 | 0 | machine.sanitize (c))); |
671 | 0 | } |
672 | | |
673 | | template <typename set_t> |
674 | | void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const |
675 | 0 | { |
676 | 0 | machine.collect_initial_glyphs (left_set, num_glyphs, *this); |
677 | | //machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning |
678 | 0 | } |
679 | | |
680 | | protected: |
681 | | KernSubTableHeader header; |
682 | | StateTable<Types, EntryData> machine; |
683 | | HBUINT32 flags; |
684 | | public: |
685 | | DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + (StateTable<Types, EntryData>::static_size + HBUINT32::static_size)); |
686 | | }; |
687 | | |
688 | | template <typename KernSubTableHeader> |
689 | | struct KerxSubTableFormat6 |
690 | | { |
691 | | enum Flags |
692 | | { |
693 | | ValuesAreLong = 0x00000001, |
694 | | }; |
695 | | |
696 | 0 | bool is_long () const { return flags & ValuesAreLong; } |
697 | | |
698 | | int get_kerning (hb_codepoint_t left, hb_codepoint_t right, |
699 | | hb_aat_apply_context_t *c) const |
700 | 0 | { |
701 | 0 | unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); |
702 | 0 | if (is_long ()) |
703 | 0 | { |
704 | 0 | const auto &t = u.l; |
705 | 0 | unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); |
706 | 0 | unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); |
707 | 0 | unsigned int offset = l + r; |
708 | 0 | if (unlikely (offset < l)) return 0; /* Addition overflow. */ |
709 | 0 | if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0; |
710 | 0 | const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32)); |
711 | 0 | if (unlikely (!v->sanitize (&c->sanitizer))) return 0; |
712 | 0 | hb_barrier (); |
713 | 0 | return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); |
714 | 0 | } |
715 | 0 | else |
716 | 0 | { |
717 | 0 | const auto &t = u.s; |
718 | 0 | unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs); |
719 | 0 | unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs); |
720 | 0 | unsigned int offset = l + r; |
721 | 0 | const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD)); |
722 | 0 | if (unlikely (!v->sanitize (&c->sanitizer))) return 0; |
723 | 0 | hb_barrier (); |
724 | 0 | return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c); |
725 | 0 | } |
726 | 0 | } |
727 | | |
728 | | bool apply (hb_aat_apply_context_t *c) const |
729 | 0 | { |
730 | 0 | TRACE_APPLY (this); |
731 | |
|
732 | 0 | if (!c->plan->requested_kerning) |
733 | 0 | return_trace (false); |
734 | | |
735 | 0 | if (header.coverage & header.Backwards) |
736 | 0 | return_trace (false); |
737 | | |
738 | 0 | accelerator_t accel (*this, c); |
739 | 0 | hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream); |
740 | 0 | machine.kern (c->font, c->buffer, c->plan->kern_mask); |
741 | |
|
742 | 0 | return_trace (true); |
743 | 0 | } |
744 | | |
745 | | bool sanitize (hb_sanitize_context_t *c) const |
746 | 0 | { |
747 | 0 | TRACE_SANITIZE (this); |
748 | 0 | return_trace (likely (c->check_struct (this) && |
749 | 0 | hb_barrier () && |
750 | 0 | (is_long () ? |
751 | 0 | ( |
752 | 0 | u.l.rowIndexTable.sanitize (c, this) && |
753 | 0 | u.l.columnIndexTable.sanitize (c, this) && |
754 | 0 | c->check_range (this, u.l.array) |
755 | 0 | ) : ( |
756 | 0 | u.s.rowIndexTable.sanitize (c, this) && |
757 | 0 | u.s.columnIndexTable.sanitize (c, this) && |
758 | 0 | c->check_range (this, u.s.array) |
759 | 0 | )) && |
760 | 0 | (header.tuple_count () == 0 || |
761 | 0 | c->check_range (this, vector)))); |
762 | 0 | } |
763 | | |
764 | | template <typename set_t> |
765 | | void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const |
766 | 0 | { |
767 | 0 | if (is_long ()) |
768 | 0 | { |
769 | 0 | const auto &t = u.l; |
770 | 0 | (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs); |
771 | 0 | (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs); |
772 | 0 | } |
773 | 0 | else |
774 | 0 | { |
775 | 0 | const auto &t = u.s; |
776 | 0 | (this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs); |
777 | 0 | (this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs); |
778 | 0 | } |
779 | 0 | } |
780 | | |
781 | | struct accelerator_t |
782 | | { |
783 | | const KerxSubTableFormat6 &table; |
784 | | hb_aat_apply_context_t *c; |
785 | | |
786 | | accelerator_t (const KerxSubTableFormat6 &table_, |
787 | | hb_aat_apply_context_t *c_) : |
788 | 0 | table (table_), c (c_) {} |
789 | | |
790 | | int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const |
791 | 0 | { |
792 | 0 | if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0; |
793 | 0 | return table.get_kerning (left, right, c); |
794 | 0 | } |
795 | | }; |
796 | | |
797 | | protected: |
798 | | KernSubTableHeader header; |
799 | | HBUINT32 flags; |
800 | | HBUINT16 rowCount; |
801 | | HBUINT16 columnCount; |
802 | | union U |
803 | | { |
804 | | struct Long |
805 | | { |
806 | | NNOffset32To<Lookup<HBUINT32>> rowIndexTable; |
807 | | NNOffset32To<Lookup<HBUINT32>> columnIndexTable; |
808 | | NNOffset32To<UnsizedArrayOf<FWORD32>> array; |
809 | | } l; |
810 | | struct Short |
811 | | { |
812 | | NNOffset32To<Lookup<HBUINT16>> rowIndexTable; |
813 | | NNOffset32To<Lookup<HBUINT16>> columnIndexTable; |
814 | | NNOffset32To<UnsizedArrayOf<FWORD>> array; |
815 | | } s; |
816 | | } u; |
817 | | NNOffset32To<UnsizedArrayOf<FWORD>> vector; |
818 | | public: |
819 | | DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24); |
820 | | }; |
821 | | |
822 | | |
823 | | struct KerxSubTableHeader |
824 | | { |
825 | | typedef ExtendedTypes Types; |
826 | | |
827 | 0 | unsigned tuple_count () const { return tupleCount; } |
828 | 0 | bool is_horizontal () const { return !(coverage & Vertical); } |
829 | | |
830 | | enum Coverage |
831 | | { |
832 | | Vertical = 0x80000000u, /* Set if table has vertical kerning values. */ |
833 | | CrossStream = 0x40000000u, /* Set if table has cross-stream kerning values. */ |
834 | | Variation = 0x20000000u, /* Set if table has variation kerning values. */ |
835 | | Backwards = 0x10000000u, /* If clear, process the glyphs forwards, that |
836 | | * is, from first to last in the glyph stream. |
837 | | * If we, process them from last to first. |
838 | | * This flag only applies to state-table based |
839 | | * 'kerx' subtables (types 1 and 4). */ |
840 | | Reserved = 0x0FFFFF00u, /* Reserved, set to zero. */ |
841 | | SubtableType= 0x000000FFu, /* Subtable type. */ |
842 | | }; |
843 | | |
844 | | bool sanitize (hb_sanitize_context_t *c) const |
845 | 0 | { |
846 | 0 | TRACE_SANITIZE (this); |
847 | 0 | return_trace (c->check_struct (this)); |
848 | 0 | } |
849 | | |
850 | | public: |
851 | | HBUINT32 length; |
852 | | HBUINT32 coverage; |
853 | | HBUINT32 tupleCount; |
854 | | public: |
855 | | DEFINE_SIZE_STATIC (12); |
856 | | }; |
857 | | |
858 | | struct KerxSubTable |
859 | | { |
860 | | friend struct kerx; |
861 | | |
862 | 0 | unsigned int get_size () const { return u.header.length; } |
863 | 0 | unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; } |
864 | | |
865 | | template <typename context_t, typename ...Ts> |
866 | | typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const |
867 | 0 | { |
868 | 0 | unsigned int subtable_type = get_type (); |
869 | 0 | TRACE_DISPATCH (this, subtable_type); |
870 | 0 | switch (subtable_type) { |
871 | 0 | case 0: return_trace (c->dispatch (u.format0, std::forward<Ts> (ds)...)); |
872 | 0 | case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); |
873 | 0 | case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); |
874 | 0 | case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...)); |
875 | 0 | case 6: return_trace (c->dispatch (u.format6, std::forward<Ts> (ds)...)); |
876 | 0 | default: return_trace (c->default_return_value ()); |
877 | 0 | } |
878 | 0 | } Unexecuted instantiation: hb_sanitize_context_t::return_t AAT::KerxSubTable::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const Unexecuted instantiation: AAT::hb_aat_apply_context_t::return_t AAT::KerxSubTable::dispatch<AAT::hb_aat_apply_context_t>(AAT::hb_aat_apply_context_t*) const |
879 | | |
880 | | template <typename set_t> |
881 | | void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const |
882 | 0 | { |
883 | 0 | unsigned int subtable_type = get_type (); |
884 | 0 | switch (subtable_type) { |
885 | 0 | case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return; |
886 | 0 | case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return; |
887 | 0 | case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return; |
888 | 0 | case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return; |
889 | 0 | case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return; |
890 | 0 | default: return; |
891 | 0 | } |
892 | 0 | } |
893 | | |
894 | | bool sanitize (hb_sanitize_context_t *c) const |
895 | 0 | { |
896 | 0 | TRACE_SANITIZE (this); |
897 | 0 | if (!(u.header.sanitize (c) && |
898 | 0 | hb_barrier () && |
899 | 0 | u.header.length >= u.header.static_size && |
900 | 0 | c->check_range (this, u.header.length))) |
901 | 0 | return_trace (false); |
902 | | |
903 | 0 | return_trace (dispatch (c)); |
904 | 0 | } |
905 | | |
906 | | public: |
907 | | union { |
908 | | KerxSubTableHeader header; |
909 | | KerxSubTableFormat0<KerxSubTableHeader> format0; |
910 | | KerxSubTableFormat1<KerxSubTableHeader> format1; |
911 | | KerxSubTableFormat2<KerxSubTableHeader> format2; |
912 | | KerxSubTableFormat4<KerxSubTableHeader> format4; |
913 | | KerxSubTableFormat6<KerxSubTableHeader> format6; |
914 | | } u; |
915 | | public: |
916 | | DEFINE_SIZE_MIN (12); |
917 | | }; |
918 | | |
919 | | |
920 | | /* |
921 | | * The 'kerx' Table |
922 | | */ |
923 | | |
924 | | struct kern_subtable_accelerator_data_t |
925 | | { |
926 | | hb_bit_set_t left_set; |
927 | | hb_bit_set_t right_set; |
928 | | mutable hb_aat_class_cache_t class_cache; |
929 | | }; |
930 | | |
931 | | struct kern_accelerator_data_t |
932 | | { |
933 | | hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels; |
934 | | hb_aat_scratch_t scratch; |
935 | | }; |
936 | | |
937 | | template <typename T> |
938 | | struct KerxTable |
939 | | { |
940 | | /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ |
941 | 47.5M | const T* thiz () const { return static_cast<const T *> (this); } AAT::KerxTable<AAT::kerx>::thiz() const Line | Count | Source | 941 | 120 | const T* thiz () const { return static_cast<const T *> (this); } |
AAT::KerxTable<OT::KernOT>::thiz() const Line | Count | Source | 941 | 47.5M | const T* thiz () const { return static_cast<const T *> (this); } |
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::thiz() const |
942 | | |
943 | | bool has_state_machine () const |
944 | 7.55k | { |
945 | 7.55k | typedef typename T::SubTable SubTable; |
946 | | |
947 | 7.55k | const SubTable *st = &thiz()->firstSubTable; |
948 | 7.55k | unsigned int count = thiz()->tableCount; |
949 | 15.1k | for (unsigned int i = 0; i < count; i++) |
950 | 7.55k | { |
951 | 7.55k | if (st->get_type () == 1) |
952 | 0 | return true; |
953 | | |
954 | | // TODO: What about format 4? What's this API used for anyway? |
955 | | |
956 | 7.55k | st = &StructAfter<SubTable> (*st); |
957 | 7.55k | } |
958 | 7.55k | return false; |
959 | 7.55k | } AAT::KerxTable<OT::KernOT>::has_state_machine() const Line | Count | Source | 944 | 7.55k | { | 945 | 7.55k | typedef typename T::SubTable SubTable; | 946 | | | 947 | 7.55k | const SubTable *st = &thiz()->firstSubTable; | 948 | 7.55k | unsigned int count = thiz()->tableCount; | 949 | 15.1k | for (unsigned int i = 0; i < count; i++) | 950 | 7.55k | { | 951 | 7.55k | if (st->get_type () == 1) | 952 | 0 | return true; | 953 | | | 954 | | // TODO: What about format 4? What's this API used for anyway? | 955 | | | 956 | 7.55k | st = &StructAfter<SubTable> (*st); | 957 | 7.55k | } | 958 | 7.55k | return false; | 959 | 7.55k | } |
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::has_state_machine() const |
960 | | |
961 | | bool has_cross_stream () const |
962 | 0 | { |
963 | 0 | typedef typename T::SubTable SubTable; |
964 | |
|
965 | 0 | const SubTable *st = &thiz()->firstSubTable; |
966 | 0 | unsigned int count = thiz()->tableCount; |
967 | 0 | for (unsigned int i = 0; i < count; i++) |
968 | 0 | { |
969 | 0 | if (st->u.header.coverage & st->u.header.CrossStream) |
970 | 0 | return true; |
971 | 0 | st = &StructAfter<SubTable> (*st); |
972 | 0 | } |
973 | 0 | return false; |
974 | 0 | } Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::has_cross_stream() const Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::has_cross_stream() const |
975 | | |
976 | | int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const |
977 | 0 | { |
978 | 0 | typedef typename T::SubTable SubTable; |
979 | 0 |
|
980 | 0 | int v = 0; |
981 | 0 | const SubTable *st = &thiz()->firstSubTable; |
982 | 0 | unsigned int count = thiz()->tableCount; |
983 | 0 | for (unsigned int i = 0; i < count; i++) |
984 | 0 | { |
985 | 0 | if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) || |
986 | 0 | !st->u.header.is_horizontal ()) |
987 | 0 | continue; |
988 | 0 | v += st->get_kerning (left, right); |
989 | 0 | st = &StructAfter<SubTable> (*st); |
990 | 0 | } |
991 | 0 | return v; |
992 | 0 | } Unexecuted instantiation: AAT::KerxTable<OT::KernOT>::get_h_kerning(unsigned int, unsigned int) const Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::get_h_kerning(unsigned int, unsigned int) const |
993 | | |
994 | | bool apply (AAT::hb_aat_apply_context_t *c, |
995 | | const kern_accelerator_data_t &accel_data) const |
996 | 23.7M | { |
997 | 23.7M | c->buffer->unsafe_to_concat (); |
998 | | |
999 | 23.7M | c->setup_buffer_glyph_set (); |
1000 | | |
1001 | 23.7M | typedef typename T::SubTable SubTable; |
1002 | | |
1003 | 23.7M | bool ret = false; |
1004 | 23.7M | bool seenCrossStream = false; |
1005 | 23.7M | c->set_lookup_index (0); |
1006 | 23.7M | const SubTable *st = &thiz()->firstSubTable; |
1007 | 23.7M | unsigned int count = thiz()->tableCount; |
1008 | 47.5M | for (unsigned int i = 0; i < count; i++) |
1009 | 23.7M | { |
1010 | 23.7M | bool reverse; |
1011 | | |
1012 | 23.7M | auto &subtable_accel = accel_data.subtable_accels[i]; |
1013 | | |
1014 | 23.7M | if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation)) |
1015 | 0 | goto skip; |
1016 | | |
1017 | 23.7M | if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) |
1018 | 1.74M | goto skip; |
1019 | | |
1020 | 22.0M | c->left_set = &subtable_accel.left_set; |
1021 | 22.0M | c->right_set = &subtable_accel.right_set; |
1022 | 22.0M | c->machine_glyph_set = &subtable_accel.left_set; |
1023 | 22.0M | c->machine_class_cache = &subtable_accel.class_cache; |
1024 | | |
1025 | 22.0M | if (!c->buffer_intersects_machine ()) |
1026 | 19.5M | { |
1027 | 19.5M | (void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index); |
1028 | 19.5M | goto skip; |
1029 | 19.5M | } |
1030 | | |
1031 | 2.46M | reverse = bool (st->u.header.coverage & st->u.header.Backwards) != |
1032 | 2.46M | HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); |
1033 | | |
1034 | 2.46M | if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index)) |
1035 | 0 | goto skip; |
1036 | | |
1037 | 2.46M | if (!seenCrossStream && |
1038 | 2.46M | (st->u.header.coverage & st->u.header.CrossStream)) |
1039 | 0 | { |
1040 | | /* Attach all glyphs into a chain. */ |
1041 | 0 | seenCrossStream = true; |
1042 | 0 | hb_glyph_position_t *pos = c->buffer->pos; |
1043 | 0 | unsigned int count = c->buffer->len; |
1044 | 0 | for (unsigned int i = 0; i < count; i++) |
1045 | 0 | { |
1046 | 0 | pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE; |
1047 | 0 | pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1; |
1048 | | /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT, |
1049 | | * since there needs to be a non-zero attachment for post-positioning to |
1050 | | * be needed. */ |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | 2.46M | if (reverse) |
1055 | 24.2k | c->buffer->reverse (); |
1056 | | |
1057 | 2.46M | { |
1058 | | /* See comment in sanitize() for conditional here. */ |
1059 | 2.46M | hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr); |
1060 | 2.46M | ret |= st->dispatch (c); |
1061 | 2.46M | } |
1062 | | |
1063 | 2.46M | if (reverse) |
1064 | 24.2k | c->buffer->reverse (); |
1065 | | |
1066 | 2.46M | (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index); |
1067 | | |
1068 | 23.7M | skip: |
1069 | 23.7M | st = &StructAfter<SubTable> (*st); |
1070 | 23.7M | c->set_lookup_index (c->lookup_index + 1); |
1071 | 23.7M | } |
1072 | | |
1073 | 23.7M | return ret; |
1074 | 23.7M | } Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const AAT::KerxTable<OT::KernOT>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const Line | Count | Source | 996 | 23.7M | { | 997 | 23.7M | c->buffer->unsafe_to_concat (); | 998 | | | 999 | 23.7M | c->setup_buffer_glyph_set (); | 1000 | | | 1001 | 23.7M | typedef typename T::SubTable SubTable; | 1002 | | | 1003 | 23.7M | bool ret = false; | 1004 | 23.7M | bool seenCrossStream = false; | 1005 | 23.7M | c->set_lookup_index (0); | 1006 | 23.7M | const SubTable *st = &thiz()->firstSubTable; | 1007 | 23.7M | unsigned int count = thiz()->tableCount; | 1008 | 47.5M | for (unsigned int i = 0; i < count; i++) | 1009 | 23.7M | { | 1010 | 23.7M | bool reverse; | 1011 | | | 1012 | 23.7M | auto &subtable_accel = accel_data.subtable_accels[i]; | 1013 | | | 1014 | 23.7M | if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation)) | 1015 | 0 | goto skip; | 1016 | | | 1017 | 23.7M | if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) | 1018 | 1.74M | goto skip; | 1019 | | | 1020 | 22.0M | c->left_set = &subtable_accel.left_set; | 1021 | 22.0M | c->right_set = &subtable_accel.right_set; | 1022 | 22.0M | c->machine_glyph_set = &subtable_accel.left_set; | 1023 | 22.0M | c->machine_class_cache = &subtable_accel.class_cache; | 1024 | | | 1025 | 22.0M | if (!c->buffer_intersects_machine ()) | 1026 | 19.5M | { | 1027 | 19.5M | (void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index); | 1028 | 19.5M | goto skip; | 1029 | 19.5M | } | 1030 | | | 1031 | 2.46M | reverse = bool (st->u.header.coverage & st->u.header.Backwards) != | 1032 | 2.46M | HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); | 1033 | | | 1034 | 2.46M | if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index)) | 1035 | 0 | goto skip; | 1036 | | | 1037 | 2.46M | if (!seenCrossStream && | 1038 | 2.46M | (st->u.header.coverage & st->u.header.CrossStream)) | 1039 | 0 | { | 1040 | | /* Attach all glyphs into a chain. */ | 1041 | 0 | seenCrossStream = true; | 1042 | 0 | hb_glyph_position_t *pos = c->buffer->pos; | 1043 | 0 | unsigned int count = c->buffer->len; | 1044 | 0 | for (unsigned int i = 0; i < count; i++) | 1045 | 0 | { | 1046 | 0 | pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE; | 1047 | 0 | pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1; | 1048 | | /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT, | 1049 | | * since there needs to be a non-zero attachment for post-positioning to | 1050 | | * be needed. */ | 1051 | 0 | } | 1052 | 0 | } | 1053 | | | 1054 | 2.46M | if (reverse) | 1055 | 24.2k | c->buffer->reverse (); | 1056 | | | 1057 | 2.46M | { | 1058 | | /* See comment in sanitize() for conditional here. */ | 1059 | 2.46M | hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr); | 1060 | 2.46M | ret |= st->dispatch (c); | 1061 | 2.46M | } | 1062 | | | 1063 | 2.46M | if (reverse) | 1064 | 24.2k | c->buffer->reverse (); | 1065 | | | 1066 | 2.46M | (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index); | 1067 | | | 1068 | 23.7M | skip: | 1069 | 23.7M | st = &StructAfter<SubTable> (*st); | 1070 | 23.7M | c->set_lookup_index (c->lookup_index + 1); | 1071 | 23.7M | } | 1072 | | | 1073 | 23.7M | return ret; | 1074 | 23.7M | } |
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::apply(AAT::hb_aat_apply_context_t*, AAT::kern_accelerator_data_t const&) const |
1075 | | |
1076 | | bool sanitize (hb_sanitize_context_t *c) const |
1077 | 60 | { |
1078 | 60 | TRACE_SANITIZE (this); |
1079 | 60 | if (unlikely (!(thiz()->version.sanitize (c) && |
1080 | 60 | hb_barrier () && |
1081 | 60 | (unsigned) thiz()->version >= (unsigned) T::minVersion && |
1082 | 60 | thiz()->tableCount.sanitize (c)))) |
1083 | 0 | return_trace (false); |
1084 | | |
1085 | 60 | typedef typename T::SubTable SubTable; |
1086 | | |
1087 | 60 | const SubTable *st = &thiz()->firstSubTable; |
1088 | 60 | unsigned int count = thiz()->tableCount; |
1089 | 120 | for (unsigned int i = 0; i < count; i++) |
1090 | 60 | { |
1091 | 60 | if (unlikely (!st->u.header.sanitize (c))) |
1092 | 0 | return_trace (false); |
1093 | 60 | hb_barrier (); |
1094 | | /* OpenType kern table has 2-byte subtable lengths. That's limiting. |
1095 | | * MS implementation also only supports one subtable, of format 0, |
1096 | | * anyway. Certain versions of some fonts, like Calibry, contain |
1097 | | * kern subtable that exceeds 64kb. Looks like, the subtable length |
1098 | | * is simply ignored. Which makes sense. It's only needed if you |
1099 | | * have multiple subtables. To handle such fonts, we just ignore |
1100 | | * the length for the last subtable. */ |
1101 | 60 | hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr); |
1102 | | |
1103 | 60 | if (unlikely (!st->sanitize (c))) |
1104 | 0 | return_trace (false); |
1105 | | |
1106 | 60 | st = &StructAfter<SubTable> (*st); |
1107 | 60 | } |
1108 | | |
1109 | 60 | unsigned majorVersion = thiz()->version; |
1110 | 60 | if (sizeof (thiz()->version) == 4) |
1111 | 0 | majorVersion = majorVersion >> 16; |
1112 | 60 | if (majorVersion >= 3) |
1113 | 0 | { |
1114 | 0 | const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st; |
1115 | 0 | if (!coverage->sanitize (c, count)) |
1116 | 0 | return_trace (false); |
1117 | 0 | } |
1118 | | |
1119 | 60 | return_trace (true); |
1120 | 60 | } Unexecuted instantiation: AAT::KerxTable<AAT::kerx>::sanitize(hb_sanitize_context_t*) const AAT::KerxTable<OT::KernOT>::sanitize(hb_sanitize_context_t*) const Line | Count | Source | 1077 | 60 | { | 1078 | 60 | TRACE_SANITIZE (this); | 1079 | 60 | if (unlikely (!(thiz()->version.sanitize (c) && | 1080 | 60 | hb_barrier () && | 1081 | 60 | (unsigned) thiz()->version >= (unsigned) T::minVersion && | 1082 | 60 | thiz()->tableCount.sanitize (c)))) | 1083 | 0 | return_trace (false); | 1084 | | | 1085 | 60 | typedef typename T::SubTable SubTable; | 1086 | | | 1087 | 60 | const SubTable *st = &thiz()->firstSubTable; | 1088 | 60 | unsigned int count = thiz()->tableCount; | 1089 | 120 | for (unsigned int i = 0; i < count; i++) | 1090 | 60 | { | 1091 | 60 | if (unlikely (!st->u.header.sanitize (c))) | 1092 | 0 | return_trace (false); | 1093 | 60 | hb_barrier (); | 1094 | | /* OpenType kern table has 2-byte subtable lengths. That's limiting. | 1095 | | * MS implementation also only supports one subtable, of format 0, | 1096 | | * anyway. Certain versions of some fonts, like Calibry, contain | 1097 | | * kern subtable that exceeds 64kb. Looks like, the subtable length | 1098 | | * is simply ignored. Which makes sense. It's only needed if you | 1099 | | * have multiple subtables. To handle such fonts, we just ignore | 1100 | | * the length for the last subtable. */ | 1101 | 60 | hb_sanitize_with_object_t with (c, i < count - 1 ? st : (const SubTable *) nullptr); | 1102 | | | 1103 | 60 | if (unlikely (!st->sanitize (c))) | 1104 | 0 | return_trace (false); | 1105 | | | 1106 | 60 | st = &StructAfter<SubTable> (*st); | 1107 | 60 | } | 1108 | | | 1109 | 60 | unsigned majorVersion = thiz()->version; | 1110 | 60 | if (sizeof (thiz()->version) == 4) | 1111 | 0 | majorVersion = majorVersion >> 16; | 1112 | 60 | if (majorVersion >= 3) | 1113 | 0 | { | 1114 | 0 | const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) st; | 1115 | 0 | if (!coverage->sanitize (c, count)) | 1116 | 0 | return_trace (false); | 1117 | 0 | } | 1118 | | | 1119 | 60 | return_trace (true); | 1120 | 60 | } |
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::sanitize(hb_sanitize_context_t*) const |
1121 | | |
1122 | | kern_accelerator_data_t create_accelerator_data (unsigned num_glyphs) const |
1123 | 120 | { |
1124 | 120 | kern_accelerator_data_t accel_data; |
1125 | | |
1126 | 120 | typedef typename T::SubTable SubTable; |
1127 | | |
1128 | 120 | const SubTable *st = &thiz()->firstSubTable; |
1129 | 120 | unsigned int count = thiz()->tableCount; |
1130 | 180 | for (unsigned int i = 0; i < count; i++) |
1131 | 60 | { |
1132 | 60 | auto &subtable_accel = *accel_data.subtable_accels.push (); |
1133 | 60 | if (unlikely (accel_data.subtable_accels.in_error ())) |
1134 | 0 | return accel_data; |
1135 | | |
1136 | 60 | st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs); |
1137 | 60 | subtable_accel.class_cache.clear (); |
1138 | | |
1139 | 60 | st = &StructAfter<SubTable> (*st); |
1140 | 60 | } |
1141 | | |
1142 | 120 | return accel_data; |
1143 | 120 | } AAT::KerxTable<AAT::kerx>::create_accelerator_data(unsigned int) const Line | Count | Source | 1123 | 60 | { | 1124 | 60 | kern_accelerator_data_t accel_data; | 1125 | | | 1126 | 60 | typedef typename T::SubTable SubTable; | 1127 | | | 1128 | 60 | const SubTable *st = &thiz()->firstSubTable; | 1129 | 60 | unsigned int count = thiz()->tableCount; | 1130 | 60 | for (unsigned int i = 0; i < count; i++) | 1131 | 0 | { | 1132 | 0 | auto &subtable_accel = *accel_data.subtable_accels.push (); | 1133 | 0 | if (unlikely (accel_data.subtable_accels.in_error ())) | 1134 | 0 | return accel_data; | 1135 | | | 1136 | 0 | st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs); | 1137 | 0 | subtable_accel.class_cache.clear (); | 1138 | |
| 1139 | 0 | st = &StructAfter<SubTable> (*st); | 1140 | 0 | } | 1141 | | | 1142 | 60 | return accel_data; | 1143 | 60 | } |
AAT::KerxTable<OT::KernOT>::create_accelerator_data(unsigned int) const Line | Count | Source | 1123 | 60 | { | 1124 | 60 | kern_accelerator_data_t accel_data; | 1125 | | | 1126 | 60 | typedef typename T::SubTable SubTable; | 1127 | | | 1128 | 60 | const SubTable *st = &thiz()->firstSubTable; | 1129 | 60 | unsigned int count = thiz()->tableCount; | 1130 | 120 | for (unsigned int i = 0; i < count; i++) | 1131 | 60 | { | 1132 | 60 | auto &subtable_accel = *accel_data.subtable_accels.push (); | 1133 | 60 | if (unlikely (accel_data.subtable_accels.in_error ())) | 1134 | 0 | return accel_data; | 1135 | | | 1136 | 60 | st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs); | 1137 | 60 | subtable_accel.class_cache.clear (); | 1138 | | | 1139 | 60 | st = &StructAfter<SubTable> (*st); | 1140 | 60 | } | 1141 | | | 1142 | 60 | return accel_data; | 1143 | 60 | } |
Unexecuted instantiation: AAT::KerxTable<OT::KernAAT>::create_accelerator_data(unsigned int) const |
1144 | | |
1145 | | struct accelerator_t |
1146 | | { |
1147 | | accelerator_t (hb_face_t *face) |
1148 | 60 | { |
1149 | 60 | hb_sanitize_context_t sc; |
1150 | 60 | this->table = sc.reference_table<T> (face); |
1151 | 60 | this->accel_data = this->table->create_accelerator_data (face->get_num_glyphs ()); |
1152 | 60 | } |
1153 | | ~accelerator_t () |
1154 | 0 | { |
1155 | 0 | this->table.destroy (); |
1156 | 0 | } |
1157 | | |
1158 | 0 | hb_blob_t *get_blob () const { return table.get_blob (); } |
1159 | | |
1160 | | bool apply (AAT::hb_aat_apply_context_t *c) const |
1161 | 0 | { |
1162 | 0 | return table->apply (c, accel_data); |
1163 | 0 | } |
1164 | | |
1165 | | hb_blob_ptr_t<T> table; |
1166 | | kern_accelerator_data_t accel_data; |
1167 | | hb_aat_scratch_t scratch; |
1168 | | }; |
1169 | | }; |
1170 | | |
1171 | | struct kerx : KerxTable<kerx> |
1172 | | { |
1173 | | friend struct KerxTable<kerx>; |
1174 | | |
1175 | | static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx; |
1176 | | static constexpr unsigned minVersion = 2u; |
1177 | | |
1178 | | typedef KerxSubTableHeader SubTableHeader; |
1179 | | typedef SubTableHeader::Types Types; |
1180 | | typedef KerxSubTable SubTable; |
1181 | | |
1182 | 8.85k | bool has_data () const { return version; } |
1183 | | |
1184 | | protected: |
1185 | | HBUINT16 version; /* The version number of the extended kerning table |
1186 | | * (currently 2, 3, or 4). */ |
1187 | | HBUINT16 unused; /* Set to 0. */ |
1188 | | HBUINT32 tableCount; /* The number of subtables included in the extended kerning |
1189 | | * table. */ |
1190 | | SubTable firstSubTable; /* Subtables. */ |
1191 | | /*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ |
1192 | | |
1193 | | public: |
1194 | | DEFINE_SIZE_MIN (8); |
1195 | | }; |
1196 | | |
1197 | | struct kerx_accelerator_t : kerx::accelerator_t { |
1198 | 60 | kerx_accelerator_t (hb_face_t *face) : kerx::accelerator_t (face) {} |
1199 | | }; |
1200 | | |
1201 | | } /* namespace AAT */ |
1202 | | |
1203 | | #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */ |