2 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
4 * This is part of HarfBuzz, an OpenType Layout engine library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 * Red Hat Author(s): Behdad Esfahbod
27 #ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H
28 #define HB_OT_LAYOUT_GSUB_PRIVATE_H
30 #include "hb-ot-layout-private.h"
32 #include "hb-ot-layout-open-private.h"
33 #include "hb-ot-layout-gdef-private.h"
35 #include "harfbuzz-buffer-private.h" /* XXX */
37 #define DEFINE_GET_GLYPH_COVERAGE(name) \
38 inline unsigned int get_##name (hb_codepoint_t glyph) const { \
39 const Coverage &c = get_coverage (); \
40 return c.get_coverage (glyph); \
43 #define SUBTABLE_SUBSTITUTE_ARGS_DEF \
44 hb_ot_layout_t *layout, \
45 hb_buffer_t *buffer, \
46 unsigned int context_length, \
47 unsigned int nesting_level_left, \
48 unsigned int lookup_flag
49 #define SUBTABLE_SUBSTITUTE_ARGS \
56 struct SingleSubstFormat1 {
58 friend struct SingleSubst;
61 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
62 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
64 inline bool single_substitute (hb_codepoint_t &glyph_id) const {
66 unsigned int index = get_glyph_coverage (glyph_id);
67 if (NOT_COVERED == index)
70 glyph_id += deltaGlyphID;
76 USHORT substFormat; /* Format identifier--format = 1 */
77 Offset coverage; /* Offset to Coverage table--from
78 * beginning of Substitution table */
79 SHORT deltaGlyphID; /* Add to original GlyphID to get
80 * substitute GlyphID */
82 ASSERT_SIZE (SingleSubstFormat1, 6);
84 struct SingleSubstFormat2 {
86 friend struct SingleSubst;
89 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
90 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
92 inline bool single_substitute (hb_codepoint_t &glyph_id) const {
94 unsigned int index = get_glyph_coverage (glyph_id);
96 if (index >= glyphCount)
99 glyph_id = substitute[index];
104 USHORT substFormat; /* Format identifier--format = 2 */
105 Offset coverage; /* Offset to Coverage table--from
106 * beginning of Substitution table */
107 USHORT glyphCount; /* Number of GlyphIDs in the Substitute
109 GlyphID substitute[]; /* Array of substitute
110 * GlyphIDs--ordered by Coverage Index */
112 ASSERT_SIZE (SingleSubstFormat2, 6);
116 friend struct SubstLookupSubTable;
120 unsigned int get_size (void) const {
121 switch (u.substFormat) {
122 case 1: return sizeof (u.format1);
123 case 2: return sizeof (u.format2);
124 default:return sizeof (u.substFormat);
128 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
130 HB_UNUSED (nesting_level_left);
132 if (HB_UNLIKELY (context_length < 1))
135 unsigned int property;
136 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
139 hb_codepoint_t glyph_id = IN_CURGLYPH ();
141 switch (u.substFormat) {
142 case 1: if (!u.format1.single_substitute (glyph_id)) return false;
143 case 2: if (!u.format2.single_substitute (glyph_id)) return false;
144 default:return false;
147 _hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
149 if ( _hb_ot_layout_has_new_glyph_classes (layout) )
151 /* we inherit the old glyph class to the substituted glyph */
152 _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
160 USHORT substFormat; /* Format identifier */
161 SingleSubstFormat1 format1;
162 SingleSubstFormat2 format2;
165 DEFINE_NULL (SingleSubst, 2);
170 friend struct MultipleSubstFormat1;
173 /* GlyphID tables, in Coverage Index order */
174 DEFINE_OFFSET_ARRAY_TYPE (GlyphID, substitute, glyphCount);
176 inline void set_glyph_class (hb_ot_layout_t *layout, unsigned int property) const {
178 unsigned int count = glyphCount;
179 for (unsigned int n = 0; n < count; n++)
180 _hb_ot_layout_set_glyph_property (layout, substitute[n], property);
184 USHORT glyphCount; /* Number of GlyphIDs in the Substitute
185 * array. This should always be
187 GlyphID substitute[]; /* String of GlyphIDs to substitute */
189 DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
191 struct MultipleSubstFormat1 {
193 friend struct MultipleSubst;
196 /* Sequence tables, in Coverage Index order */
197 DEFINE_OFFSET_ARRAY_TYPE (Sequence, sequence, sequenceCount);
198 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
199 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
201 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
203 HB_UNUSED (nesting_level_left);
205 if (HB_UNLIKELY (context_length < 1))
208 unsigned int property;
209 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
212 hb_codepoint_t glyph_id = IN_CURGLYPH ();
214 unsigned int index = get_glyph_coverage (glyph_id);
216 const Sequence &seq = (*this)[index];
218 if (HB_UNLIKELY (!seq.get_len ()))
221 _hb_buffer_add_output_glyph_ids (buffer, 1,
222 seq.glyphCount, seq.substitute,
225 if ( _hb_ot_layout_has_new_glyph_classes (layout) )
227 /* this is a guess only ... */
229 if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
230 property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
232 seq.set_glyph_class (layout, property);
239 USHORT substFormat; /* Format identifier--format = 1 */
240 Offset coverage; /* Offset to Coverage table--from
241 * beginning of Substitution table */
242 USHORT sequenceCount; /* Number of Sequence table offsets in
243 * the Sequence array */
244 Offset sequence[]; /* Array of offsets to Sequence
245 * tables--from beginning of
246 * Substitution table--ordered by
249 ASSERT_SIZE (MultipleSubstFormat1, 6);
251 struct MultipleSubst {
253 friend struct SubstLookupSubTable;
257 unsigned int get_size (void) const {
258 switch (u.substFormat) {
259 case 1: return sizeof (u.format1);
260 default:return sizeof (u.substFormat);
264 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
265 switch (u.substFormat) {
266 case 1: return u.format1.substitute (SUBTABLE_SUBSTITUTE_ARGS);
267 default:return false;
273 USHORT substFormat; /* Format identifier */
274 MultipleSubstFormat1 format1;
277 DEFINE_NULL (MultipleSubst, 2);
280 struct AlternateSet {
282 /* GlyphIDs, in no particular order */
283 DEFINE_ARRAY_TYPE (GlyphID, alternate, glyphCount);
286 USHORT glyphCount; /* Number of GlyphIDs in the Alternate
288 GlyphID alternate[]; /* Array of alternate GlyphIDs--in
291 DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
293 struct AlternateSubstFormat1 {
295 friend struct AlternateSubst;
298 /* AlternateSet tables, in Coverage Index order */
299 DEFINE_OFFSET_ARRAY_TYPE (AlternateSet, alternateSet, alternateSetCount);
300 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
301 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
303 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
305 HB_UNUSED (nesting_level_left);
307 if (HB_UNLIKELY (context_length < 1))
310 unsigned int property;
311 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
314 hb_codepoint_t glyph_id = IN_CURGLYPH ();
316 unsigned int index = get_glyph_coverage (glyph_id);
318 const AlternateSet &alt_set = (*this)[index];
320 if (HB_UNLIKELY (!alt_set.get_len ()))
323 unsigned int alt_index = 0;
325 /* XXX callback to user to choose alternate
327 alt_index = (gsub->altfunc)( buffer->out_pos, glyph_id,
328 aset.GlyphCount, aset.Alternate,
332 if (HB_UNLIKELY (alt_index >= alt_set.get_len ()))
335 glyph_id = alt_set[alt_index];
337 _hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
339 if ( _hb_ot_layout_has_new_glyph_classes (layout) )
341 /* we inherit the old glyph class to the substituted glyph */
342 _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
349 USHORT substFormat; /* Format identifier--format = 1 */
350 Offset coverage; /* Offset to Coverage table--from
351 * beginning of Substitution table */
352 USHORT alternateSetCount; /* Number of AlternateSet tables */
353 Offset alternateSet[]; /* Array of offsets to AlternateSet
354 * tables--from beginning of
355 * Substitution table--ordered by
358 ASSERT_SIZE (AlternateSubstFormat1, 6);
360 struct AlternateSubst {
362 friend struct SubstLookupSubTable;
366 unsigned int get_size (void) const {
367 switch (u.substFormat) {
368 case 1: return sizeof (u.format1);
369 default:return sizeof (u.substFormat);
373 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
374 switch (u.substFormat) {
375 case 1: return u.format1.substitute (SUBTABLE_SUBSTITUTE_ARGS);
376 default:return false;
382 USHORT substFormat; /* Format identifier */
383 AlternateSubstFormat1 format1;
386 DEFINE_NULL (AlternateSubst, 2);
393 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
394 USHORT compCount; /* Number of components in the ligature */
395 GlyphID component[]; /* Array of component GlyphIDs--start
396 * with the second component--ordered
397 * in writing direction */
399 DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
405 USHORT ligatureCount; /* Number of Ligature tables */
406 Offset ligature[]; /* Array of offsets to Ligature
407 * tables--from beginning of
408 * LigatureSet table--ordered by
411 DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
413 struct LigatureSubstFormat1 {
415 friend struct LigatureSubst;
418 /* LigatureSet tables, in Coverage Index order */
419 DEFINE_OFFSET_ARRAY_TYPE (LigatureSet, ligatureSet, ligSetCount);
420 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
421 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
423 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
425 HB_UNUSED (nesting_level_left);
427 unsigned int property;
428 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
431 hb_codepoint_t glyph_id = IN_CURGLYPH ();
433 unsigned int index = get_glyph_coverage (glyph_id);
435 const LigatureSet &lig_set = (*this)[index];
437 bool first_is_mark = (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK ||
438 property & LookupFlag::MarkAttachmentType);
440 unsigned int num_sets = get_len ();
441 for (unsigned int i = 0; i < num_sets; i++) {
443 const LigatureSet &lig_set = (*this)[i];
452 USHORT substFormat; /* Format identifier--format = 1 */
453 Offset coverage; /* Offset to Coverage table--from
454 * beginning of Substitution table */
455 USHORT ligSetCount; /* Number of LigatureSet tables */
456 Offset ligatureSet[]; /* Array of offsets to LigatureSet
457 * tables--from beginning of
458 * Substitution table--ordered by
461 ASSERT_SIZE (LigatureSubstFormat1, 6);
463 struct LigatureSubst {
465 friend struct SubstLookupSubTable;
469 unsigned int get_size (void) const {
470 switch (u.substFormat) {
471 case 1: return sizeof (u.format1);
472 default:return sizeof (u.substFormat);
476 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
477 switch (u.substFormat) {
478 case 1: return u.format1.substitute (SUBTABLE_SUBSTITUTE_ARGS);
479 default:return false;
485 USHORT substFormat; /* Format identifier */
486 LigatureSubstFormat1 format1;
489 DEFINE_NULL (LigatureSubst, 2);
492 struct SubstLookupRecord {
496 USHORT sequenceIndex; /* Index into current glyph
497 * sequence--first glyph = 0 */
498 USHORT lookupListIndex; /* Lookup to apply to that
499 * position--zero--based */
501 DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4);
503 struct ContextSubstFormat1 {
507 USHORT substFormat; /* Format identifier--format = 1 */
508 Offset coverage; /* Offset to Coverage table--from
509 * beginning of Substitution table */
510 USHORT subRuleSetCount; /* Number of SubRuleSet tables--must
511 * equal GlyphCount in Coverage table */
512 Offset subRuleSet[]; /* Array of offsets to SubRuleSet
513 * tables--from beginning of
514 * Substitution table--ordered by
517 ASSERT_SIZE (ContextSubstFormat1, 6);
523 USHORT subRuleCount; /* Number of SubRule tables */
524 Offset subRule[]; /* Array of offsets to SubRule
525 * tables--from beginning of SubRuleSet
526 * table--ordered by preference */
528 DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2);
534 USHORT glyphCount; /* Total number of glyphs in input
535 * glyph sequence--includes the first
537 USHORT substCount; /* Number of SubstLookupRecords */
538 GlyphID input[]; /* Array of input GlyphIDs--start with
540 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
543 DEFINE_NULL_ASSERT_SIZE (SubRule, 4);
545 struct ContextSubstFormat2 {
549 USHORT substFormat; /* Format identifier--format = 2 */
550 Offset coverage; /* Offset to Coverage table--from
551 * beginning of Substitution table */
552 Offset classDef; /* Offset to glyph ClassDef table--from
553 * beginning of Substitution table */
554 USHORT subClassSetCnt; /* Number of SubClassSet tables */
555 Offset subClassSet[]; /* Array of offsets to SubClassSet
556 * tables--from beginning of
557 * Substitution table--ordered by
558 * class--may be NULL */
560 ASSERT_SIZE (ContextSubstFormat2, 8);
566 USHORT subClassRuleCnt; /* Number of SubClassRule tables */
567 Offset subClassRule[]; /* Array of offsets to SubClassRule
568 * tables--from beginning of
569 * SubClassSet--ordered by preference */
571 DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2);
573 struct SubClassRule {
577 USHORT glyphCount; /* Total number of classes
578 * specified for the context in the
579 * rule--includes the first class */
580 USHORT substCount; /* Number of SubstLookupRecords */
581 USHORT klass[]; /* Array of classes--beginning with the
582 * second class--to be matched to the
583 * input glyph class sequence */
584 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
587 DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4);
589 struct ContextSubstFormat3 {
593 USHORT substFormat; /* Format identifier--format = 3 */
594 USHORT glyphCount; /* Number of glyphs in the input glyph
596 USHORT substCount; /* Number of SubstLookupRecords */
597 Offset coverage[]; /* Array of offsets to Coverage
598 * table--from beginning of
599 * Substitution table--in glyph
601 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
604 ASSERT_SIZE (ContextSubstFormat3, 6);
606 struct ChainContextSubstFormat1 {
610 USHORT substFormat; /* Format identifier--format = 1 */
611 Offset coverage; /* Offset to Coverage table--from
612 * beginning of Substitution table */
613 USHORT chainSubRuleSetCount; /* Number of ChainSubRuleSet
614 * tables--must equal GlyphCount in
616 Offset chainSubRuleSet[]; /* Array of offsets to ChainSubRuleSet
617 * tables--from beginning of
618 * Substitution table--ordered by
621 ASSERT_SIZE (ChainContextSubstFormat1, 6);
623 struct ChainSubRuleSet {
627 USHORT chainSubRuleCount; /* Number of ChainSubRule tables */
628 Offset chainSubRule[]; /* Array of offsets to ChainSubRule
629 * tables--from beginning of
630 * ChainSubRuleSet table--ordered
633 DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2);
635 struct ChainSubRule {
639 USHORT backtrackGlyphCount; /* Total number of glyphs in the
640 * backtrack sequence (number of
641 * glyphs to be matched before the
643 GlyphID backtrack[]; /* Array of backtracking GlyphID's
644 * (to be matched before the input
646 USHORT inputGlyphCount; /* Total number of glyphs in the input
647 * sequence (includes the first glyph) */
648 GlyphID input[]; /* Array of input GlyphIDs (start with
650 USHORT lookaheadGlyphCount; /* Total number of glyphs in the look
651 * ahead sequence (number of glyphs to
652 * be matched after the input sequence) */
653 GlyphID lookAhead[]; /* Array of lookahead GlyphID's (to be
654 * matched after the input sequence) */
655 USHORT substCount; /* Number of SubstLookupRecords */
656 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
659 DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8);
661 struct ChainContextSubstFormat2 {
665 USHORT substFormat; /* Format identifier--format = 2 */
666 Offset coverage; /* Offset to Coverage table--from
667 * beginning of Substitution table */
668 Offset backtrackClassDef; /* Offset to glyph ClassDef table
669 * containing backtrack sequence
670 * data--from beginning of Substitution
672 Offset inputClassDef; /* Offset to glyph ClassDef
673 * table containing input sequence
674 * data--from beginning of Substitution
676 Offset lookaheadClassDef; /* Offset to glyph ClassDef table
677 * containing lookahead sequence
678 * data--from beginning of Substitution
680 USHORT chainSubClassSetCnt; /* Number of ChainSubClassSet tables */
681 Offset chainSubClassSet[]; /* Array of offsets to ChainSubClassSet
682 * tables--from beginning of
683 * Substitution table--ordered by input
684 * class--may be NULL */
686 ASSERT_SIZE (ChainContextSubstFormat2, 12);
688 struct ChainSubClassSet {
692 USHORT chainSubClassRuleCnt; /* Number of ChainSubClassRule tables */
693 Offset chainSubClassRule[]; /* Array of offsets
694 * to ChainSubClassRule
695 * tables--from beginning of
696 * ChainSubClassSet--ordered by
699 DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2);
701 struct ChainSubClassRule {
705 USHORT backtrackGlyphCount; /* Total number of glyphs in the
706 * backtrack sequence (number of
707 * glyphs to be matched before the
709 USHORT backtrack[]; /* Array of backtracking classes(to be
710 * matched before the input sequence) */
711 USHORT inputGlyphCount; /* Total number of classes in the input
712 * sequence (includes the first class) */
713 USHORT input[]; /* Array of input classes(start with
714 * second class; to be matched with
715 * the input glyph sequence) */
716 USHORT lookaheadGlyphCount; /* Total number of classes in the
717 * look ahead sequence (number of
718 * classes to be matched after the
720 USHORT lookAhead[]; /* Array of lookahead classes(to be
721 * matched after the input sequence) */
722 USHORT substCount; /* Number of SubstLookupRecords */
723 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
726 DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8);
728 struct ChainContextSubstFormat3 {
732 USHORT substFormat; /* Format identifier--format = 3 */
733 USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking
735 Offset backtrackCoverage[]; /* Array of offsets to coverage tables
736 * in backtracking sequence, in glyph
738 USHORT inputGlyphCount; /* Number of glyphs in input sequence */
739 Offset inputCoverage[]; /* Array of offsets to coverage
740 * tables in input sequence, in glyph
742 USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead
744 Offset lookaheadCoverage[]; /* Array of offsets to coverage tables
745 * in lookahead sequence, in glyph
747 USHORT substCount; /* Number of SubstLookupRecords */
748 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
751 ASSERT_SIZE (ChainContextSubstFormat3, 10);
754 struct ExtensionSubstFormat1 {
756 friend struct ExtensionSubst;
759 inline unsigned int get_type (void) const { return extensionLookupType; }
760 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const;
763 USHORT substFormat; /* Format identifier. Set to 1. */
764 USHORT extensionLookupType; /* Lookup type of subtable referenced
765 * by ExtensionOffset (i.e. the
766 * extension subtable). */
767 ULONG extensionOffset; /* Offset to the extension subtable,
768 * of lookup type subtable. */
770 ASSERT_SIZE (ExtensionSubstFormat1, 8);
772 struct ExtensionSubst {
774 friend struct SubstLookup;
775 friend struct SubstLookupSubTable;
779 unsigned int get_size (void) const {
780 switch (u.substFormat) {
781 case 1: return sizeof (u.format1);
782 default:return sizeof (u.substFormat);
786 inline unsigned int get_type (void) const {
787 switch (u.substFormat) {
788 case 1: return u.format1.get_type ();
793 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
794 switch (u.substFormat) {
795 case 1: return u.format1.substitute (SUBTABLE_SUBSTITUTE_ARGS);
796 default:return false;
802 USHORT substFormat; /* Format identifier */
803 ExtensionSubstFormat1 format1;
806 DEFINE_NULL (ExtensionSubst, 2);
810 struct ReverseChainSingleSubstFormat1 {
814 USHORT substFormat; /* Format identifier--format = 1 */
815 Offset coverage; /* Offset to Coverage table -- from
816 * beginning of Substitution table */
817 USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking
819 Offset backtrackCoverage[]; /* Array of offsets to coverage tables
820 * in backtracking sequence, in glyph
822 USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead
824 Offset lookaheadCoverage[]; /* Array of offsets to coverage tables
825 * in lookahead sequence, in glyph
827 USHORT glyphCount; /* Number of GlyphIDs in the Substitute
829 GlyphID substitute[]; /* Array of substitute
830 * GlyphIDs--ordered by Coverage Index */
832 ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
844 GSUB_ChainingContext = 6,
846 GSUB_ReverseChainingContextSingle = 8,
849 struct SubstLookupSubTable {
850 DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
852 friend struct SubstLookup;
854 unsigned int get_size (unsigned int lookup_type) const {
855 switch (lookup_type) {
856 case GSUB_Single: return u.single.get_size ();
857 case GSUB_Multiple: return u.multiple.get_size ();
858 case GSUB_Alternate: return u.alternate.get_size ();
859 case GSUB_Ligature: return u.ligature.get_size ();
862 case GSUB_ChainingContext:
864 case GSUB_Extension: return u.extension.get_size ();
866 case GSUB_ReverseChainingContextSingle:
868 default:return sizeof (LookupSubTable);
872 inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF,
873 unsigned int lookup_type) const {
874 switch (lookup_type) {
875 case GSUB_Single: return u.single.substitute (SUBTABLE_SUBSTITUTE_ARGS);
876 case GSUB_Multiple: return u.multiple.substitute (SUBTABLE_SUBSTITUTE_ARGS);
877 case GSUB_Alternate: return u.alternate.substitute (SUBTABLE_SUBSTITUTE_ARGS);
878 case GSUB_Ligature: return u.ligature.substitute (SUBTABLE_SUBSTITUTE_ARGS);
880 case GSUB_Context: return u.context.substitute (SUBTABLE_SUBSTITUTE_ARGS);
881 case GSUB_ChainingContext: return u.chainingContext.substitute (SUBTABLE_SUBSTITUTE_ARGS);
883 case GSUB_Extension: return u.extension.substitute (SUBTABLE_SUBSTITUTE_ARGS);
885 case GSUB_ReverseChainingContextSingle: return u.reverseChainingContextSingle.substitute (SUBTABLE_SUBSTITUTE_ARGS);
887 default:return false;
895 MultipleSubst multiple;
896 AlternateSubst alternate;
897 LigatureSubst ligature;
899 ContextSubst context;
900 ChainingContextSubst chainingContext;
902 ExtensionSubst extension;
904 ReverseChainingContextSingleSubst reverseChainingContextSingle;
910 /* Out-of-class implementation for methods chaining */
912 inline bool ExtensionSubstFormat1::substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
913 return (*(SubstLookupSubTable *)(((char *) this) + extensionOffset)).substitute (SUBTABLE_SUBSTITUTE_ARGS,
919 struct SubstLookup : Lookup {
921 DEFINE_NON_INSTANTIABLE(SubstLookup);
923 inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
924 return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
927 /* Like get_type(), but looks through extension lookups.
928 * Never returns Extension */
929 inline unsigned int get_effective_type (void) const {
930 unsigned int type = get_type ();
932 if (HB_UNLIKELY (type == GSUB_Extension)) {
933 /* Return lookup type of first extension subtable.
934 * The spec says all of them should have the same type.
935 * XXX check for that somehow */
936 type = get_subtable(0).u.extension.get_type ();
942 inline bool is_reverse (void) const {
943 switch (get_effective_type ()) {
944 case GSUB_ReverseChainingContextSingle: return true;
945 default: return false;
949 bool substitute_once (hb_ot_layout_t *layout,
951 unsigned int context_length,
952 unsigned int nesting_level_left) const {
954 unsigned int lookup_type = get_type ();
955 unsigned int lookup_flag = get_flag ();
957 if (HB_UNLIKELY (nesting_level_left == 0))
959 nesting_level_left--;
961 for (unsigned int i = 0; i < get_subtable_count (); i++)
962 if (get_subtable (i).substitute (SUBTABLE_SUBSTITUTE_ARGS,
969 bool substitute_string (hb_ot_layout_t *layout,
971 hb_ot_layout_feature_mask_t mask) const {
975 if (HB_LIKELY (!is_reverse ())) {
977 /* in/out forward substitution */
978 _hb_buffer_clear_output (buffer);
980 while (buffer->in_pos < buffer->in_length) {
982 if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
983 substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
986 _hb_buffer_copy_output_glyph (buffer);
990 _hb_buffer_swap (buffer);
994 /* in-place backward substitution */
995 buffer->in_pos = buffer->in_length - 1;
998 if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
999 substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
1004 } while ((int) buffer->in_pos >= 0);
1010 DEFINE_NULL_ALIAS (SubstLookup, Lookup);
1016 struct GSUB : GSUBGPOS {
1017 static const hb_tag_t Tag = HB_TAG ('G','S','U','B');
1019 STATIC_DEFINE_GET_FOR_DATA (GSUB);
1020 /* XXX check version here? */
1022 inline const SubstLookup& get_lookup (unsigned int i) const {
1023 return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
1028 DEFINE_NULL_ALIAS (GSUB, GSUBGPOS);
1031 #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */