Line data Source code
1 : /*
2 : * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 : * Copyright © 2010,2012,2013 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 : * Red Hat Author(s): Behdad Esfahbod
26 : * Google Author(s): Behdad Esfahbod
27 : */
28 :
29 : #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
30 : #define HB_OT_LAYOUT_GSUB_TABLE_HH
31 :
32 : #include "hb-ot-layout-gsubgpos-private.hh"
33 :
34 :
35 : namespace OT {
36 :
37 :
38 : struct SingleSubstFormat1
39 : {
40 0 : inline void closure (hb_closure_context_t *c) const
41 : {
42 0 : TRACE_CLOSURE (this);
43 0 : Coverage::Iter iter;
44 0 : for (iter.init (this+coverage); iter.more (); iter.next ())
45 : {
46 : /* TODO Switch to range-based API to work around malicious fonts.
47 : * https://github.com/behdad/harfbuzz/issues/363 */
48 0 : hb_codepoint_t glyph_id = iter.get_glyph ();
49 0 : if (c->glyphs->has (glyph_id))
50 0 : c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
51 : }
52 0 : }
53 :
54 14 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
55 : {
56 14 : TRACE_COLLECT_GLYPHS (this);
57 14 : Coverage::Iter iter;
58 82 : for (iter.init (this+coverage); iter.more (); iter.next ())
59 : {
60 : /* TODO Switch to range-based API to work around malicious fonts.
61 : * https://github.com/behdad/harfbuzz/issues/363 */
62 68 : hb_codepoint_t glyph_id = iter.get_glyph ();
63 68 : c->input->add (glyph_id);
64 68 : c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
65 : }
66 14 : }
67 :
68 20 : inline const Coverage &get_coverage (void) const
69 : {
70 20 : return this+coverage;
71 : }
72 :
73 0 : inline bool would_apply (hb_would_apply_context_t *c) const
74 : {
75 0 : TRACE_WOULD_APPLY (this);
76 0 : return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
77 : }
78 :
79 0 : inline bool apply (hb_apply_context_t *c) const
80 : {
81 0 : TRACE_APPLY (this);
82 0 : hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
83 0 : unsigned int index = (this+coverage).get_coverage (glyph_id);
84 0 : if (likely (index == NOT_COVERED)) return_trace (false);
85 :
86 : /* According to the Adobe Annotated OpenType Suite, result is always
87 : * limited to 16bit. */
88 0 : glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
89 0 : c->replace_glyph (glyph_id);
90 :
91 0 : return_trace (true);
92 : }
93 :
94 0 : inline bool serialize (hb_serialize_context_t *c,
95 : Supplier<GlyphID> &glyphs,
96 : unsigned int num_glyphs,
97 : int delta)
98 : {
99 0 : TRACE_SERIALIZE (this);
100 0 : if (unlikely (!c->extend_min (*this))) return_trace (false);
101 0 : if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
102 0 : deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
103 0 : return_trace (true);
104 : }
105 :
106 20 : inline bool sanitize (hb_sanitize_context_t *c) const
107 : {
108 20 : TRACE_SANITIZE (this);
109 20 : return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
110 : }
111 :
112 : protected:
113 : USHORT format; /* Format identifier--format = 1 */
114 : OffsetTo<Coverage>
115 : coverage; /* Offset to Coverage table--from
116 : * beginning of Substitution table */
117 : SHORT deltaGlyphID; /* Add to original GlyphID to get
118 : * substitute GlyphID */
119 : public:
120 : DEFINE_SIZE_STATIC (6);
121 : };
122 :
123 : struct SingleSubstFormat2
124 : {
125 0 : inline void closure (hb_closure_context_t *c) const
126 : {
127 0 : TRACE_CLOSURE (this);
128 0 : Coverage::Iter iter;
129 0 : unsigned int count = substitute.len;
130 0 : for (iter.init (this+coverage); iter.more (); iter.next ())
131 : {
132 0 : if (unlikely (iter.get_coverage () >= count))
133 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
134 0 : if (c->glyphs->has (iter.get_glyph ()))
135 0 : c->glyphs->add (substitute[iter.get_coverage ()]);
136 : }
137 0 : }
138 :
139 36 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
140 : {
141 36 : TRACE_COLLECT_GLYPHS (this);
142 36 : Coverage::Iter iter;
143 36 : unsigned int count = substitute.len;
144 1448 : for (iter.init (this+coverage); iter.more (); iter.next ())
145 : {
146 1412 : if (unlikely (iter.get_coverage () >= count))
147 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
148 1412 : c->input->add (iter.get_glyph ());
149 1412 : c->output->add (substitute[iter.get_coverage ()]);
150 : }
151 36 : }
152 :
153 34 : inline const Coverage &get_coverage (void) const
154 : {
155 34 : return this+coverage;
156 : }
157 :
158 0 : inline bool would_apply (hb_would_apply_context_t *c) const
159 : {
160 0 : TRACE_WOULD_APPLY (this);
161 0 : return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
162 : }
163 :
164 0 : inline bool apply (hb_apply_context_t *c) const
165 : {
166 0 : TRACE_APPLY (this);
167 0 : hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
168 0 : unsigned int index = (this+coverage).get_coverage (glyph_id);
169 0 : if (likely (index == NOT_COVERED)) return_trace (false);
170 :
171 0 : if (unlikely (index >= substitute.len)) return_trace (false);
172 :
173 0 : glyph_id = substitute[index];
174 0 : c->replace_glyph (glyph_id);
175 :
176 0 : return_trace (true);
177 : }
178 :
179 0 : inline bool serialize (hb_serialize_context_t *c,
180 : Supplier<GlyphID> &glyphs,
181 : Supplier<GlyphID> &substitutes,
182 : unsigned int num_glyphs)
183 : {
184 0 : TRACE_SERIALIZE (this);
185 0 : if (unlikely (!c->extend_min (*this))) return_trace (false);
186 0 : if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
187 0 : if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
188 0 : return_trace (true);
189 : }
190 :
191 34 : inline bool sanitize (hb_sanitize_context_t *c) const
192 : {
193 34 : TRACE_SANITIZE (this);
194 34 : return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
195 : }
196 :
197 : protected:
198 : USHORT format; /* Format identifier--format = 2 */
199 : OffsetTo<Coverage>
200 : coverage; /* Offset to Coverage table--from
201 : * beginning of Substitution table */
202 : ArrayOf<GlyphID>
203 : substitute; /* Array of substitute
204 : * GlyphIDs--ordered by Coverage Index */
205 : public:
206 : DEFINE_SIZE_ARRAY (6, substitute);
207 : };
208 :
209 : struct SingleSubst
210 : {
211 0 : inline bool serialize (hb_serialize_context_t *c,
212 : Supplier<GlyphID> &glyphs,
213 : Supplier<GlyphID> &substitutes,
214 : unsigned int num_glyphs)
215 : {
216 0 : TRACE_SERIALIZE (this);
217 0 : if (unlikely (!c->extend_min (u.format))) return_trace (false);
218 0 : unsigned int format = 2;
219 0 : int delta = 0;
220 0 : if (num_glyphs) {
221 0 : format = 1;
222 : /* TODO(serialize) check for wrap-around */
223 0 : delta = substitutes[0] - glyphs[0];
224 0 : for (unsigned int i = 1; i < num_glyphs; i++)
225 0 : if (delta != substitutes[i] - glyphs[i]) {
226 0 : format = 2;
227 0 : break;
228 : }
229 : }
230 0 : u.format.set (format);
231 0 : switch (u.format) {
232 0 : case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
233 0 : case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
234 0 : default:return_trace (false);
235 : }
236 : }
237 :
238 : template <typename context_t>
239 274 : inline typename context_t::return_t dispatch (context_t *c) const
240 : {
241 274 : TRACE_DISPATCH (this, u.format);
242 274 : if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
243 274 : switch (u.format) {
244 54 : case 1: return_trace (c->dispatch (u.format1));
245 220 : case 2: return_trace (c->dispatch (u.format2));
246 0 : default:return_trace (c->default_return_value ());
247 : }
248 : }
249 :
250 : protected:
251 : union {
252 : USHORT format; /* Format identifier */
253 : SingleSubstFormat1 format1;
254 : SingleSubstFormat2 format2;
255 : } u;
256 : };
257 :
258 :
259 : struct Sequence
260 : {
261 0 : inline void closure (hb_closure_context_t *c) const
262 : {
263 0 : TRACE_CLOSURE (this);
264 0 : unsigned int count = substitute.len;
265 0 : for (unsigned int i = 0; i < count; i++)
266 0 : c->glyphs->add (substitute[i]);
267 0 : }
268 :
269 0 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
270 : {
271 0 : TRACE_COLLECT_GLYPHS (this);
272 0 : unsigned int count = substitute.len;
273 0 : for (unsigned int i = 0; i < count; i++)
274 0 : c->output->add (substitute[i]);
275 0 : }
276 :
277 0 : inline bool apply (hb_apply_context_t *c) const
278 : {
279 0 : TRACE_APPLY (this);
280 0 : unsigned int count = substitute.len;
281 :
282 : /* Special-case to make it in-place and not consider this
283 : * as a "multiplied" substitution. */
284 0 : if (unlikely (count == 1))
285 : {
286 0 : c->replace_glyph (substitute.array[0]);
287 0 : return_trace (true);
288 : }
289 : /* Spec disallows this, but Uniscribe allows it.
290 : * https://github.com/behdad/harfbuzz/issues/253 */
291 0 : else if (unlikely (count == 0))
292 : {
293 0 : c->buffer->delete_glyph ();
294 0 : return_trace (true);
295 : }
296 :
297 0 : unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
298 0 : HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
299 :
300 0 : for (unsigned int i = 0; i < count; i++) {
301 0 : _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
302 0 : c->output_glyph_for_component (substitute.array[i], klass);
303 : }
304 0 : c->buffer->skip_glyph ();
305 :
306 0 : return_trace (true);
307 : }
308 :
309 : inline bool serialize (hb_serialize_context_t *c,
310 : Supplier<GlyphID> &glyphs,
311 : unsigned int num_glyphs)
312 : {
313 : TRACE_SERIALIZE (this);
314 : if (unlikely (!c->extend_min (*this))) return_trace (false);
315 : if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
316 : return_trace (true);
317 : }
318 :
319 0 : inline bool sanitize (hb_sanitize_context_t *c) const
320 : {
321 0 : TRACE_SANITIZE (this);
322 0 : return_trace (substitute.sanitize (c));
323 : }
324 :
325 : protected:
326 : ArrayOf<GlyphID>
327 : substitute; /* String of GlyphIDs to substitute */
328 : public:
329 : DEFINE_SIZE_ARRAY (2, substitute);
330 : };
331 :
332 : struct MultipleSubstFormat1
333 : {
334 0 : inline void closure (hb_closure_context_t *c) const
335 : {
336 0 : TRACE_CLOSURE (this);
337 0 : Coverage::Iter iter;
338 0 : unsigned int count = sequence.len;
339 0 : for (iter.init (this+coverage); iter.more (); iter.next ())
340 : {
341 0 : if (unlikely (iter.get_coverage () >= count))
342 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
343 0 : if (c->glyphs->has (iter.get_glyph ()))
344 0 : (this+sequence[iter.get_coverage ()]).closure (c);
345 : }
346 0 : }
347 :
348 0 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
349 : {
350 0 : TRACE_COLLECT_GLYPHS (this);
351 0 : (this+coverage).add_coverage (c->input);
352 0 : unsigned int count = sequence.len;
353 0 : for (unsigned int i = 0; i < count; i++)
354 0 : (this+sequence[i]).collect_glyphs (c);
355 0 : }
356 :
357 0 : inline const Coverage &get_coverage (void) const
358 : {
359 0 : return this+coverage;
360 : }
361 :
362 0 : inline bool would_apply (hb_would_apply_context_t *c) const
363 : {
364 0 : TRACE_WOULD_APPLY (this);
365 0 : return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
366 : }
367 :
368 0 : inline bool apply (hb_apply_context_t *c) const
369 : {
370 0 : TRACE_APPLY (this);
371 :
372 0 : unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
373 0 : if (likely (index == NOT_COVERED)) return_trace (false);
374 :
375 0 : return_trace ((this+sequence[index]).apply (c));
376 : }
377 :
378 : inline bool serialize (hb_serialize_context_t *c,
379 : Supplier<GlyphID> &glyphs,
380 : Supplier<unsigned int> &substitute_len_list,
381 : unsigned int num_glyphs,
382 : Supplier<GlyphID> &substitute_glyphs_list)
383 : {
384 : TRACE_SERIALIZE (this);
385 : if (unlikely (!c->extend_min (*this))) return_trace (false);
386 : if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
387 : for (unsigned int i = 0; i < num_glyphs; i++)
388 : if (unlikely (!sequence[i].serialize (c, this).serialize (c,
389 : substitute_glyphs_list,
390 : substitute_len_list[i]))) return_trace (false);
391 : substitute_len_list.advance (num_glyphs);
392 : if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
393 : return_trace (true);
394 : }
395 :
396 0 : inline bool sanitize (hb_sanitize_context_t *c) const
397 : {
398 0 : TRACE_SANITIZE (this);
399 0 : return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
400 : }
401 :
402 : protected:
403 : USHORT format; /* Format identifier--format = 1 */
404 : OffsetTo<Coverage>
405 : coverage; /* Offset to Coverage table--from
406 : * beginning of Substitution table */
407 : OffsetArrayOf<Sequence>
408 : sequence; /* Array of Sequence tables
409 : * ordered by Coverage Index */
410 : public:
411 : DEFINE_SIZE_ARRAY (6, sequence);
412 : };
413 :
414 : struct MultipleSubst
415 : {
416 : inline bool serialize (hb_serialize_context_t *c,
417 : Supplier<GlyphID> &glyphs,
418 : Supplier<unsigned int> &substitute_len_list,
419 : unsigned int num_glyphs,
420 : Supplier<GlyphID> &substitute_glyphs_list)
421 : {
422 : TRACE_SERIALIZE (this);
423 : if (unlikely (!c->extend_min (u.format))) return_trace (false);
424 : unsigned int format = 1;
425 : u.format.set (format);
426 : switch (u.format) {
427 : case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
428 : default:return_trace (false);
429 : }
430 : }
431 :
432 : template <typename context_t>
433 0 : inline typename context_t::return_t dispatch (context_t *c) const
434 : {
435 0 : TRACE_DISPATCH (this, u.format);
436 0 : if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
437 0 : switch (u.format) {
438 0 : case 1: return_trace (c->dispatch (u.format1));
439 0 : default:return_trace (c->default_return_value ());
440 : }
441 : }
442 :
443 : protected:
444 : union {
445 : USHORT format; /* Format identifier */
446 : MultipleSubstFormat1 format1;
447 : } u;
448 : };
449 :
450 :
451 : typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
452 : * arbitrary order */
453 :
454 : struct AlternateSubstFormat1
455 : {
456 0 : inline void closure (hb_closure_context_t *c) const
457 : {
458 0 : TRACE_CLOSURE (this);
459 0 : Coverage::Iter iter;
460 0 : unsigned int count = alternateSet.len;
461 0 : for (iter.init (this+coverage); iter.more (); iter.next ())
462 : {
463 0 : if (unlikely (iter.get_coverage () >= count))
464 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
465 0 : if (c->glyphs->has (iter.get_glyph ())) {
466 0 : const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
467 0 : unsigned int count = alt_set.len;
468 0 : for (unsigned int i = 0; i < count; i++)
469 0 : c->glyphs->add (alt_set[i]);
470 : }
471 : }
472 0 : }
473 :
474 9 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
475 : {
476 9 : TRACE_COLLECT_GLYPHS (this);
477 9 : Coverage::Iter iter;
478 9 : unsigned int count = alternateSet.len;
479 63 : for (iter.init (this+coverage); iter.more (); iter.next ())
480 : {
481 54 : if (unlikely (iter.get_coverage () >= count))
482 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
483 54 : c->input->add (iter.get_glyph ());
484 54 : const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
485 54 : unsigned int count = alt_set.len;
486 118 : for (unsigned int i = 0; i < count; i++)
487 64 : c->output->add (alt_set[i]);
488 : }
489 9 : }
490 :
491 6 : inline const Coverage &get_coverage (void) const
492 : {
493 6 : return this+coverage;
494 : }
495 :
496 0 : inline bool would_apply (hb_would_apply_context_t *c) const
497 : {
498 0 : TRACE_WOULD_APPLY (this);
499 0 : return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
500 : }
501 :
502 0 : inline bool apply (hb_apply_context_t *c) const
503 : {
504 0 : TRACE_APPLY (this);
505 0 : hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
506 :
507 0 : unsigned int index = (this+coverage).get_coverage (glyph_id);
508 0 : if (likely (index == NOT_COVERED)) return_trace (false);
509 :
510 0 : const AlternateSet &alt_set = this+alternateSet[index];
511 :
512 0 : if (unlikely (!alt_set.len)) return_trace (false);
513 :
514 0 : hb_mask_t glyph_mask = c->buffer->cur().mask;
515 0 : hb_mask_t lookup_mask = c->lookup_mask;
516 :
517 : /* Note: This breaks badly if two features enabled this lookup together. */
518 0 : unsigned int shift = _hb_ctz (lookup_mask);
519 0 : unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
520 :
521 0 : if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
522 :
523 0 : glyph_id = alt_set[alt_index - 1];
524 :
525 0 : c->replace_glyph (glyph_id);
526 :
527 0 : return_trace (true);
528 : }
529 :
530 : inline bool serialize (hb_serialize_context_t *c,
531 : Supplier<GlyphID> &glyphs,
532 : Supplier<unsigned int> &alternate_len_list,
533 : unsigned int num_glyphs,
534 : Supplier<GlyphID> &alternate_glyphs_list)
535 : {
536 : TRACE_SERIALIZE (this);
537 : if (unlikely (!c->extend_min (*this))) return_trace (false);
538 : if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
539 : for (unsigned int i = 0; i < num_glyphs; i++)
540 : if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
541 : alternate_glyphs_list,
542 : alternate_len_list[i]))) return_trace (false);
543 : alternate_len_list.advance (num_glyphs);
544 : if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
545 : return_trace (true);
546 : }
547 :
548 6 : inline bool sanitize (hb_sanitize_context_t *c) const
549 : {
550 6 : TRACE_SANITIZE (this);
551 6 : return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
552 : }
553 :
554 : protected:
555 : USHORT format; /* Format identifier--format = 1 */
556 : OffsetTo<Coverage>
557 : coverage; /* Offset to Coverage table--from
558 : * beginning of Substitution table */
559 : OffsetArrayOf<AlternateSet>
560 : alternateSet; /* Array of AlternateSet tables
561 : * ordered by Coverage Index */
562 : public:
563 : DEFINE_SIZE_ARRAY (6, alternateSet);
564 : };
565 :
566 : struct AlternateSubst
567 : {
568 : inline bool serialize (hb_serialize_context_t *c,
569 : Supplier<GlyphID> &glyphs,
570 : Supplier<unsigned int> &alternate_len_list,
571 : unsigned int num_glyphs,
572 : Supplier<GlyphID> &alternate_glyphs_list)
573 : {
574 : TRACE_SERIALIZE (this);
575 : if (unlikely (!c->extend_min (u.format))) return_trace (false);
576 : unsigned int format = 1;
577 : u.format.set (format);
578 : switch (u.format) {
579 : case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
580 : default:return_trace (false);
581 : }
582 : }
583 :
584 : template <typename context_t>
585 21 : inline typename context_t::return_t dispatch (context_t *c) const
586 : {
587 21 : TRACE_DISPATCH (this, u.format);
588 21 : if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
589 21 : switch (u.format) {
590 21 : case 1: return_trace (c->dispatch (u.format1));
591 0 : default:return_trace (c->default_return_value ());
592 : }
593 : }
594 :
595 : protected:
596 : union {
597 : USHORT format; /* Format identifier */
598 : AlternateSubstFormat1 format1;
599 : } u;
600 : };
601 :
602 :
603 : struct Ligature
604 : {
605 0 : inline void closure (hb_closure_context_t *c) const
606 : {
607 0 : TRACE_CLOSURE (this);
608 0 : unsigned int count = component.len;
609 0 : for (unsigned int i = 1; i < count; i++)
610 0 : if (!c->glyphs->has (component[i]))
611 0 : return;
612 0 : c->glyphs->add (ligGlyph);
613 : }
614 :
615 2959 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
616 : {
617 2959 : TRACE_COLLECT_GLYPHS (this);
618 2959 : unsigned int count = component.len;
619 8848 : for (unsigned int i = 1; i < count; i++)
620 5889 : c->input->add (component[i]);
621 2959 : c->output->add (ligGlyph);
622 2959 : }
623 :
624 0 : inline bool would_apply (hb_would_apply_context_t *c) const
625 : {
626 0 : TRACE_WOULD_APPLY (this);
627 0 : if (c->len != component.len)
628 0 : return_trace (false);
629 :
630 0 : for (unsigned int i = 1; i < c->len; i++)
631 0 : if (likely (c->glyphs[i] != component[i]))
632 0 : return_trace (false);
633 :
634 0 : return_trace (true);
635 : }
636 :
637 10 : inline bool apply (hb_apply_context_t *c) const
638 : {
639 10 : TRACE_APPLY (this);
640 10 : unsigned int count = component.len;
641 :
642 10 : if (unlikely (!count)) return_trace (false);
643 :
644 : /* Special-case to make it in-place and not consider this
645 : * as a "ligated" substitution. */
646 10 : if (unlikely (count == 1))
647 : {
648 0 : c->replace_glyph (ligGlyph);
649 0 : return_trace (true);
650 : }
651 :
652 10 : bool is_mark_ligature = false;
653 10 : unsigned int total_component_count = 0;
654 :
655 10 : unsigned int match_length = 0;
656 : unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
657 :
658 10 : if (likely (!match_input (c, count,
659 : &component[1],
660 : match_glyph,
661 : NULL,
662 : &match_length,
663 : match_positions,
664 : &is_mark_ligature,
665 : &total_component_count)))
666 10 : return_trace (false);
667 :
668 0 : ligate_input (c,
669 : count,
670 : match_positions,
671 : match_length,
672 : ligGlyph,
673 : is_mark_ligature,
674 0 : total_component_count);
675 :
676 0 : return_trace (true);
677 : }
678 :
679 0 : inline bool serialize (hb_serialize_context_t *c,
680 : GlyphID ligature,
681 : Supplier<GlyphID> &components, /* Starting from second */
682 : unsigned int num_components /* Including first component */)
683 : {
684 0 : TRACE_SERIALIZE (this);
685 0 : if (unlikely (!c->extend_min (*this))) return_trace (false);
686 0 : ligGlyph = ligature;
687 0 : if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
688 0 : return_trace (true);
689 : }
690 :
691 : public:
692 1988 : inline bool sanitize (hb_sanitize_context_t *c) const
693 : {
694 1988 : TRACE_SANITIZE (this);
695 1988 : return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
696 : }
697 :
698 : protected:
699 : GlyphID ligGlyph; /* GlyphID of ligature to substitute */
700 : HeadlessArrayOf<GlyphID>
701 : component; /* Array of component GlyphIDs--start
702 : * with the second component--ordered
703 : * in writing direction */
704 : public:
705 : DEFINE_SIZE_ARRAY (4, component);
706 : };
707 :
708 : struct LigatureSet
709 : {
710 0 : inline void closure (hb_closure_context_t *c) const
711 : {
712 0 : TRACE_CLOSURE (this);
713 0 : unsigned int num_ligs = ligature.len;
714 0 : for (unsigned int i = 0; i < num_ligs; i++)
715 0 : (this+ligature[i]).closure (c);
716 0 : }
717 :
718 163 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
719 : {
720 163 : TRACE_COLLECT_GLYPHS (this);
721 163 : unsigned int num_ligs = ligature.len;
722 3122 : for (unsigned int i = 0; i < num_ligs; i++)
723 2959 : (this+ligature[i]).collect_glyphs (c);
724 163 : }
725 :
726 0 : inline bool would_apply (hb_would_apply_context_t *c) const
727 : {
728 0 : TRACE_WOULD_APPLY (this);
729 0 : unsigned int num_ligs = ligature.len;
730 0 : for (unsigned int i = 0; i < num_ligs; i++)
731 : {
732 0 : const Ligature &lig = this+ligature[i];
733 0 : if (lig.would_apply (c))
734 0 : return_trace (true);
735 : }
736 0 : return_trace (false);
737 : }
738 :
739 2 : inline bool apply (hb_apply_context_t *c) const
740 : {
741 2 : TRACE_APPLY (this);
742 2 : unsigned int num_ligs = ligature.len;
743 12 : for (unsigned int i = 0; i < num_ligs; i++)
744 : {
745 10 : const Ligature &lig = this+ligature[i];
746 10 : if (lig.apply (c)) return_trace (true);
747 : }
748 :
749 2 : return_trace (false);
750 : }
751 :
752 0 : inline bool serialize (hb_serialize_context_t *c,
753 : Supplier<GlyphID> &ligatures,
754 : Supplier<unsigned int> &component_count_list,
755 : unsigned int num_ligatures,
756 : Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
757 : {
758 0 : TRACE_SERIALIZE (this);
759 0 : if (unlikely (!c->extend_min (*this))) return_trace (false);
760 0 : if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
761 0 : for (unsigned int i = 0; i < num_ligatures; i++)
762 0 : if (unlikely (!ligature[i].serialize (c, this).serialize (c,
763 : ligatures[i],
764 : component_list,
765 0 : component_count_list[i]))) return_trace (false);
766 0 : ligatures.advance (num_ligatures);
767 0 : component_count_list.advance (num_ligatures);
768 0 : return_trace (true);
769 : }
770 :
771 110 : inline bool sanitize (hb_sanitize_context_t *c) const
772 : {
773 110 : TRACE_SANITIZE (this);
774 110 : return_trace (ligature.sanitize (c, this));
775 : }
776 :
777 : protected:
778 : OffsetArrayOf<Ligature>
779 : ligature; /* Array LigatureSet tables
780 : * ordered by preference */
781 : public:
782 : DEFINE_SIZE_ARRAY (2, ligature);
783 : };
784 :
785 : struct LigatureSubstFormat1
786 : {
787 0 : inline void closure (hb_closure_context_t *c) const
788 : {
789 0 : TRACE_CLOSURE (this);
790 0 : Coverage::Iter iter;
791 0 : unsigned int count = ligatureSet.len;
792 0 : for (iter.init (this+coverage); iter.more (); iter.next ())
793 : {
794 0 : if (unlikely (iter.get_coverage () >= count))
795 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
796 0 : if (c->glyphs->has (iter.get_glyph ()))
797 0 : (this+ligatureSet[iter.get_coverage ()]).closure (c);
798 : }
799 0 : }
800 :
801 18 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
802 : {
803 18 : TRACE_COLLECT_GLYPHS (this);
804 18 : Coverage::Iter iter;
805 18 : unsigned int count = ligatureSet.len;
806 181 : for (iter.init (this+coverage); iter.more (); iter.next ())
807 : {
808 163 : if (unlikely (iter.get_coverage () >= count))
809 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
810 163 : c->input->add (iter.get_glyph ());
811 163 : (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
812 : }
813 18 : }
814 :
815 14 : inline const Coverage &get_coverage (void) const
816 : {
817 14 : return this+coverage;
818 : }
819 :
820 0 : inline bool would_apply (hb_would_apply_context_t *c) const
821 : {
822 0 : TRACE_WOULD_APPLY (this);
823 0 : unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
824 0 : if (likely (index == NOT_COVERED)) return_trace (false);
825 :
826 0 : const LigatureSet &lig_set = this+ligatureSet[index];
827 0 : return_trace (lig_set.would_apply (c));
828 : }
829 :
830 2 : inline bool apply (hb_apply_context_t *c) const
831 : {
832 2 : TRACE_APPLY (this);
833 2 : hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
834 :
835 2 : unsigned int index = (this+coverage).get_coverage (glyph_id);
836 2 : if (likely (index == NOT_COVERED)) return_trace (false);
837 :
838 2 : const LigatureSet &lig_set = this+ligatureSet[index];
839 2 : return_trace (lig_set.apply (c));
840 : }
841 :
842 0 : inline bool serialize (hb_serialize_context_t *c,
843 : Supplier<GlyphID> &first_glyphs,
844 : Supplier<unsigned int> &ligature_per_first_glyph_count_list,
845 : unsigned int num_first_glyphs,
846 : Supplier<GlyphID> &ligatures_list,
847 : Supplier<unsigned int> &component_count_list,
848 : Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
849 : {
850 0 : TRACE_SERIALIZE (this);
851 0 : if (unlikely (!c->extend_min (*this))) return_trace (false);
852 0 : if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
853 0 : for (unsigned int i = 0; i < num_first_glyphs; i++)
854 0 : if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
855 : ligatures_list,
856 : component_count_list,
857 : ligature_per_first_glyph_count_list[i],
858 0 : component_list))) return_trace (false);
859 0 : ligature_per_first_glyph_count_list.advance (num_first_glyphs);
860 0 : if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
861 0 : return_trace (true);
862 : }
863 :
864 14 : inline bool sanitize (hb_sanitize_context_t *c) const
865 : {
866 14 : TRACE_SANITIZE (this);
867 14 : return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
868 : }
869 :
870 : protected:
871 : USHORT format; /* Format identifier--format = 1 */
872 : OffsetTo<Coverage>
873 : coverage; /* Offset to Coverage table--from
874 : * beginning of Substitution table */
875 : OffsetArrayOf<LigatureSet>
876 : ligatureSet; /* Array LigatureSet tables
877 : * ordered by Coverage Index */
878 : public:
879 : DEFINE_SIZE_ARRAY (6, ligatureSet);
880 : };
881 :
882 : struct LigatureSubst
883 : {
884 0 : inline bool serialize (hb_serialize_context_t *c,
885 : Supplier<GlyphID> &first_glyphs,
886 : Supplier<unsigned int> &ligature_per_first_glyph_count_list,
887 : unsigned int num_first_glyphs,
888 : Supplier<GlyphID> &ligatures_list,
889 : Supplier<unsigned int> &component_count_list,
890 : Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
891 : {
892 0 : TRACE_SERIALIZE (this);
893 0 : if (unlikely (!c->extend_min (u.format))) return_trace (false);
894 0 : unsigned int format = 1;
895 0 : u.format.set (format);
896 0 : switch (u.format) {
897 0 : case 1: return_trace (u.format1.serialize (c,
898 : first_glyphs,
899 : ligature_per_first_glyph_count_list,
900 : num_first_glyphs,
901 : ligatures_list,
902 : component_count_list,
903 : component_list));
904 0 : default:return_trace (false);
905 : }
906 : }
907 :
908 : template <typename context_t>
909 114 : inline typename context_t::return_t dispatch (context_t *c) const
910 : {
911 114 : TRACE_DISPATCH (this, u.format);
912 114 : if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
913 114 : switch (u.format) {
914 114 : case 1: return_trace (c->dispatch (u.format1));
915 0 : default:return_trace (c->default_return_value ());
916 : }
917 : }
918 :
919 : protected:
920 : union {
921 : USHORT format; /* Format identifier */
922 : LigatureSubstFormat1 format1;
923 : } u;
924 : };
925 :
926 :
927 : struct ContextSubst : Context {};
928 :
929 : struct ChainContextSubst : ChainContext {};
930 :
931 : struct ExtensionSubst : Extension<ExtensionSubst>
932 : {
933 : typedef struct SubstLookupSubTable LookupSubTable;
934 :
935 : inline bool is_reverse (void) const;
936 : };
937 :
938 :
939 : struct ReverseChainSingleSubstFormat1
940 : {
941 0 : inline void closure (hb_closure_context_t *c) const
942 : {
943 0 : TRACE_CLOSURE (this);
944 0 : const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
945 :
946 : unsigned int count;
947 :
948 0 : count = backtrack.len;
949 0 : for (unsigned int i = 0; i < count; i++)
950 0 : if (!(this+backtrack[i]).intersects (c->glyphs))
951 0 : return;
952 :
953 0 : count = lookahead.len;
954 0 : for (unsigned int i = 0; i < count; i++)
955 0 : if (!(this+lookahead[i]).intersects (c->glyphs))
956 0 : return;
957 :
958 0 : const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
959 0 : Coverage::Iter iter;
960 0 : count = substitute.len;
961 0 : for (iter.init (this+coverage); iter.more (); iter.next ())
962 : {
963 0 : if (unlikely (iter.get_coverage () >= count))
964 0 : break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
965 0 : if (c->glyphs->has (iter.get_glyph ()))
966 0 : c->glyphs->add (substitute[iter.get_coverage ()]);
967 : }
968 : }
969 :
970 0 : inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
971 : {
972 0 : TRACE_COLLECT_GLYPHS (this);
973 :
974 0 : const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
975 :
976 : unsigned int count;
977 :
978 0 : (this+coverage).add_coverage (c->input);
979 :
980 0 : count = backtrack.len;
981 0 : for (unsigned int i = 0; i < count; i++)
982 0 : (this+backtrack[i]).add_coverage (c->before);
983 :
984 0 : count = lookahead.len;
985 0 : for (unsigned int i = 0; i < count; i++)
986 0 : (this+lookahead[i]).add_coverage (c->after);
987 :
988 0 : const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
989 0 : count = substitute.len;
990 0 : for (unsigned int i = 0; i < count; i++)
991 0 : c->output->add (substitute[i]);
992 0 : }
993 :
994 0 : inline const Coverage &get_coverage (void) const
995 : {
996 0 : return this+coverage;
997 : }
998 :
999 0 : inline bool would_apply (hb_would_apply_context_t *c) const
1000 : {
1001 0 : TRACE_WOULD_APPLY (this);
1002 0 : return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1003 : }
1004 :
1005 0 : inline bool apply (hb_apply_context_t *c) const
1006 : {
1007 0 : TRACE_APPLY (this);
1008 0 : if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
1009 0 : return_trace (false); /* No chaining to this type */
1010 :
1011 0 : unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1012 0 : if (likely (index == NOT_COVERED)) return_trace (false);
1013 :
1014 0 : const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1015 0 : const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1016 :
1017 0 : if (match_backtrack (c,
1018 : backtrack.len, (USHORT *) backtrack.array,
1019 0 : match_coverage, this) &&
1020 0 : match_lookahead (c,
1021 : lookahead.len, (USHORT *) lookahead.array,
1022 : match_coverage, this,
1023 0 : 1))
1024 : {
1025 0 : c->replace_glyph_inplace (substitute[index]);
1026 : /* Note: We DON'T decrease buffer->idx. The main loop does it
1027 : * for us. This is useful for preventing surprises if someone
1028 : * calls us through a Context lookup. */
1029 0 : return_trace (true);
1030 : }
1031 :
1032 0 : return_trace (false);
1033 : }
1034 :
1035 0 : inline bool sanitize (hb_sanitize_context_t *c) const
1036 : {
1037 0 : TRACE_SANITIZE (this);
1038 0 : if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1039 0 : return_trace (false);
1040 0 : const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1041 0 : if (!lookahead.sanitize (c, this))
1042 0 : return_trace (false);
1043 0 : const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1044 0 : return_trace (substitute.sanitize (c));
1045 : }
1046 :
1047 : protected:
1048 : USHORT format; /* Format identifier--format = 1 */
1049 : OffsetTo<Coverage>
1050 : coverage; /* Offset to Coverage table--from
1051 : * beginning of table */
1052 : OffsetArrayOf<Coverage>
1053 : backtrack; /* Array of coverage tables
1054 : * in backtracking sequence, in glyph
1055 : * sequence order */
1056 : OffsetArrayOf<Coverage>
1057 : lookaheadX; /* Array of coverage tables
1058 : * in lookahead sequence, in glyph
1059 : * sequence order */
1060 : ArrayOf<GlyphID>
1061 : substituteX; /* Array of substitute
1062 : * GlyphIDs--ordered by Coverage Index */
1063 : public:
1064 : DEFINE_SIZE_MIN (10);
1065 : };
1066 :
1067 : struct ReverseChainSingleSubst
1068 : {
1069 : template <typename context_t>
1070 0 : inline typename context_t::return_t dispatch (context_t *c) const
1071 : {
1072 0 : TRACE_DISPATCH (this, u.format);
1073 0 : if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1074 0 : switch (u.format) {
1075 0 : case 1: return_trace (c->dispatch (u.format1));
1076 0 : default:return_trace (c->default_return_value ());
1077 : }
1078 : }
1079 :
1080 : protected:
1081 : union {
1082 : USHORT format; /* Format identifier */
1083 : ReverseChainSingleSubstFormat1 format1;
1084 : } u;
1085 : };
1086 :
1087 :
1088 :
1089 : /*
1090 : * SubstLookup
1091 : */
1092 :
1093 : struct SubstLookupSubTable
1094 : {
1095 : friend struct SubstLookup;
1096 :
1097 : enum Type {
1098 : Single = 1,
1099 : Multiple = 2,
1100 : Alternate = 3,
1101 : Ligature = 4,
1102 : Context = 5,
1103 : ChainContext = 6,
1104 : Extension = 7,
1105 : ReverseChainSingle = 8
1106 : };
1107 :
1108 : template <typename context_t>
1109 458 : inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1110 : {
1111 458 : TRACE_DISPATCH (this, lookup_type);
1112 458 : if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1113 458 : switch (lookup_type) {
1114 274 : case Single: return_trace (u.single.dispatch (c));
1115 0 : case Multiple: return_trace (u.multiple.dispatch (c));
1116 21 : case Alternate: return_trace (u.alternate.dispatch (c));
1117 114 : case Ligature: return_trace (u.ligature.dispatch (c));
1118 0 : case Context: return_trace (u.context.dispatch (c));
1119 49 : case ChainContext: return_trace (u.chainContext.dispatch (c));
1120 0 : case Extension: return_trace (u.extension.dispatch (c));
1121 0 : case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
1122 0 : default: return_trace (c->default_return_value ());
1123 : }
1124 : }
1125 :
1126 : protected:
1127 : union {
1128 : USHORT sub_format;
1129 : SingleSubst single;
1130 : MultipleSubst multiple;
1131 : AlternateSubst alternate;
1132 : LigatureSubst ligature;
1133 : ContextSubst context;
1134 : ChainContextSubst chainContext;
1135 : ExtensionSubst extension;
1136 : ReverseChainSingleSubst reverseChainContextSingle;
1137 : } u;
1138 : public:
1139 : DEFINE_SIZE_UNION (2, sub_format);
1140 : };
1141 :
1142 :
1143 : struct SubstLookup : Lookup
1144 : {
1145 0 : inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1146 0 : { return Lookup::get_subtable<SubstLookupSubTable> (i); }
1147 :
1148 218 : inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1149 218 : { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1150 :
1151 218 : inline bool is_reverse (void) const
1152 : {
1153 218 : unsigned int type = get_type ();
1154 218 : if (unlikely (type == SubstLookupSubTable::Extension))
1155 0 : return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1156 218 : return lookup_type_is_reverse (type);
1157 : }
1158 :
1159 : inline bool apply (hb_apply_context_t *c) const
1160 : {
1161 : TRACE_APPLY (this);
1162 : return_trace (dispatch (c));
1163 : }
1164 :
1165 0 : inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
1166 : {
1167 0 : TRACE_CLOSURE (this);
1168 0 : c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
1169 0 : return_trace (dispatch (c));
1170 : }
1171 :
1172 84 : inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1173 : {
1174 84 : TRACE_COLLECT_GLYPHS (this);
1175 84 : c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1176 84 : return_trace (dispatch (c));
1177 : }
1178 :
1179 : template <typename set_t>
1180 78 : inline void add_coverage (set_t *glyphs) const
1181 : {
1182 78 : hb_add_coverage_context_t<set_t> c (glyphs);
1183 78 : dispatch (&c);
1184 78 : }
1185 :
1186 0 : inline bool would_apply (hb_would_apply_context_t *c,
1187 : const hb_ot_layout_lookup_accelerator_t *accel) const
1188 : {
1189 0 : TRACE_WOULD_APPLY (this);
1190 0 : if (unlikely (!c->len)) return_trace (false);
1191 0 : if (!accel->may_have (c->glyphs[0])) return_trace (false);
1192 0 : return_trace (dispatch (c));
1193 : }
1194 :
1195 : static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1196 :
1197 0 : inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1198 : unsigned int i)
1199 0 : { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1200 :
1201 0 : inline bool serialize_single (hb_serialize_context_t *c,
1202 : uint32_t lookup_props,
1203 : Supplier<GlyphID> &glyphs,
1204 : Supplier<GlyphID> &substitutes,
1205 : unsigned int num_glyphs)
1206 : {
1207 0 : TRACE_SERIALIZE (this);
1208 0 : if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
1209 0 : return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1210 : }
1211 :
1212 : inline bool serialize_multiple (hb_serialize_context_t *c,
1213 : uint32_t lookup_props,
1214 : Supplier<GlyphID> &glyphs,
1215 : Supplier<unsigned int> &substitute_len_list,
1216 : unsigned int num_glyphs,
1217 : Supplier<GlyphID> &substitute_glyphs_list)
1218 : {
1219 : TRACE_SERIALIZE (this);
1220 : if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
1221 : return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
1222 : glyphs,
1223 : substitute_len_list,
1224 : num_glyphs,
1225 : substitute_glyphs_list));
1226 : }
1227 :
1228 : inline bool serialize_alternate (hb_serialize_context_t *c,
1229 : uint32_t lookup_props,
1230 : Supplier<GlyphID> &glyphs,
1231 : Supplier<unsigned int> &alternate_len_list,
1232 : unsigned int num_glyphs,
1233 : Supplier<GlyphID> &alternate_glyphs_list)
1234 : {
1235 : TRACE_SERIALIZE (this);
1236 : if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
1237 : return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
1238 : glyphs,
1239 : alternate_len_list,
1240 : num_glyphs,
1241 : alternate_glyphs_list));
1242 : }
1243 :
1244 0 : inline bool serialize_ligature (hb_serialize_context_t *c,
1245 : uint32_t lookup_props,
1246 : Supplier<GlyphID> &first_glyphs,
1247 : Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1248 : unsigned int num_first_glyphs,
1249 : Supplier<GlyphID> &ligatures_list,
1250 : Supplier<unsigned int> &component_count_list,
1251 : Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1252 : {
1253 0 : TRACE_SERIALIZE (this);
1254 0 : if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
1255 0 : return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
1256 : first_glyphs,
1257 : ligature_per_first_glyph_count_list,
1258 : num_first_glyphs,
1259 : ligatures_list,
1260 : component_count_list,
1261 : component_list));
1262 : }
1263 :
1264 : template <typename context_t>
1265 : static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1266 :
1267 : template <typename context_t>
1268 458 : inline typename context_t::return_t dispatch (context_t *c) const
1269 458 : { return Lookup::dispatch<SubstLookupSubTable> (c); }
1270 :
1271 78 : inline bool sanitize (hb_sanitize_context_t *c) const
1272 : {
1273 78 : TRACE_SANITIZE (this);
1274 78 : if (unlikely (!Lookup::sanitize (c))) return_trace (false);
1275 78 : if (unlikely (!dispatch (c))) return_trace (false);
1276 :
1277 78 : if (unlikely (get_type () == SubstLookupSubTable::Extension))
1278 : {
1279 : /* The spec says all subtables of an Extension lookup should
1280 : * have the same type. This is specially important if one has
1281 : * a reverse type! */
1282 0 : unsigned int type = get_subtable (0).u.extension.get_type ();
1283 0 : unsigned int count = get_subtable_count ();
1284 0 : for (unsigned int i = 1; i < count; i++)
1285 0 : if (get_subtable (i).u.extension.get_type () != type)
1286 0 : return_trace (false);
1287 : }
1288 78 : return_trace (true);
1289 : }
1290 : };
1291 :
1292 : typedef OffsetListOf<SubstLookup> SubstLookupList;
1293 :
1294 : /*
1295 : * GSUB -- The Glyph Substitution Table
1296 : */
1297 :
1298 : struct GSUB : GSUBGPOS
1299 : {
1300 : static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
1301 :
1302 380 : inline const SubstLookup& get_lookup (unsigned int i) const
1303 380 : { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1304 :
1305 : static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1306 :
1307 4 : inline bool sanitize (hb_sanitize_context_t *c) const
1308 : {
1309 4 : TRACE_SANITIZE (this);
1310 4 : if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
1311 4 : const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1312 4 : return_trace (list.sanitize (c, this));
1313 : }
1314 : };
1315 :
1316 :
1317 : void
1318 34 : GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1319 : {
1320 34 : _hb_buffer_assert_gsubgpos_vars (buffer);
1321 :
1322 34 : const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1323 34 : unsigned int count = buffer->len;
1324 299 : for (unsigned int i = 0; i < count; i++)
1325 : {
1326 265 : _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
1327 265 : _hb_glyph_info_clear_lig_props (&buffer->info[i]);
1328 265 : buffer->info[i].syllable() = 0;
1329 : }
1330 34 : }
1331 :
1332 :
1333 : /* Out-of-class implementation for methods recursing */
1334 :
1335 0 : /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1336 : {
1337 0 : unsigned int type = get_type ();
1338 0 : if (unlikely (type == SubstLookupSubTable::Extension))
1339 0 : return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
1340 0 : return SubstLookup::lookup_type_is_reverse (type);
1341 : }
1342 :
1343 : template <typename context_t>
1344 0 : /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1345 : {
1346 0 : const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1347 0 : const SubstLookup &l = gsub.get_lookup (lookup_index);
1348 0 : return l.dispatch (c);
1349 : }
1350 :
1351 0 : /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1352 : {
1353 0 : const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1354 0 : const SubstLookup &l = gsub.get_lookup (lookup_index);
1355 0 : unsigned int saved_lookup_props = c->lookup_props;
1356 0 : unsigned int saved_lookup_index = c->lookup_index;
1357 0 : c->set_lookup_index (lookup_index);
1358 0 : c->set_lookup_props (l.get_props ());
1359 0 : bool ret = l.dispatch (c);
1360 0 : c->set_lookup_index (saved_lookup_index);
1361 0 : c->set_lookup_props (saved_lookup_props);
1362 0 : return ret;
1363 : }
1364 :
1365 :
1366 : } /* namespace OT */
1367 :
1368 :
1369 : #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
|