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