2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012,2013 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
30 #define HB_OT_LAYOUT_GSUB_TABLE_HH
32 #include "hb-ot-layout-gsubgpos-private.hh"
38 struct SingleSubstFormat1
40 inline void closure (hb_closure_context_t *c) const
44 for (iter.init (this+coverage); iter.more (); iter.next ()) {
45 hb_codepoint_t glyph_id = iter.get_glyph ();
46 if (c->glyphs->has (glyph_id))
47 c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
51 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
53 TRACE_COLLECT_GLYPHS (this);
55 for (iter.init (this+coverage); iter.more (); iter.next ()) {
56 hb_codepoint_t glyph_id = iter.get_glyph ();
57 c->input->add (glyph_id);
58 c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
62 inline const Coverage &get_coverage (void) const
67 inline bool would_apply (hb_would_apply_context_t *c) const
69 TRACE_WOULD_APPLY (this);
70 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
73 inline bool apply (hb_apply_context_t *c) const
76 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
77 unsigned int index = (this+coverage).get_coverage (glyph_id);
78 if (likely (index == NOT_COVERED)) return_trace (false);
80 /* According to the Adobe Annotated OpenType Suite, result is always
81 * limited to 16bit. */
82 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
83 c->replace_glyph (glyph_id);
88 inline bool serialize (hb_serialize_context_t *c,
89 Supplier<GlyphID> &glyphs,
90 unsigned int num_glyphs,
93 TRACE_SERIALIZE (this);
94 if (unlikely (!c->extend_min (*this))) return_trace (false);
95 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
96 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
100 inline bool sanitize (hb_sanitize_context_t *c) const
102 TRACE_SANITIZE (this);
103 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
107 USHORT format; /* Format identifier--format = 1 */
109 coverage; /* Offset to Coverage table--from
110 * beginning of Substitution table */
111 SHORT deltaGlyphID; /* Add to original GlyphID to get
112 * substitute GlyphID */
114 DEFINE_SIZE_STATIC (6);
117 struct SingleSubstFormat2
119 inline void closure (hb_closure_context_t *c) const
121 TRACE_CLOSURE (this);
123 for (iter.init (this+coverage); iter.more (); iter.next ()) {
124 if (c->glyphs->has (iter.get_glyph ()))
125 c->glyphs->add (substitute[iter.get_coverage ()]);
129 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
131 TRACE_COLLECT_GLYPHS (this);
133 for (iter.init (this+coverage); iter.more (); iter.next ()) {
134 c->input->add (iter.get_glyph ());
135 c->output->add (substitute[iter.get_coverage ()]);
139 inline const Coverage &get_coverage (void) const
141 return this+coverage;
144 inline bool would_apply (hb_would_apply_context_t *c) const
146 TRACE_WOULD_APPLY (this);
147 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
150 inline bool apply (hb_apply_context_t *c) const
153 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
154 unsigned int index = (this+coverage).get_coverage (glyph_id);
155 if (likely (index == NOT_COVERED)) return_trace (false);
157 if (unlikely (index >= substitute.len)) return_trace (false);
159 glyph_id = substitute[index];
160 c->replace_glyph (glyph_id);
165 inline bool serialize (hb_serialize_context_t *c,
166 Supplier<GlyphID> &glyphs,
167 Supplier<GlyphID> &substitutes,
168 unsigned int num_glyphs)
170 TRACE_SERIALIZE (this);
171 if (unlikely (!c->extend_min (*this))) return_trace (false);
172 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
173 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
177 inline bool sanitize (hb_sanitize_context_t *c) const
179 TRACE_SANITIZE (this);
180 return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
184 USHORT format; /* Format identifier--format = 2 */
186 coverage; /* Offset to Coverage table--from
187 * beginning of Substitution table */
189 substitute; /* Array of substitute
190 * GlyphIDs--ordered by Coverage Index */
192 DEFINE_SIZE_ARRAY (6, substitute);
197 inline bool serialize (hb_serialize_context_t *c,
198 Supplier<GlyphID> &glyphs,
199 Supplier<GlyphID> &substitutes,
200 unsigned int num_glyphs)
202 TRACE_SERIALIZE (this);
203 if (unlikely (!c->extend_min (u.format))) return_trace (false);
204 unsigned int format = 2;
208 /* TODO(serialize) check for wrap-around */
209 delta = substitutes[0] - glyphs[0];
210 for (unsigned int i = 1; i < num_glyphs; i++)
211 if (delta != substitutes[i] - glyphs[i]) {
216 u.format.set (format);
218 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
219 case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
220 default:return_trace (false);
224 template <typename context_t>
225 inline typename context_t::return_t dispatch (context_t *c) const
227 TRACE_DISPATCH (this, u.format);
228 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
230 case 1: return_trace (c->dispatch (u.format1));
231 case 2: return_trace (c->dispatch (u.format2));
232 default:return_trace (c->default_return_value ());
238 USHORT format; /* Format identifier */
239 SingleSubstFormat1 format1;
240 SingleSubstFormat2 format2;
247 inline void closure (hb_closure_context_t *c) const
249 TRACE_CLOSURE (this);
250 unsigned int count = substitute.len;
251 for (unsigned int i = 0; i < count; i++)
252 c->glyphs->add (substitute[i]);
255 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
257 TRACE_COLLECT_GLYPHS (this);
258 unsigned int count = substitute.len;
259 for (unsigned int i = 0; i < count; i++)
260 c->output->add (substitute[i]);
263 inline bool apply (hb_apply_context_t *c) const
266 unsigned int count = substitute.len;
268 /* Special-case to make it in-place and not consider this
269 * as a "multiplied" substitution. */
270 if (unlikely (count == 1))
272 c->replace_glyph (substitute.array[0]);
275 /* Spec disallows this, but Uniscribe allows it.
276 * https://github.com/behdad/harfbuzz/issues/253 */
277 else if (unlikely (count == 0))
279 c->buffer->delete_glyph ();
283 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
284 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
286 for (unsigned int i = 0; i < count; i++) {
287 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
288 c->output_glyph_for_component (substitute.array[i], klass);
290 c->buffer->skip_glyph ();
295 inline bool serialize (hb_serialize_context_t *c,
296 Supplier<GlyphID> &glyphs,
297 unsigned int num_glyphs)
299 TRACE_SERIALIZE (this);
300 if (unlikely (!c->extend_min (*this))) return_trace (false);
301 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
305 inline bool sanitize (hb_sanitize_context_t *c) const
307 TRACE_SANITIZE (this);
308 return_trace (substitute.sanitize (c));
313 substitute; /* String of GlyphIDs to substitute */
315 DEFINE_SIZE_ARRAY (2, substitute);
318 struct MultipleSubstFormat1
320 inline void closure (hb_closure_context_t *c) const
322 TRACE_CLOSURE (this);
324 for (iter.init (this+coverage); iter.more (); iter.next ()) {
325 if (c->glyphs->has (iter.get_glyph ()))
326 (this+sequence[iter.get_coverage ()]).closure (c);
330 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
332 TRACE_COLLECT_GLYPHS (this);
333 (this+coverage).add_coverage (c->input);
334 unsigned int count = sequence.len;
335 for (unsigned int i = 0; i < count; i++)
336 (this+sequence[i]).collect_glyphs (c);
339 inline const Coverage &get_coverage (void) const
341 return this+coverage;
344 inline bool would_apply (hb_would_apply_context_t *c) const
346 TRACE_WOULD_APPLY (this);
347 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
350 inline bool apply (hb_apply_context_t *c) const
354 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
355 if (likely (index == NOT_COVERED)) return_trace (false);
357 return_trace ((this+sequence[index]).apply (c));
360 inline bool serialize (hb_serialize_context_t *c,
361 Supplier<GlyphID> &glyphs,
362 Supplier<unsigned int> &substitute_len_list,
363 unsigned int num_glyphs,
364 Supplier<GlyphID> &substitute_glyphs_list)
366 TRACE_SERIALIZE (this);
367 if (unlikely (!c->extend_min (*this))) return_trace (false);
368 if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
369 for (unsigned int i = 0; i < num_glyphs; i++)
370 if (unlikely (!sequence[i].serialize (c, this).serialize (c,
371 substitute_glyphs_list,
372 substitute_len_list[i]))) return_trace (false);
373 substitute_len_list.advance (num_glyphs);
374 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
378 inline bool sanitize (hb_sanitize_context_t *c) const
380 TRACE_SANITIZE (this);
381 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
385 USHORT format; /* Format identifier--format = 1 */
387 coverage; /* Offset to Coverage table--from
388 * beginning of Substitution table */
389 OffsetArrayOf<Sequence>
390 sequence; /* Array of Sequence tables
391 * ordered by Coverage Index */
393 DEFINE_SIZE_ARRAY (6, sequence);
398 inline bool serialize (hb_serialize_context_t *c,
399 Supplier<GlyphID> &glyphs,
400 Supplier<unsigned int> &substitute_len_list,
401 unsigned int num_glyphs,
402 Supplier<GlyphID> &substitute_glyphs_list)
404 TRACE_SERIALIZE (this);
405 if (unlikely (!c->extend_min (u.format))) return_trace (false);
406 unsigned int format = 1;
407 u.format.set (format);
409 case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
410 default:return_trace (false);
414 template <typename context_t>
415 inline typename context_t::return_t dispatch (context_t *c) const
417 TRACE_DISPATCH (this, u.format);
418 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
420 case 1: return_trace (c->dispatch (u.format1));
421 default:return_trace (c->default_return_value ());
427 USHORT format; /* Format identifier */
428 MultipleSubstFormat1 format1;
433 typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
436 struct AlternateSubstFormat1
438 inline void closure (hb_closure_context_t *c) const
440 TRACE_CLOSURE (this);
442 for (iter.init (this+coverage); iter.more (); iter.next ()) {
443 if (c->glyphs->has (iter.get_glyph ())) {
444 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
445 unsigned int count = alt_set.len;
446 for (unsigned int i = 0; i < count; i++)
447 c->glyphs->add (alt_set[i]);
452 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
454 TRACE_COLLECT_GLYPHS (this);
456 for (iter.init (this+coverage); iter.more (); iter.next ()) {
457 c->input->add (iter.get_glyph ());
458 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
459 unsigned int count = alt_set.len;
460 for (unsigned int i = 0; i < count; i++)
461 c->output->add (alt_set[i]);
465 inline const Coverage &get_coverage (void) const
467 return this+coverage;
470 inline bool would_apply (hb_would_apply_context_t *c) const
472 TRACE_WOULD_APPLY (this);
473 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
476 inline bool apply (hb_apply_context_t *c) const
479 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
481 unsigned int index = (this+coverage).get_coverage (glyph_id);
482 if (likely (index == NOT_COVERED)) return_trace (false);
484 const AlternateSet &alt_set = this+alternateSet[index];
486 if (unlikely (!alt_set.len)) return_trace (false);
488 hb_mask_t glyph_mask = c->buffer->cur().mask;
489 hb_mask_t lookup_mask = c->lookup_mask;
491 /* Note: This breaks badly if two features enabled this lookup together. */
492 unsigned int shift = _hb_ctz (lookup_mask);
493 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
495 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
497 glyph_id = alt_set[alt_index - 1];
499 c->replace_glyph (glyph_id);
504 inline bool serialize (hb_serialize_context_t *c,
505 Supplier<GlyphID> &glyphs,
506 Supplier<unsigned int> &alternate_len_list,
507 unsigned int num_glyphs,
508 Supplier<GlyphID> &alternate_glyphs_list)
510 TRACE_SERIALIZE (this);
511 if (unlikely (!c->extend_min (*this))) return_trace (false);
512 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
513 for (unsigned int i = 0; i < num_glyphs; i++)
514 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
515 alternate_glyphs_list,
516 alternate_len_list[i]))) return_trace (false);
517 alternate_len_list.advance (num_glyphs);
518 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
522 inline bool sanitize (hb_sanitize_context_t *c) const
524 TRACE_SANITIZE (this);
525 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
529 USHORT format; /* Format identifier--format = 1 */
531 coverage; /* Offset to Coverage table--from
532 * beginning of Substitution table */
533 OffsetArrayOf<AlternateSet>
534 alternateSet; /* Array of AlternateSet tables
535 * ordered by Coverage Index */
537 DEFINE_SIZE_ARRAY (6, alternateSet);
540 struct AlternateSubst
542 inline bool serialize (hb_serialize_context_t *c,
543 Supplier<GlyphID> &glyphs,
544 Supplier<unsigned int> &alternate_len_list,
545 unsigned int num_glyphs,
546 Supplier<GlyphID> &alternate_glyphs_list)
548 TRACE_SERIALIZE (this);
549 if (unlikely (!c->extend_min (u.format))) return_trace (false);
550 unsigned int format = 1;
551 u.format.set (format);
553 case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
554 default:return_trace (false);
558 template <typename context_t>
559 inline typename context_t::return_t dispatch (context_t *c) const
561 TRACE_DISPATCH (this, u.format);
562 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
564 case 1: return_trace (c->dispatch (u.format1));
565 default:return_trace (c->default_return_value ());
571 USHORT format; /* Format identifier */
572 AlternateSubstFormat1 format1;
579 inline void closure (hb_closure_context_t *c) const
581 TRACE_CLOSURE (this);
582 unsigned int count = component.len;
583 for (unsigned int i = 1; i < count; i++)
584 if (!c->glyphs->has (component[i]))
586 c->glyphs->add (ligGlyph);
589 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
591 TRACE_COLLECT_GLYPHS (this);
592 unsigned int count = component.len;
593 for (unsigned int i = 1; i < count; i++)
594 c->input->add (component[i]);
595 c->output->add (ligGlyph);
598 inline bool would_apply (hb_would_apply_context_t *c) const
600 TRACE_WOULD_APPLY (this);
601 if (c->len != component.len)
602 return_trace (false);
604 for (unsigned int i = 1; i < c->len; i++)
605 if (likely (c->glyphs[i] != component[i]))
606 return_trace (false);
611 inline bool apply (hb_apply_context_t *c) const
614 unsigned int count = component.len;
616 if (unlikely (!count)) return_trace (false);
618 /* Special-case to make it in-place and not consider this
619 * as a "ligated" substitution. */
620 if (unlikely (count == 1))
622 c->replace_glyph (ligGlyph);
626 bool is_mark_ligature = false;
627 unsigned int total_component_count = 0;
629 unsigned int match_length = 0;
630 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
632 if (likely (!match_input (c, count,
639 &total_component_count)))
640 return_trace (false);
648 total_component_count);
653 inline bool serialize (hb_serialize_context_t *c,
655 Supplier<GlyphID> &components, /* Starting from second */
656 unsigned int num_components /* Including first component */)
658 TRACE_SERIALIZE (this);
659 if (unlikely (!c->extend_min (*this))) return_trace (false);
661 if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
666 inline bool sanitize (hb_sanitize_context_t *c) const
668 TRACE_SANITIZE (this);
669 return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
673 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
674 HeadlessArrayOf<GlyphID>
675 component; /* Array of component GlyphIDs--start
676 * with the second component--ordered
677 * in writing direction */
679 DEFINE_SIZE_ARRAY (4, component);
684 inline void closure (hb_closure_context_t *c) const
686 TRACE_CLOSURE (this);
687 unsigned int num_ligs = ligature.len;
688 for (unsigned int i = 0; i < num_ligs; i++)
689 (this+ligature[i]).closure (c);
692 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
694 TRACE_COLLECT_GLYPHS (this);
695 unsigned int num_ligs = ligature.len;
696 for (unsigned int i = 0; i < num_ligs; i++)
697 (this+ligature[i]).collect_glyphs (c);
700 inline bool would_apply (hb_would_apply_context_t *c) const
702 TRACE_WOULD_APPLY (this);
703 unsigned int num_ligs = ligature.len;
704 for (unsigned int i = 0; i < num_ligs; i++)
706 const Ligature &lig = this+ligature[i];
707 if (lig.would_apply (c))
710 return_trace (false);
713 inline bool apply (hb_apply_context_t *c) const
716 unsigned int num_ligs = ligature.len;
717 for (unsigned int i = 0; i < num_ligs; i++)
719 const Ligature &lig = this+ligature[i];
720 if (lig.apply (c)) return_trace (true);
723 return_trace (false);
726 inline bool serialize (hb_serialize_context_t *c,
727 Supplier<GlyphID> &ligatures,
728 Supplier<unsigned int> &component_count_list,
729 unsigned int num_ligatures,
730 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
732 TRACE_SERIALIZE (this);
733 if (unlikely (!c->extend_min (*this))) return_trace (false);
734 if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
735 for (unsigned int i = 0; i < num_ligatures; i++)
736 if (unlikely (!ligature[i].serialize (c, this).serialize (c,
739 component_count_list[i]))) return_trace (false);
740 ligatures.advance (num_ligatures);
741 component_count_list.advance (num_ligatures);
745 inline bool sanitize (hb_sanitize_context_t *c) const
747 TRACE_SANITIZE (this);
748 return_trace (ligature.sanitize (c, this));
752 OffsetArrayOf<Ligature>
753 ligature; /* Array LigatureSet tables
754 * ordered by preference */
756 DEFINE_SIZE_ARRAY (2, ligature);
759 struct LigatureSubstFormat1
761 inline void closure (hb_closure_context_t *c) const
763 TRACE_CLOSURE (this);
765 for (iter.init (this+coverage); iter.more (); iter.next ()) {
766 if (c->glyphs->has (iter.get_glyph ()))
767 (this+ligatureSet[iter.get_coverage ()]).closure (c);
771 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
773 TRACE_COLLECT_GLYPHS (this);
775 for (iter.init (this+coverage); iter.more (); iter.next ()) {
776 c->input->add (iter.get_glyph ());
777 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
781 inline const Coverage &get_coverage (void) const
783 return this+coverage;
786 inline bool would_apply (hb_would_apply_context_t *c) const
788 TRACE_WOULD_APPLY (this);
789 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
790 if (likely (index == NOT_COVERED)) return_trace (false);
792 const LigatureSet &lig_set = this+ligatureSet[index];
793 return_trace (lig_set.would_apply (c));
796 inline bool apply (hb_apply_context_t *c) const
799 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
801 unsigned int index = (this+coverage).get_coverage (glyph_id);
802 if (likely (index == NOT_COVERED)) return_trace (false);
804 const LigatureSet &lig_set = this+ligatureSet[index];
805 return_trace (lig_set.apply (c));
808 inline bool serialize (hb_serialize_context_t *c,
809 Supplier<GlyphID> &first_glyphs,
810 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
811 unsigned int num_first_glyphs,
812 Supplier<GlyphID> &ligatures_list,
813 Supplier<unsigned int> &component_count_list,
814 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
816 TRACE_SERIALIZE (this);
817 if (unlikely (!c->extend_min (*this))) return_trace (false);
818 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
819 for (unsigned int i = 0; i < num_first_glyphs; i++)
820 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
822 component_count_list,
823 ligature_per_first_glyph_count_list[i],
824 component_list))) return_trace (false);
825 ligature_per_first_glyph_count_list.advance (num_first_glyphs);
826 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
830 inline bool sanitize (hb_sanitize_context_t *c) const
832 TRACE_SANITIZE (this);
833 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
837 USHORT format; /* Format identifier--format = 1 */
839 coverage; /* Offset to Coverage table--from
840 * beginning of Substitution table */
841 OffsetArrayOf<LigatureSet>
842 ligatureSet; /* Array LigatureSet tables
843 * ordered by Coverage Index */
845 DEFINE_SIZE_ARRAY (6, ligatureSet);
850 inline bool serialize (hb_serialize_context_t *c,
851 Supplier<GlyphID> &first_glyphs,
852 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
853 unsigned int num_first_glyphs,
854 Supplier<GlyphID> &ligatures_list,
855 Supplier<unsigned int> &component_count_list,
856 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
858 TRACE_SERIALIZE (this);
859 if (unlikely (!c->extend_min (u.format))) return_trace (false);
860 unsigned int format = 1;
861 u.format.set (format);
863 case 1: return_trace (u.format1.serialize (c,
865 ligature_per_first_glyph_count_list,
868 component_count_list,
870 default:return_trace (false);
874 template <typename context_t>
875 inline typename context_t::return_t dispatch (context_t *c) const
877 TRACE_DISPATCH (this, u.format);
878 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
880 case 1: return_trace (c->dispatch (u.format1));
881 default:return_trace (c->default_return_value ());
887 USHORT format; /* Format identifier */
888 LigatureSubstFormat1 format1;
893 struct ContextSubst : Context {};
895 struct ChainContextSubst : ChainContext {};
897 struct ExtensionSubst : Extension<ExtensionSubst>
899 typedef struct SubstLookupSubTable LookupSubTable;
901 inline bool is_reverse (void) const;
905 struct ReverseChainSingleSubstFormat1
907 inline void closure (hb_closure_context_t *c) const
909 TRACE_CLOSURE (this);
910 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
914 count = backtrack.len;
915 for (unsigned int i = 0; i < count; i++)
916 if (!(this+backtrack[i]).intersects (c->glyphs))
919 count = lookahead.len;
920 for (unsigned int i = 0; i < count; i++)
921 if (!(this+lookahead[i]).intersects (c->glyphs))
924 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
926 for (iter.init (this+coverage); iter.more (); iter.next ()) {
927 if (c->glyphs->has (iter.get_glyph ()))
928 c->glyphs->add (substitute[iter.get_coverage ()]);
932 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
934 TRACE_COLLECT_GLYPHS (this);
936 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
940 (this+coverage).add_coverage (c->input);
942 count = backtrack.len;
943 for (unsigned int i = 0; i < count; i++)
944 (this+backtrack[i]).add_coverage (c->before);
946 count = lookahead.len;
947 for (unsigned int i = 0; i < count; i++)
948 (this+lookahead[i]).add_coverage (c->after);
950 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
951 count = substitute.len;
952 for (unsigned int i = 0; i < count; i++)
953 c->output->add (substitute[i]);
956 inline const Coverage &get_coverage (void) const
958 return this+coverage;
961 inline bool would_apply (hb_would_apply_context_t *c) const
963 TRACE_WOULD_APPLY (this);
964 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
967 inline bool apply (hb_apply_context_t *c) const
970 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
971 return_trace (false); /* No chaining to this type */
973 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
974 if (likely (index == NOT_COVERED)) return_trace (false);
976 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
977 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
979 if (match_backtrack (c,
980 backtrack.len, (USHORT *) backtrack.array,
981 match_coverage, this) &&
983 lookahead.len, (USHORT *) lookahead.array,
984 match_coverage, this,
987 c->replace_glyph_inplace (substitute[index]);
988 /* Note: We DON'T decrease buffer->idx. The main loop does it
989 * for us. This is useful for preventing surprises if someone
990 * calls us through a Context lookup. */
994 return_trace (false);
997 inline bool sanitize (hb_sanitize_context_t *c) const
999 TRACE_SANITIZE (this);
1000 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1001 return_trace (false);
1002 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1003 if (!lookahead.sanitize (c, this))
1004 return_trace (false);
1005 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1006 return_trace (substitute.sanitize (c));
1010 USHORT format; /* Format identifier--format = 1 */
1012 coverage; /* Offset to Coverage table--from
1013 * beginning of table */
1014 OffsetArrayOf<Coverage>
1015 backtrack; /* Array of coverage tables
1016 * in backtracking sequence, in glyph
1018 OffsetArrayOf<Coverage>
1019 lookaheadX; /* Array of coverage tables
1020 * in lookahead sequence, in glyph
1023 substituteX; /* Array of substitute
1024 * GlyphIDs--ordered by Coverage Index */
1026 DEFINE_SIZE_MIN (10);
1029 struct ReverseChainSingleSubst
1031 template <typename context_t>
1032 inline typename context_t::return_t dispatch (context_t *c) const
1034 TRACE_DISPATCH (this, u.format);
1035 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1037 case 1: return_trace (c->dispatch (u.format1));
1038 default:return_trace (c->default_return_value ());
1044 USHORT format; /* Format identifier */
1045 ReverseChainSingleSubstFormat1 format1;
1055 struct SubstLookupSubTable
1057 friend struct SubstLookup;
1067 ReverseChainSingle = 8
1070 template <typename context_t>
1071 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1073 TRACE_DISPATCH (this, lookup_type);
1074 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1075 switch (lookup_type) {
1076 case Single: return_trace (u.single.dispatch (c));
1077 case Multiple: return_trace (u.multiple.dispatch (c));
1078 case Alternate: return_trace (u.alternate.dispatch (c));
1079 case Ligature: return_trace (u.ligature.dispatch (c));
1080 case Context: return_trace (u.context.dispatch (c));
1081 case ChainContext: return_trace (u.chainContext.dispatch (c));
1082 case Extension: return_trace (u.extension.dispatch (c));
1083 case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
1084 default: return_trace (c->default_return_value ());
1092 MultipleSubst multiple;
1093 AlternateSubst alternate;
1094 LigatureSubst ligature;
1095 ContextSubst context;
1096 ChainContextSubst chainContext;
1097 ExtensionSubst extension;
1098 ReverseChainSingleSubst reverseChainContextSingle;
1101 DEFINE_SIZE_UNION (2, sub_format);
1105 struct SubstLookup : Lookup
1107 inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1108 { return Lookup::get_subtable<SubstLookupSubTable> (i); }
1110 inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1111 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1113 inline bool is_reverse (void) const
1115 unsigned int type = get_type ();
1116 if (unlikely (type == SubstLookupSubTable::Extension))
1117 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1118 return lookup_type_is_reverse (type);
1121 inline bool apply (hb_apply_context_t *c) const
1124 return_trace (dispatch (c));
1127 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
1129 TRACE_CLOSURE (this);
1130 c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
1131 return_trace (dispatch (c));
1134 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1136 TRACE_COLLECT_GLYPHS (this);
1137 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1138 return_trace (dispatch (c));
1141 template <typename set_t>
1142 inline void add_coverage (set_t *glyphs) const
1144 hb_add_coverage_context_t<set_t> c (glyphs);
1148 inline bool would_apply (hb_would_apply_context_t *c,
1149 const hb_ot_layout_lookup_accelerator_t *accel) const
1151 TRACE_WOULD_APPLY (this);
1152 if (unlikely (!c->len)) return_trace (false);
1153 if (!accel->may_have (c->glyphs[0])) return_trace (false);
1154 return_trace (dispatch (c));
1157 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1159 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1161 { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1163 inline bool serialize_single (hb_serialize_context_t *c,
1164 uint32_t lookup_props,
1165 Supplier<GlyphID> &glyphs,
1166 Supplier<GlyphID> &substitutes,
1167 unsigned int num_glyphs)
1169 TRACE_SERIALIZE (this);
1170 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
1171 return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1174 inline bool serialize_multiple (hb_serialize_context_t *c,
1175 uint32_t lookup_props,
1176 Supplier<GlyphID> &glyphs,
1177 Supplier<unsigned int> &substitute_len_list,
1178 unsigned int num_glyphs,
1179 Supplier<GlyphID> &substitute_glyphs_list)
1181 TRACE_SERIALIZE (this);
1182 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
1183 return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
1185 substitute_len_list,
1187 substitute_glyphs_list));
1190 inline bool serialize_alternate (hb_serialize_context_t *c,
1191 uint32_t lookup_props,
1192 Supplier<GlyphID> &glyphs,
1193 Supplier<unsigned int> &alternate_len_list,
1194 unsigned int num_glyphs,
1195 Supplier<GlyphID> &alternate_glyphs_list)
1197 TRACE_SERIALIZE (this);
1198 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
1199 return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
1203 alternate_glyphs_list));
1206 inline bool serialize_ligature (hb_serialize_context_t *c,
1207 uint32_t lookup_props,
1208 Supplier<GlyphID> &first_glyphs,
1209 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1210 unsigned int num_first_glyphs,
1211 Supplier<GlyphID> &ligatures_list,
1212 Supplier<unsigned int> &component_count_list,
1213 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1215 TRACE_SERIALIZE (this);
1216 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
1217 return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
1219 ligature_per_first_glyph_count_list,
1222 component_count_list,
1226 template <typename context_t>
1227 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1229 template <typename context_t>
1230 inline typename context_t::return_t dispatch (context_t *c) const
1231 { return Lookup::dispatch<SubstLookupSubTable> (c); }
1233 inline bool sanitize (hb_sanitize_context_t *c) const
1235 TRACE_SANITIZE (this);
1236 if (unlikely (!Lookup::sanitize (c))) return_trace (false);
1237 if (unlikely (!dispatch (c))) return_trace (false);
1239 if (unlikely (get_type () == SubstLookupSubTable::Extension))
1241 /* The spec says all subtables of an Extension lookup should
1242 * have the same type. This is specially important if one has
1243 * a reverse type! */
1244 unsigned int type = get_subtable (0).u.extension.get_type ();
1245 unsigned int count = get_subtable_count ();
1246 for (unsigned int i = 1; i < count; i++)
1247 if (get_subtable (i).u.extension.get_type () != type)
1248 return_trace (false);
1250 return_trace (true);
1254 typedef OffsetListOf<SubstLookup> SubstLookupList;
1257 * GSUB -- The Glyph Substitution Table
1260 struct GSUB : GSUBGPOS
1262 static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
1264 inline const SubstLookup& get_lookup (unsigned int i) const
1265 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1267 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1269 inline bool sanitize (hb_sanitize_context_t *c) const
1271 TRACE_SANITIZE (this);
1272 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
1273 const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1274 return_trace (list.sanitize (c, this));
1277 DEFINE_SIZE_STATIC (10);
1282 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1284 _hb_buffer_assert_gsubgpos_vars (buffer);
1286 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1287 unsigned int count = buffer->len;
1288 hb_glyph_info_t *info = buffer->info;
1289 for (unsigned int i = 0; i < count; i++)
1291 unsigned int props = gdef.get_glyph_props (info[i].codepoint);
1294 /* Never mark default-ignorables as marks.
1295 * They won't get in the way of lookups anyway,
1296 * but having them as mark will cause them to be skipped
1297 * over if the lookup-flag says so, but at least for the
1298 * Mongolian variation selectors, looks like Uniscribe
1299 * marks them as non-mark. Some Mongolian fonts without
1300 * GDEF rely on this. Another notable character that
1301 * this applies to is COMBINING GRAPHEME JOINER. */
1302 props = (_hb_glyph_info_get_general_category (&info[i]) !=
1303 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
1304 _hb_glyph_info_is_default_ignorable (&info[i])) ?
1305 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
1306 HB_OT_LAYOUT_GLYPH_PROPS_MARK;
1308 _hb_glyph_info_set_glyph_props (&info[i], props);
1309 _hb_glyph_info_clear_lig_props (&info[i]);
1310 buffer->info[i].syllable() = 0;
1315 /* Out-of-class implementation for methods recursing */
1317 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1319 unsigned int type = get_type ();
1320 if (unlikely (type == SubstLookupSubTable::Extension))
1321 return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
1322 return SubstLookup::lookup_type_is_reverse (type);
1325 template <typename context_t>
1326 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1328 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1329 const SubstLookup &l = gsub.get_lookup (lookup_index);
1330 return l.dispatch (c);
1333 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1335 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1336 const SubstLookup &l = gsub.get_lookup (lookup_index);
1337 unsigned int saved_lookup_props = c->lookup_props;
1338 unsigned int saved_lookup_index = c->lookup_index;
1339 c->set_lookup_index (lookup_index);
1340 c->set_lookup_props (l.get_props ());
1341 bool ret = l.dispatch (c);
1342 c->set_lookup_index (saved_lookup_index);
1343 c->set_lookup_props (saved_lookup_props);
1348 } /* namespace OT */
1351 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */