Update mojo sdk to rev 1dc8a9a5db73d3718d99917fadf31f5fb2ebad4f
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-ot-layout-gsub-table.hh
blobebe4c9ec4e4e0b7f6053de32cfedd8516cb27a28
1 /*
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
17 * DAMAGE.
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"
35 namespace OT {
38 struct SingleSubstFormat1
40 inline void closure (hb_closure_context_t *c) const
42 TRACE_CLOSURE (this);
43 Coverage::Iter iter;
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);
54 Coverage::Iter iter;
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
64 return this+coverage;
67 inline bool would_apply (hb_would_apply_context_t *c) const
69 TRACE_WOULD_APPLY (this);
70 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
73 inline bool apply (hb_apply_context_t *c) const
75 TRACE_APPLY (this);
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_RETURN (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);
85 return TRACE_RETURN (true);
88 inline bool serialize (hb_serialize_context_t *c,
89 Supplier<GlyphID> &glyphs,
90 unsigned int num_glyphs,
91 int delta)
93 TRACE_SERIALIZE (this);
94 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
95 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
96 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
97 return TRACE_RETURN (true);
100 inline bool sanitize (hb_sanitize_context_t *c) const
102 TRACE_SANITIZE (this);
103 return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
106 protected:
107 USHORT format; /* Format identifier--format = 1 */
108 OffsetTo<Coverage>
109 coverage; /* Offset to Coverage table--from
110 * beginning of Substitution table */
111 SHORT deltaGlyphID; /* Add to original GlyphID to get
112 * substitute GlyphID */
113 public:
114 DEFINE_SIZE_STATIC (6);
117 struct SingleSubstFormat2
119 inline void closure (hb_closure_context_t *c) const
121 TRACE_CLOSURE (this);
122 Coverage::Iter iter;
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);
132 Coverage::Iter iter;
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_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
150 inline bool apply (hb_apply_context_t *c) const
152 TRACE_APPLY (this);
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_RETURN (false);
157 if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
159 glyph_id = substitute[index];
160 c->replace_glyph (glyph_id);
162 return TRACE_RETURN (true);
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_RETURN (false);
172 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
173 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
174 return TRACE_RETURN (true);
177 inline bool sanitize (hb_sanitize_context_t *c) const
179 TRACE_SANITIZE (this);
180 return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
183 protected:
184 USHORT format; /* Format identifier--format = 2 */
185 OffsetTo<Coverage>
186 coverage; /* Offset to Coverage table--from
187 * beginning of Substitution table */
188 ArrayOf<GlyphID>
189 substitute; /* Array of substitute
190 * GlyphIDs--ordered by Coverage Index */
191 public:
192 DEFINE_SIZE_ARRAY (6, substitute);
195 struct SingleSubst
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_RETURN (false);
204 unsigned int format = 2;
205 int delta = 0;
206 if (num_glyphs) {
207 format = 1;
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]) {
212 format = 2;
213 break;
216 u.format.set (format);
217 switch (u.format) {
218 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
219 case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
220 default:return TRACE_RETURN (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))) TRACE_RETURN (c->default_return_value ());
229 switch (u.format) {
230 case 1: return TRACE_RETURN (c->dispatch (u.format1));
231 case 2: return TRACE_RETURN (c->dispatch (u.format2));
232 default:return TRACE_RETURN (c->default_return_value ());
236 protected:
237 union {
238 USHORT format; /* Format identifier */
239 SingleSubstFormat1 format1;
240 SingleSubstFormat2 format2;
241 } u;
245 struct Sequence
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
265 TRACE_APPLY (this);
266 unsigned int count = substitute.len;
268 /* TODO:
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_RETURN (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]);
283 return TRACE_RETURN (true);
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 ();
295 return TRACE_RETURN (true);
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_RETURN (false);
304 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
305 return TRACE_RETURN (true);
308 inline bool sanitize (hb_sanitize_context_t *c) const
310 TRACE_SANITIZE (this);
311 return TRACE_RETURN (substitute.sanitize (c));
314 protected:
315 ArrayOf<GlyphID>
316 substitute; /* String of GlyphIDs to substitute */
317 public:
318 DEFINE_SIZE_ARRAY (2, substitute);
321 struct MultipleSubstFormat1
323 inline void closure (hb_closure_context_t *c) const
325 TRACE_CLOSURE (this);
326 Coverage::Iter iter;
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_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
353 inline bool apply (hb_apply_context_t *c) const
355 TRACE_APPLY (this);
357 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
358 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
360 return TRACE_RETURN ((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_RETURN (false);
371 if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (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_RETURN (false);
376 substitute_len_list.advance (num_glyphs);
377 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
378 return TRACE_RETURN (true);
381 inline bool sanitize (hb_sanitize_context_t *c) const
383 TRACE_SANITIZE (this);
384 return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
387 protected:
388 USHORT format; /* Format identifier--format = 1 */
389 OffsetTo<Coverage>
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 */
395 public:
396 DEFINE_SIZE_ARRAY (6, sequence);
399 struct MultipleSubst
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_RETURN (false);
409 unsigned int format = 1;
410 u.format.set (format);
411 switch (u.format) {
412 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
413 default:return TRACE_RETURN (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))) TRACE_RETURN (c->default_return_value ());
422 switch (u.format) {
423 case 1: return TRACE_RETURN (c->dispatch (u.format1));
424 default:return TRACE_RETURN (c->default_return_value ());
428 protected:
429 union {
430 USHORT format; /* Format identifier */
431 MultipleSubstFormat1 format1;
432 } u;
436 typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
437 * arbitrary order */
439 struct AlternateSubstFormat1
441 inline void closure (hb_closure_context_t *c) const
443 TRACE_CLOSURE (this);
444 Coverage::Iter iter;
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);
458 Coverage::Iter iter;
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_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
479 inline bool apply (hb_apply_context_t *c) const
481 TRACE_APPLY (this);
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_RETURN (false);
487 const AlternateSet &alt_set = this+alternateSet[index];
489 if (unlikely (!alt_set.len)) return TRACE_RETURN (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_RETURN (false);
500 glyph_id = alt_set[alt_index - 1];
502 c->replace_glyph (glyph_id);
504 return TRACE_RETURN (true);
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_RETURN (false);
515 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (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_RETURN (false);
520 alternate_len_list.advance (num_glyphs);
521 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
522 return TRACE_RETURN (true);
525 inline bool sanitize (hb_sanitize_context_t *c) const
527 TRACE_SANITIZE (this);
528 return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
531 protected:
532 USHORT format; /* Format identifier--format = 1 */
533 OffsetTo<Coverage>
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 */
539 public:
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_RETURN (false);
553 unsigned int format = 1;
554 u.format.set (format);
555 switch (u.format) {
556 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
557 default:return TRACE_RETURN (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))) TRACE_RETURN (c->default_return_value ());
566 switch (u.format) {
567 case 1: return TRACE_RETURN (c->dispatch (u.format1));
568 default:return TRACE_RETURN (c->default_return_value ());
572 protected:
573 union {
574 USHORT format; /* Format identifier */
575 AlternateSubstFormat1 format1;
576 } u;
580 struct Ligature
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]))
588 return;
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_RETURN (false);
607 for (unsigned int i = 1; i < c->len; i++)
608 if (likely (c->glyphs[i] != component[i]))
609 return TRACE_RETURN (false);
611 return TRACE_RETURN (true);
614 inline bool apply (hb_apply_context_t *c) const
616 TRACE_APPLY (this);
617 unsigned int count = component.len;
619 if (unlikely (!count)) return TRACE_RETURN (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);
626 return TRACE_RETURN (true);
629 bool is_mark_ligature = false;
630 unsigned int total_component_count = 0;
632 unsigned int match_length = 0;
633 unsigned int match_positions[MAX_CONTEXT_LENGTH];
635 if (likely (!match_input (c, count,
636 &component[1],
637 match_glyph,
638 NULL,
639 &match_length,
640 match_positions,
641 &is_mark_ligature,
642 &total_component_count)))
643 return TRACE_RETURN (false);
645 ligate_input (c,
646 count,
647 match_positions,
648 match_length,
649 ligGlyph,
650 is_mark_ligature,
651 total_component_count);
653 return TRACE_RETURN (true);
656 inline bool serialize (hb_serialize_context_t *c,
657 GlyphID ligature,
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_RETURN (false);
663 ligGlyph = ligature;
664 if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
665 return TRACE_RETURN (true);
668 public:
669 inline bool sanitize (hb_sanitize_context_t *c) const
671 TRACE_SANITIZE (this);
672 return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
675 protected:
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 */
681 public:
682 DEFINE_SIZE_ARRAY (4, component);
685 struct LigatureSet
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))
711 return TRACE_RETURN (true);
713 return TRACE_RETURN (false);
716 inline bool apply (hb_apply_context_t *c) const
718 TRACE_APPLY (this);
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_RETURN (true);
726 return TRACE_RETURN (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_RETURN (false);
737 if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
738 for (unsigned int i = 0; i < num_ligatures; i++)
739 if (unlikely (!ligature[i].serialize (c, this).serialize (c,
740 ligatures[i],
741 component_list,
742 component_count_list[i]))) return TRACE_RETURN (false);
743 ligatures.advance (num_ligatures);
744 component_count_list.advance (num_ligatures);
745 return TRACE_RETURN (true);
748 inline bool sanitize (hb_sanitize_context_t *c) const
750 TRACE_SANITIZE (this);
751 return TRACE_RETURN (ligature.sanitize (c, this));
754 protected:
755 OffsetArrayOf<Ligature>
756 ligature; /* Array LigatureSet tables
757 * ordered by preference */
758 public:
759 DEFINE_SIZE_ARRAY (2, ligature);
762 struct LigatureSubstFormat1
764 inline void closure (hb_closure_context_t *c) const
766 TRACE_CLOSURE (this);
767 Coverage::Iter iter;
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);
777 Coverage::Iter iter;
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_RETURN (false);
795 const LigatureSet &lig_set = this+ligatureSet[index];
796 return TRACE_RETURN (lig_set.would_apply (c));
799 inline bool apply (hb_apply_context_t *c) const
801 TRACE_APPLY (this);
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_RETURN (false);
807 const LigatureSet &lig_set = this+ligatureSet[index];
808 return TRACE_RETURN (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_RETURN (false);
821 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
822 for (unsigned int i = 0; i < num_first_glyphs; i++)
823 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
824 ligatures_list,
825 component_count_list,
826 ligature_per_first_glyph_count_list[i],
827 component_list))) return TRACE_RETURN (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_RETURN (false);
830 return TRACE_RETURN (true);
833 inline bool sanitize (hb_sanitize_context_t *c) const
835 TRACE_SANITIZE (this);
836 return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
839 protected:
840 USHORT format; /* Format identifier--format = 1 */
841 OffsetTo<Coverage>
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 */
847 public:
848 DEFINE_SIZE_ARRAY (6, ligatureSet);
851 struct LigatureSubst
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_RETURN (false);
863 unsigned int format = 1;
864 u.format.set (format);
865 switch (u.format) {
866 case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
867 ligatures_list, component_count_list, component_list));
868 default:return TRACE_RETURN (false);
872 template <typename context_t>
873 inline typename context_t::return_t dispatch (context_t *c) const
875 TRACE_DISPATCH (this, u.format);
876 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
877 switch (u.format) {
878 case 1: return TRACE_RETURN (c->dispatch (u.format1));
879 default:return TRACE_RETURN (c->default_return_value ());
883 protected:
884 union {
885 USHORT format; /* Format identifier */
886 LigatureSubstFormat1 format1;
887 } u;
891 struct ContextSubst : Context {};
893 struct ChainContextSubst : ChainContext {};
895 struct ExtensionSubst : Extension<ExtensionSubst>
897 typedef struct SubstLookupSubTable LookupSubTable;
899 inline bool is_reverse (void) const;
903 struct ReverseChainSingleSubstFormat1
905 inline void closure (hb_closure_context_t *c) const
907 TRACE_CLOSURE (this);
908 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
910 unsigned int count;
912 count = backtrack.len;
913 for (unsigned int i = 0; i < count; i++)
914 if (!(this+backtrack[i]).intersects (c->glyphs))
915 return;
917 count = lookahead.len;
918 for (unsigned int i = 0; i < count; i++)
919 if (!(this+lookahead[i]).intersects (c->glyphs))
920 return;
922 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
923 Coverage::Iter iter;
924 for (iter.init (this+coverage); iter.more (); iter.next ()) {
925 if (c->glyphs->has (iter.get_glyph ()))
926 c->glyphs->add (substitute[iter.get_coverage ()]);
930 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
932 TRACE_COLLECT_GLYPHS (this);
934 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
936 unsigned int count;
938 (this+coverage).add_coverage (c->input);
940 count = backtrack.len;
941 for (unsigned int i = 0; i < count; i++)
942 (this+backtrack[i]).add_coverage (c->before);
944 count = lookahead.len;
945 for (unsigned int i = 0; i < count; i++)
946 (this+lookahead[i]).add_coverage (c->after);
948 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
949 count = substitute.len;
950 for (unsigned int i = 0; i < count; i++)
951 c->output->add (substitute[i]);
954 inline const Coverage &get_coverage (void) const
956 return this+coverage;
959 inline bool would_apply (hb_would_apply_context_t *c) const
961 TRACE_WOULD_APPLY (this);
962 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
965 inline bool apply (hb_apply_context_t *c) const
967 TRACE_APPLY (this);
968 if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
969 return TRACE_RETURN (false); /* No chaining to this type */
971 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
972 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
974 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
975 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
977 if (match_backtrack (c,
978 backtrack.len, (USHORT *) backtrack.array,
979 match_coverage, this) &&
980 match_lookahead (c,
981 lookahead.len, (USHORT *) lookahead.array,
982 match_coverage, this,
985 c->replace_glyph_inplace (substitute[index]);
986 /* Note: We DON'T decrease buffer->idx. The main loop does it
987 * for us. This is useful for preventing surprises if someone
988 * calls us through a Context lookup. */
989 return TRACE_RETURN (true);
992 return TRACE_RETURN (false);
995 inline bool sanitize (hb_sanitize_context_t *c) const
997 TRACE_SANITIZE (this);
998 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
999 return TRACE_RETURN (false);
1000 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1001 if (!lookahead.sanitize (c, this))
1002 return TRACE_RETURN (false);
1003 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1004 return TRACE_RETURN (substitute.sanitize (c));
1007 protected:
1008 USHORT format; /* Format identifier--format = 1 */
1009 OffsetTo<Coverage>
1010 coverage; /* Offset to Coverage table--from
1011 * beginning of table */
1012 OffsetArrayOf<Coverage>
1013 backtrack; /* Array of coverage tables
1014 * in backtracking sequence, in glyph
1015 * sequence order */
1016 OffsetArrayOf<Coverage>
1017 lookaheadX; /* Array of coverage tables
1018 * in lookahead sequence, in glyph
1019 * sequence order */
1020 ArrayOf<GlyphID>
1021 substituteX; /* Array of substitute
1022 * GlyphIDs--ordered by Coverage Index */
1023 public:
1024 DEFINE_SIZE_MIN (10);
1027 struct ReverseChainSingleSubst
1029 template <typename context_t>
1030 inline typename context_t::return_t dispatch (context_t *c) const
1032 TRACE_DISPATCH (this, u.format);
1033 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1034 switch (u.format) {
1035 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1036 default:return TRACE_RETURN (c->default_return_value ());
1040 protected:
1041 union {
1042 USHORT format; /* Format identifier */
1043 ReverseChainSingleSubstFormat1 format1;
1044 } u;
1050 * SubstLookup
1053 struct SubstLookupSubTable
1055 friend struct SubstLookup;
1057 enum Type {
1058 Single = 1,
1059 Multiple = 2,
1060 Alternate = 3,
1061 Ligature = 4,
1062 Context = 5,
1063 ChainContext = 6,
1064 Extension = 7,
1065 ReverseChainSingle = 8
1068 template <typename context_t>
1069 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1071 TRACE_DISPATCH (this, lookup_type);
1072 /* The sub_format passed to may_dispatch is unnecessary but harmless. */
1073 if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
1074 switch (lookup_type) {
1075 case Single: return TRACE_RETURN (u.single.dispatch (c));
1076 case Multiple: return TRACE_RETURN (u.multiple.dispatch (c));
1077 case Alternate: return TRACE_RETURN (u.alternate.dispatch (c));
1078 case Ligature: return TRACE_RETURN (u.ligature.dispatch (c));
1079 case Context: return TRACE_RETURN (u.context.dispatch (c));
1080 case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
1081 case Extension: return TRACE_RETURN (u.extension.dispatch (c));
1082 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
1083 default: return TRACE_RETURN (c->default_return_value ());
1087 protected:
1088 union {
1089 USHORT sub_format;
1090 SingleSubst single;
1091 MultipleSubst multiple;
1092 AlternateSubst alternate;
1093 LigatureSubst ligature;
1094 ContextSubst context;
1095 ChainContextSubst chainContext;
1096 ExtensionSubst extension;
1097 ReverseChainSingleSubst reverseChainContextSingle;
1098 } u;
1099 public:
1100 DEFINE_SIZE_UNION (2, sub_format);
1104 struct SubstLookup : Lookup
1106 inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1107 { return Lookup::get_subtable<SubstLookupSubTable> (i); }
1109 inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1110 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1112 inline bool is_reverse (void) const
1114 unsigned int type = get_type ();
1115 if (unlikely (type == SubstLookupSubTable::Extension))
1116 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1117 return lookup_type_is_reverse (type);
1120 inline bool apply (hb_apply_context_t *c) const
1122 TRACE_APPLY (this);
1123 return TRACE_RETURN (dispatch (c));
1126 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
1128 TRACE_CLOSURE (this);
1129 c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
1130 return TRACE_RETURN (dispatch (c));
1133 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1135 TRACE_COLLECT_GLYPHS (this);
1136 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
1137 return TRACE_RETURN (dispatch (c));
1140 template <typename set_t>
1141 inline void add_coverage (set_t *glyphs) const
1143 hb_add_coverage_context_t<set_t> c (glyphs);
1144 dispatch (&c);
1147 inline bool would_apply (hb_would_apply_context_t *c,
1148 const hb_ot_layout_lookup_accelerator_t *accel) const
1150 TRACE_WOULD_APPLY (this);
1151 if (unlikely (!c->len)) return TRACE_RETURN (false);
1152 if (!accel->may_have (c->glyphs[0])) return TRACE_RETURN (false);
1153 return TRACE_RETURN (dispatch (c));
1156 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1158 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1159 unsigned int i)
1160 { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1162 inline bool serialize_single (hb_serialize_context_t *c,
1163 uint32_t lookup_props,
1164 Supplier<GlyphID> &glyphs,
1165 Supplier<GlyphID> &substitutes,
1166 unsigned int num_glyphs)
1168 TRACE_SERIALIZE (this);
1169 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
1170 return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1173 inline bool serialize_multiple (hb_serialize_context_t *c,
1174 uint32_t lookup_props,
1175 Supplier<GlyphID> &glyphs,
1176 Supplier<unsigned int> &substitute_len_list,
1177 unsigned int num_glyphs,
1178 Supplier<GlyphID> &substitute_glyphs_list)
1180 TRACE_SERIALIZE (this);
1181 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
1182 return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
1183 substitute_glyphs_list));
1186 inline bool serialize_alternate (hb_serialize_context_t *c,
1187 uint32_t lookup_props,
1188 Supplier<GlyphID> &glyphs,
1189 Supplier<unsigned int> &alternate_len_list,
1190 unsigned int num_glyphs,
1191 Supplier<GlyphID> &alternate_glyphs_list)
1193 TRACE_SERIALIZE (this);
1194 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
1195 return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
1196 alternate_glyphs_list));
1199 inline bool serialize_ligature (hb_serialize_context_t *c,
1200 uint32_t lookup_props,
1201 Supplier<GlyphID> &first_glyphs,
1202 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1203 unsigned int num_first_glyphs,
1204 Supplier<GlyphID> &ligatures_list,
1205 Supplier<unsigned int> &component_count_list,
1206 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1208 TRACE_SERIALIZE (this);
1209 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
1210 return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
1211 ligatures_list, component_count_list, component_list));
1214 template <typename context_t>
1215 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1217 template <typename context_t>
1218 inline typename context_t::return_t dispatch (context_t *c) const
1219 { return Lookup::dispatch<SubstLookupSubTable> (c); }
1221 inline bool sanitize (hb_sanitize_context_t *c) const
1223 TRACE_SANITIZE (this);
1224 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1225 const OffsetArrayOf<SubstLookupSubTable> &list = get_subtables<SubstLookupSubTable> ();
1226 if (unlikely (!dispatch (c))) return TRACE_RETURN (false);
1228 if (unlikely (get_type () == SubstLookupSubTable::Extension))
1230 /* The spec says all subtables of an Extension lookup should
1231 * have the same type. This is specially important if one has
1232 * a reverse type! */
1233 unsigned int type = get_subtable (0).u.extension.get_type ();
1234 unsigned int count = get_subtable_count ();
1235 for (unsigned int i = 1; i < count; i++)
1236 if (get_subtable (i).u.extension.get_type () != type)
1237 return TRACE_RETURN (false);
1239 return TRACE_RETURN (true);
1243 typedef OffsetListOf<SubstLookup> SubstLookupList;
1246 * GSUB -- The Glyph Substitution Table
1249 struct GSUB : GSUBGPOS
1251 static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
1253 inline const SubstLookup& get_lookup (unsigned int i) const
1254 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1256 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1257 static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
1259 inline bool sanitize (hb_sanitize_context_t *c) const
1261 TRACE_SANITIZE (this);
1262 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1263 const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1264 return TRACE_RETURN (list.sanitize (c, this));
1266 public:
1267 DEFINE_SIZE_STATIC (10);
1271 void
1272 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1274 _hb_buffer_assert_gsubgpos_vars (buffer);
1276 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1277 unsigned int count = buffer->len;
1278 for (unsigned int i = 0; i < count; i++)
1280 _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
1281 _hb_glyph_info_clear_lig_props (&buffer->info[i]);
1282 buffer->info[i].syllable() = 0;
1286 void
1287 GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
1292 /* Out-of-class implementation for methods recursing */
1294 /*static*/ inline bool ExtensionSubst::is_reverse (void) const
1296 unsigned int type = get_type ();
1297 if (unlikely (type == SubstLookupSubTable::Extension))
1298 return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
1299 return SubstLookup::lookup_type_is_reverse (type);
1302 template <typename context_t>
1303 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1305 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1306 const SubstLookup &l = gsub.get_lookup (lookup_index);
1307 return l.dispatch (c);
1310 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1312 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1313 const SubstLookup &l = gsub.get_lookup (lookup_index);
1314 unsigned int saved_lookup_props = c->lookup_props;
1315 c->set_lookup (l);
1316 bool ret = l.dispatch (c);
1317 c->set_lookup_props (saved_lookup_props);
1318 return ret;
1322 } /* namespace OT */
1325 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */