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;
269 * Testing shows that Uniscribe actually allows zero-len susbstitute,
270 * which essentially deletes a glyph. We don't allow for now. It
271 * can be confusing to the client since the cluster from the deleted
272 * glyph won't be merged with any output cluster... Also, currently
273 * buffer->move_to() makes assumptions about this too. Perhaps fix
274 * in the future after figuring out what to do with the clusters.
276 if (unlikely (!count)) return_trace (false);
278 /* Special-case to make it in-place and not consider this
279 * as a "multiplied" substitution. */
280 if (unlikely (count == 1))
282 c->replace_glyph (substitute.array[0]);
286 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
287 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
289 for (unsigned int i = 0; i < count; i++) {
290 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
291 c->output_glyph_for_component (substitute.array[i], klass);
293 c->buffer->skip_glyph ();
298 inline bool serialize (hb_serialize_context_t *c,
299 Supplier<GlyphID> &glyphs,
300 unsigned int num_glyphs)
302 TRACE_SERIALIZE (this);
303 if (unlikely (!c->extend_min (*this))) return_trace (false);
304 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
308 inline bool sanitize (hb_sanitize_context_t *c) const
310 TRACE_SANITIZE (this);
311 return_trace (substitute.sanitize (c));
316 substitute; /* String of GlyphIDs to substitute */
318 DEFINE_SIZE_ARRAY (2, substitute);
321 struct MultipleSubstFormat1
323 inline void closure (hb_closure_context_t *c) const
325 TRACE_CLOSURE (this);
327 for (iter.init (this+coverage); iter.more (); iter.next ()) {
328 if (c->glyphs->has (iter.get_glyph ()))
329 (this+sequence[iter.get_coverage ()]).closure (c);
333 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
335 TRACE_COLLECT_GLYPHS (this);
336 (this+coverage).add_coverage (c->input);
337 unsigned int count = sequence.len;
338 for (unsigned int i = 0; i < count; i++)
339 (this+sequence[i]).collect_glyphs (c);
342 inline const Coverage &get_coverage (void) const
344 return this+coverage;
347 inline bool would_apply (hb_would_apply_context_t *c) const
349 TRACE_WOULD_APPLY (this);
350 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
353 inline bool apply (hb_apply_context_t *c) const
357 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
358 if (likely (index == NOT_COVERED)) return_trace (false);
360 return_trace ((this+sequence[index]).apply (c));
363 inline bool serialize (hb_serialize_context_t *c,
364 Supplier<GlyphID> &glyphs,
365 Supplier<unsigned int> &substitute_len_list,
366 unsigned int num_glyphs,
367 Supplier<GlyphID> &substitute_glyphs_list)
369 TRACE_SERIALIZE (this);
370 if (unlikely (!c->extend_min (*this))) return_trace (false);
371 if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
372 for (unsigned int i = 0; i < num_glyphs; i++)
373 if (unlikely (!sequence[i].serialize (c, this).serialize (c,
374 substitute_glyphs_list,
375 substitute_len_list[i]))) return_trace (false);
376 substitute_len_list.advance (num_glyphs);
377 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
381 inline bool sanitize (hb_sanitize_context_t *c) const
383 TRACE_SANITIZE (this);
384 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
388 USHORT format; /* Format identifier--format = 1 */
390 coverage; /* Offset to Coverage table--from
391 * beginning of Substitution table */
392 OffsetArrayOf<Sequence>
393 sequence; /* Array of Sequence tables
394 * ordered by Coverage Index */
396 DEFINE_SIZE_ARRAY (6, sequence);
401 inline bool serialize (hb_serialize_context_t *c,
402 Supplier<GlyphID> &glyphs,
403 Supplier<unsigned int> &substitute_len_list,
404 unsigned int num_glyphs,
405 Supplier<GlyphID> &substitute_glyphs_list)
407 TRACE_SERIALIZE (this);
408 if (unlikely (!c->extend_min (u.format))) return_trace (false);
409 unsigned int format = 1;
410 u.format.set (format);
412 case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
413 default:return_trace (false);
417 template <typename context_t>
418 inline typename context_t::return_t dispatch (context_t *c) const
420 TRACE_DISPATCH (this, u.format);
421 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
423 case 1: return_trace (c->dispatch (u.format1));
424 default:return_trace (c->default_return_value ());
430 USHORT format; /* Format identifier */
431 MultipleSubstFormat1 format1;
436 typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
439 struct AlternateSubstFormat1
441 inline void closure (hb_closure_context_t *c) const
443 TRACE_CLOSURE (this);
445 for (iter.init (this+coverage); iter.more (); iter.next ()) {
446 if (c->glyphs->has (iter.get_glyph ())) {
447 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
448 unsigned int count = alt_set.len;
449 for (unsigned int i = 0; i < count; i++)
450 c->glyphs->add (alt_set[i]);
455 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
457 TRACE_COLLECT_GLYPHS (this);
459 for (iter.init (this+coverage); iter.more (); iter.next ()) {
460 c->input->add (iter.get_glyph ());
461 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
462 unsigned int count = alt_set.len;
463 for (unsigned int i = 0; i < count; i++)
464 c->output->add (alt_set[i]);
468 inline const Coverage &get_coverage (void) const
470 return this+coverage;
473 inline bool would_apply (hb_would_apply_context_t *c) const
475 TRACE_WOULD_APPLY (this);
476 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
479 inline bool apply (hb_apply_context_t *c) const
482 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
484 unsigned int index = (this+coverage).get_coverage (glyph_id);
485 if (likely (index == NOT_COVERED)) return_trace (false);
487 const AlternateSet &alt_set = this+alternateSet[index];
489 if (unlikely (!alt_set.len)) return_trace (false);
491 hb_mask_t glyph_mask = c->buffer->cur().mask;
492 hb_mask_t lookup_mask = c->lookup_mask;
494 /* Note: This breaks badly if two features enabled this lookup together. */
495 unsigned int shift = _hb_ctz (lookup_mask);
496 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
498 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
500 glyph_id = alt_set[alt_index - 1];
502 c->replace_glyph (glyph_id);
507 inline bool serialize (hb_serialize_context_t *c,
508 Supplier<GlyphID> &glyphs,
509 Supplier<unsigned int> &alternate_len_list,
510 unsigned int num_glyphs,
511 Supplier<GlyphID> &alternate_glyphs_list)
513 TRACE_SERIALIZE (this);
514 if (unlikely (!c->extend_min (*this))) return_trace (false);
515 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
516 for (unsigned int i = 0; i < num_glyphs; i++)
517 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
518 alternate_glyphs_list,
519 alternate_len_list[i]))) return_trace (false);
520 alternate_len_list.advance (num_glyphs);
521 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
525 inline bool sanitize (hb_sanitize_context_t *c) const
527 TRACE_SANITIZE (this);
528 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
532 USHORT format; /* Format identifier--format = 1 */
534 coverage; /* Offset to Coverage table--from
535 * beginning of Substitution table */
536 OffsetArrayOf<AlternateSet>
537 alternateSet; /* Array of AlternateSet tables
538 * ordered by Coverage Index */
540 DEFINE_SIZE_ARRAY (6, alternateSet);
543 struct AlternateSubst
545 inline bool serialize (hb_serialize_context_t *c,
546 Supplier<GlyphID> &glyphs,
547 Supplier<unsigned int> &alternate_len_list,
548 unsigned int num_glyphs,
549 Supplier<GlyphID> &alternate_glyphs_list)
551 TRACE_SERIALIZE (this);
552 if (unlikely (!c->extend_min (u.format))) return_trace (false);
553 unsigned int format = 1;
554 u.format.set (format);
556 case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
557 default:return_trace (false);
561 template <typename context_t>
562 inline typename context_t::return_t dispatch (context_t *c) const
564 TRACE_DISPATCH (this, u.format);
565 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
567 case 1: return_trace (c->dispatch (u.format1));
568 default:return_trace (c->default_return_value ());
574 USHORT format; /* Format identifier */
575 AlternateSubstFormat1 format1;
582 inline void closure (hb_closure_context_t *c) const
584 TRACE_CLOSURE (this);
585 unsigned int count = component.len;
586 for (unsigned int i = 1; i < count; i++)
587 if (!c->glyphs->has (component[i]))
589 c->glyphs->add (ligGlyph);
592 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
594 TRACE_COLLECT_GLYPHS (this);
595 unsigned int count = component.len;
596 for (unsigned int i = 1; i < count; i++)
597 c->input->add (component[i]);
598 c->output->add (ligGlyph);
601 inline bool would_apply (hb_would_apply_context_t *c) const
603 TRACE_WOULD_APPLY (this);
604 if (c->len != component.len)
605 return_trace (false);
607 for (unsigned int i = 1; i < c->len; i++)
608 if (likely (c->glyphs[i] != component[i]))
609 return_trace (false);
614 inline bool apply (hb_apply_context_t *c) const
617 unsigned int count = component.len;
619 if (unlikely (!count)) return_trace (false);
621 /* Special-case to make it in-place and not consider this
622 * as a "ligated" substitution. */
623 if (unlikely (count == 1))
625 c->replace_glyph (ligGlyph);
629 bool is_mark_ligature = false;
630 unsigned int total_component_count = 0;
632 unsigned int match_length = 0;
633 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
635 if (likely (!match_input (c, count,
642 &total_component_count)))
643 return_trace (false);
651 total_component_count);
656 inline bool serialize (hb_serialize_context_t *c,
658 Supplier<GlyphID> &components, /* Starting from second */
659 unsigned int num_components /* Including first component */)
661 TRACE_SERIALIZE (this);
662 if (unlikely (!c->extend_min (*this))) return_trace (false);
664 if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
669 inline bool sanitize (hb_sanitize_context_t *c) const
671 TRACE_SANITIZE (this);
672 return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
676 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
677 HeadlessArrayOf<GlyphID>
678 component; /* Array of component GlyphIDs--start
679 * with the second component--ordered
680 * in writing direction */
682 DEFINE_SIZE_ARRAY (4, component);
687 inline void closure (hb_closure_context_t *c) const
689 TRACE_CLOSURE (this);
690 unsigned int num_ligs = ligature.len;
691 for (unsigned int i = 0; i < num_ligs; i++)
692 (this+ligature[i]).closure (c);
695 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
697 TRACE_COLLECT_GLYPHS (this);
698 unsigned int num_ligs = ligature.len;
699 for (unsigned int i = 0; i < num_ligs; i++)
700 (this+ligature[i]).collect_glyphs (c);
703 inline bool would_apply (hb_would_apply_context_t *c) const
705 TRACE_WOULD_APPLY (this);
706 unsigned int num_ligs = ligature.len;
707 for (unsigned int i = 0; i < num_ligs; i++)
709 const Ligature &lig = this+ligature[i];
710 if (lig.would_apply (c))
713 return_trace (false);
716 inline bool apply (hb_apply_context_t *c) const
719 unsigned int num_ligs = ligature.len;
720 for (unsigned int i = 0; i < num_ligs; i++)
722 const Ligature &lig = this+ligature[i];
723 if (lig.apply (c)) return_trace (true);
726 return_trace (false);
729 inline bool serialize (hb_serialize_context_t *c,
730 Supplier<GlyphID> &ligatures,
731 Supplier<unsigned int> &component_count_list,
732 unsigned int num_ligatures,
733 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
735 TRACE_SERIALIZE (this);
736 if (unlikely (!c->extend_min (*this))) return_trace (false);
737 if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
738 for (unsigned int i = 0; i < num_ligatures; i++)
739 if (unlikely (!ligature[i].serialize (c, this).serialize (c,
742 component_count_list[i]))) return_trace (false);
743 ligatures.advance (num_ligatures);
744 component_count_list.advance (num_ligatures);
748 inline bool sanitize (hb_sanitize_context_t *c) const
750 TRACE_SANITIZE (this);
751 return_trace (ligature.sanitize (c, this));
755 OffsetArrayOf<Ligature>
756 ligature; /* Array LigatureSet tables
757 * ordered by preference */
759 DEFINE_SIZE_ARRAY (2, ligature);
762 struct LigatureSubstFormat1
764 inline void closure (hb_closure_context_t *c) const
766 TRACE_CLOSURE (this);
768 for (iter.init (this+coverage); iter.more (); iter.next ()) {
769 if (c->glyphs->has (iter.get_glyph ()))
770 (this+ligatureSet[iter.get_coverage ()]).closure (c);
774 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
776 TRACE_COLLECT_GLYPHS (this);
778 for (iter.init (this+coverage); iter.more (); iter.next ()) {
779 c->input->add (iter.get_glyph ());
780 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
784 inline const Coverage &get_coverage (void) const
786 return this+coverage;
789 inline bool would_apply (hb_would_apply_context_t *c) const
791 TRACE_WOULD_APPLY (this);
792 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
793 if (likely (index == NOT_COVERED)) return_trace (false);
795 const LigatureSet &lig_set = this+ligatureSet[index];
796 return_trace (lig_set.would_apply (c));
799 inline bool apply (hb_apply_context_t *c) const
802 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
804 unsigned int index = (this+coverage).get_coverage (glyph_id);
805 if (likely (index == NOT_COVERED)) return_trace (false);
807 const LigatureSet &lig_set = this+ligatureSet[index];
808 return_trace (lig_set.apply (c));
811 inline bool serialize (hb_serialize_context_t *c,
812 Supplier<GlyphID> &first_glyphs,
813 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
814 unsigned int num_first_glyphs,
815 Supplier<GlyphID> &ligatures_list,
816 Supplier<unsigned int> &component_count_list,
817 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
819 TRACE_SERIALIZE (this);
820 if (unlikely (!c->extend_min (*this))) return_trace (false);
821 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
822 for (unsigned int i = 0; i < num_first_glyphs; i++)
823 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
825 component_count_list,
826 ligature_per_first_glyph_count_list[i],
827 component_list))) return_trace (false);
828 ligature_per_first_glyph_count_list.advance (num_first_glyphs);
829 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
833 inline bool sanitize (hb_sanitize_context_t *c) const
835 TRACE_SANITIZE (this);
836 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
840 USHORT format; /* Format identifier--format = 1 */
842 coverage; /* Offset to Coverage table--from
843 * beginning of Substitution table */
844 OffsetArrayOf<LigatureSet>
845 ligatureSet; /* Array LigatureSet tables
846 * ordered by Coverage Index */
848 DEFINE_SIZE_ARRAY (6, ligatureSet);
853 inline bool serialize (hb_serialize_context_t *c,
854 Supplier<GlyphID> &first_glyphs,
855 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
856 unsigned int num_first_glyphs,
857 Supplier<GlyphID> &ligatures_list,
858 Supplier<unsigned int> &component_count_list,
859 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
861 TRACE_SERIALIZE (this);
862 if (unlikely (!c->extend_min (u.format))) return_trace (false);
863 unsigned int format = 1;
864 u.format.set (format);
866 case 1: return_trace (u.format1.serialize (c,
868 ligature_per_first_glyph_count_list,
871 component_count_list,
873 default:return_trace (false);
877 template <typename context_t>
878 inline typename context_t::return_t dispatch (context_t *c) const
880 TRACE_DISPATCH (this, u.format);
881 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
883 case 1: return_trace (c->dispatch (u.format1));
884 default:return_trace (c->default_return_value ());
890 USHORT format; /* Format identifier */
891 LigatureSubstFormat1 format1;
896 struct ContextSubst : Context {};
898 struct ChainContextSubst : ChainContext {};
900 struct ExtensionSubst : Extension<ExtensionSubst>
902 typedef struct SubstLookupSubTable LookupSubTable;
904 inline bool is_reverse (void) const;
908 struct ReverseChainSingleSubstFormat1
910 inline void closure (hb_closure_context_t *c) const
912 TRACE_CLOSURE (this);
913 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
917 count = backtrack.len;
918 for (unsigned int i = 0; i < count; i++)
919 if (!(this+backtrack[i]).intersects (c->glyphs))
922 count = lookahead.len;
923 for (unsigned int i = 0; i < count; i++)
924 if (!(this+lookahead[i]).intersects (c->glyphs))
927 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
929 for (iter.init (this+coverage); iter.more (); iter.next ()) {
930 if (c->glyphs->has (iter.get_glyph ()))
931 c->glyphs->add (substitute[iter.get_coverage ()]);
935 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
937 TRACE_COLLECT_GLYPHS (this);
939 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
943 (this+coverage).add_coverage (c->input);
945 count = backtrack.len;
946 for (unsigned int i = 0; i < count; i++)
947 (this+backtrack[i]).add_coverage (c->before);
949 count = lookahead.len;
950 for (unsigned int i = 0; i < count; i++)
951 (this+lookahead[i]).add_coverage (c->after);
953 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
954 count = substitute.len;
955 for (unsigned int i = 0; i < count; i++)
956 c->output->add (substitute[i]);
959 inline const Coverage &get_coverage (void) const
961 return this+coverage;
964 inline bool would_apply (hb_would_apply_context_t *c) const
966 TRACE_WOULD_APPLY (this);
967 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
970 inline bool apply (hb_apply_context_t *c) const
973 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
974 return_trace (false); /* No chaining to this type */
976 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
977 if (likely (index == NOT_COVERED)) return_trace (false);
979 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
980 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
982 if (match_backtrack (c,
983 backtrack.len, (USHORT *) backtrack.array,
984 match_coverage, this) &&
986 lookahead.len, (USHORT *) lookahead.array,
987 match_coverage, this,
990 c->replace_glyph_inplace (substitute[index]);
991 /* Note: We DON'T decrease buffer->idx. The main loop does it
992 * for us. This is useful for preventing surprises if someone
993 * calls us through a Context lookup. */
997 return_trace (false);
1000 inline bool sanitize (hb_sanitize_context_t *c) const
1002 TRACE_SANITIZE (this);
1003 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1004 return_trace (false);
1005 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1006 if (!lookahead.sanitize (c, this))
1007 return_trace (false);
1008 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1009 return_trace (substitute.sanitize (c));
1013 USHORT format; /* Format identifier--format = 1 */
1015 coverage; /* Offset to Coverage table--from
1016 * beginning of table */
1017 OffsetArrayOf<Coverage>
1018 backtrack; /* Array of coverage tables
1019 * in backtracking sequence, in glyph
1021 OffsetArrayOf<Coverage>
1022 lookaheadX; /* Array of coverage tables
1023 * in lookahead sequence, in glyph
1026 substituteX; /* Array of substitute
1027 * GlyphIDs--ordered by Coverage Index */
1029 DEFINE_SIZE_MIN (10);
1032 struct ReverseChainSingleSubst
1034 template <typename context_t>
1035 inline typename context_t::return_t dispatch (context_t *c) const
1037 TRACE_DISPATCH (this, u.format);
1038 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1040 case 1: return_trace (c->dispatch (u.format1));
1041 default:return_trace (c->default_return_value ());
1047 USHORT format; /* Format identifier */
1048 ReverseChainSingleSubstFormat1 format1;
1058 struct SubstLookupSubTable
1060 friend struct SubstLookup;
1070 ReverseChainSingle = 8
1073 template <typename context_t>
1074 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1076 TRACE_DISPATCH (this, lookup_type);
1077 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1078 switch (lookup_type) {
1079 case Single: return_trace (u.single.dispatch (c));
1080 case Multiple: return_trace (u.multiple.dispatch (c));
1081 case Alternate: return_trace (u.alternate.dispatch (c));
1082 case Ligature: return_trace (u.ligature.dispatch (c));
1083 case Context: return_trace (u.context.dispatch (c));
1084 case ChainContext: return_trace (u.chainContext.dispatch (c));
1085 case Extension: return_trace (u.extension.dispatch (c));
1086 case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
1087 default: return_trace (c->default_return_value ());
1095 MultipleSubst multiple;
1096 AlternateSubst alternate;
1097 LigatureSubst ligature;
1098 ContextSubst context;
1099 ChainContextSubst chainContext;
1100 ExtensionSubst extension;
1101 ReverseChainSingleSubst reverseChainContextSingle;
1104 DEFINE_SIZE_UNION (2, sub_format);
1108 struct SubstLookup : Lookup
1110 inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1111 { return Lookup::get_subtable<SubstLookupSubTable> (i); }
1113 inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1114 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1116 inline bool is_reverse (void) const
1118 unsigned int type = get_type ();
1119 if (unlikely (type == SubstLookupSubTable::Extension))
1120 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1121 return lookup_type_is_reverse (type);
1124 inline bool apply (hb_apply_context_t *c) const
1127 return_trace (dispatch (c));
1130 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
1132 TRACE_CLOSURE (this);
1133 c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
1134 return_trace (dispatch (c));
1137 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1139 TRACE_COLLECT_GLYPHS (this);
1140 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1141 return_trace (dispatch (c));
1144 template <typename set_t>
1145 inline void add_coverage (set_t *glyphs) const
1147 hb_add_coverage_context_t<set_t> c (glyphs);
1151 inline bool would_apply (hb_would_apply_context_t *c,
1152 const hb_ot_layout_lookup_accelerator_t *accel) const
1154 TRACE_WOULD_APPLY (this);
1155 if (unlikely (!c->len)) return_trace (false);
1156 if (!accel->may_have (c->glyphs[0])) return_trace (false);
1157 return_trace (dispatch (c));
1160 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1162 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1164 { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1166 inline bool serialize_single (hb_serialize_context_t *c,
1167 uint32_t lookup_props,
1168 Supplier<GlyphID> &glyphs,
1169 Supplier<GlyphID> &substitutes,
1170 unsigned int num_glyphs)
1172 TRACE_SERIALIZE (this);
1173 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
1174 return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1177 inline bool serialize_multiple (hb_serialize_context_t *c,
1178 uint32_t lookup_props,
1179 Supplier<GlyphID> &glyphs,
1180 Supplier<unsigned int> &substitute_len_list,
1181 unsigned int num_glyphs,
1182 Supplier<GlyphID> &substitute_glyphs_list)
1184 TRACE_SERIALIZE (this);
1185 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
1186 return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
1188 substitute_len_list,
1190 substitute_glyphs_list));
1193 inline bool serialize_alternate (hb_serialize_context_t *c,
1194 uint32_t lookup_props,
1195 Supplier<GlyphID> &glyphs,
1196 Supplier<unsigned int> &alternate_len_list,
1197 unsigned int num_glyphs,
1198 Supplier<GlyphID> &alternate_glyphs_list)
1200 TRACE_SERIALIZE (this);
1201 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
1202 return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
1206 alternate_glyphs_list));
1209 inline bool serialize_ligature (hb_serialize_context_t *c,
1210 uint32_t lookup_props,
1211 Supplier<GlyphID> &first_glyphs,
1212 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1213 unsigned int num_first_glyphs,
1214 Supplier<GlyphID> &ligatures_list,
1215 Supplier<unsigned int> &component_count_list,
1216 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1218 TRACE_SERIALIZE (this);
1219 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
1220 return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
1222 ligature_per_first_glyph_count_list,
1225 component_count_list,
1229 template <typename context_t>
1230 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1232 template <typename context_t>
1233 inline typename context_t::return_t dispatch (context_t *c) const
1234 { return Lookup::dispatch<SubstLookupSubTable> (c); }
1236 inline bool sanitize (hb_sanitize_context_t *c) const
1238 TRACE_SANITIZE (this);
1239 if (unlikely (!Lookup::sanitize (c))) return_trace (false);
1240 if (unlikely (!dispatch (c))) return_trace (false);
1242 if (unlikely (get_type () == SubstLookupSubTable::Extension))
1244 /* The spec says all subtables of an Extension lookup should
1245 * have the same type. This is specially important if one has
1246 * a reverse type! */
1247 unsigned int type = get_subtable (0).u.extension.get_type ();
1248 unsigned int count = get_subtable_count ();
1249 for (unsigned int i = 1; i < count; i++)
1250 if (get_subtable (i).u.extension.get_type () != type)
1251 return_trace (false);
1253 return_trace (true);
1257 typedef OffsetListOf<SubstLookup> SubstLookupList;
1260 * GSUB -- The Glyph Substitution Table
1263 struct GSUB : GSUBGPOS
1265 static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
1267 inline const SubstLookup& get_lookup (unsigned int i) const
1268 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1270 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1272 inline bool sanitize (hb_sanitize_context_t *c) const
1274 TRACE_SANITIZE (this);
1275 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
1276 const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1277 return_trace (list.sanitize (c, this));
1280 DEFINE_SIZE_STATIC (10);
1285 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1287 _hb_buffer_assert_gsubgpos_vars (buffer);
1289 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1290 unsigned int count = buffer->len;
1291 hb_glyph_info_t *info = buffer->info;
1292 for (unsigned int i = 0; i < count; i++)
1294 unsigned int props = gdef.get_glyph_props (info[i].codepoint);
1297 /* Never mark default-ignorables as marks.
1298 * They won't get in the way of lookups anyway,
1299 * but having them as mark will cause them to be skipped
1300 * over if the lookup-flag says so, but at least for the
1301 * Mongolian variation selectors, looks like Uniscribe
1302 * marks them as non-mark. Some Mongolian fonts without
1303 * GDEF rely on this. Another notable character that
1304 * this applies to is COMBINING GRAPHEME JOINER. */
1305 props = (_hb_glyph_info_get_general_category (&info[i]) !=
1306 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
1307 _hb_glyph_info_is_default_ignorable (&info[i])) ?
1308 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
1309 HB_OT_LAYOUT_GLYPH_PROPS_MARK;
1311 _hb_glyph_info_set_glyph_props (&info[i], props);
1312 _hb_glyph_info_clear_lig_props (&info[i]);
1313 buffer->info[i].syllable() = 0;
1318 /* Out-of-class implementation for methods recursing */
1320 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1322 unsigned int type = get_type ();
1323 if (unlikely (type == SubstLookupSubTable::Extension))
1324 return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
1325 return SubstLookup::lookup_type_is_reverse (type);
1328 template <typename context_t>
1329 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1331 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1332 const SubstLookup &l = gsub.get_lookup (lookup_index);
1333 return l.dispatch (c);
1336 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1338 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1339 const SubstLookup &l = gsub.get_lookup (lookup_index);
1340 unsigned int saved_lookup_props = c->lookup_props;
1341 unsigned int saved_lookup_index = c->lookup_index;
1342 c->set_lookup_index (lookup_index);
1343 c->set_lookup_props (l.get_props ());
1344 bool ret = l.dispatch (c);
1345 c->set_lookup_index (saved_lookup_index);
1346 c->set_lookup_props (saved_lookup_props);
1351 } /* namespace OT */
1354 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */