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 \
44 bool substitute (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) const
49 #define SUBTABLE_SUBSTITUTE_CHAIN(obj) \
50 obj.substitute (layout, \
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 {
68 index = get_glyph_coverage (glyph_id);
69 if (NOT_COVERED == index)
72 glyph_id += deltaGlyphID;
80 if ( index >= ss->ssf.ssf2.GlyphCount )
81 return ERR(HB_Err_Invalid_SubTable);
82 value = ss->ssf.ssf2.Substitute[index];
83 if ( REPLACE_Glyph( buffer, value, nesting_level ) )
89 USHORT substFormat; /* Format identifier--format = 1 */
90 Offset coverage; /* Offset to Coverage table--from
91 * beginning of Substitution table */
92 SHORT deltaGlyphID; /* Add to original GlyphID to get
93 * substitute GlyphID */
95 ASSERT_SIZE (SingleSubstFormat1, 6);
97 struct SingleSubstFormat2 {
99 friend struct SingleSubst;
102 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
103 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
105 inline bool single_substitute (hb_codepoint_t &glyph_id) const {
109 index = get_glyph_coverage (glyph_id);
111 if (index >= glyphCount)
114 glyph_id = substitute[index];
119 USHORT substFormat; /* Format identifier--format = 2 */
120 Offset coverage; /* Offset to Coverage table--from
121 * beginning of Substitution table */
122 USHORT glyphCount; /* Number of GlyphIDs in the Substitute
124 GlyphID substitute[]; /* Array of substitute
125 * GlyphIDs--ordered by Coverage Index */
127 ASSERT_SIZE (SingleSubstFormat2, 6);
131 friend struct SubstLookupSubTable;
133 unsigned int get_size (void) const {
134 switch (u.substFormat) {
135 case 1: return sizeof (u.format1);
136 case 2: return sizeof (u.format2);
137 default:return sizeof (u.substFormat);
142 inline SUBTABLE_SUBSTITUTE {
144 hb_codepoint_t glyph_id;
145 unsigned int property;
147 HB_UNUSED (nesting_level_left);
149 if (HB_UNLIKELY (context_length < 1))
152 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
155 glyph_id = IN_CURGLYPH ();
157 switch (u.substFormat) {
158 case 1: if (!u.format1.single_substitute (glyph_id)) return false;
159 case 2: if (!u.format2.single_substitute (glyph_id)) return false;
160 default:return false;
163 _hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
165 if ( _hb_ot_layout_has_new_glyph_classes (layout) )
167 /* we inherit the old glyph class to the substituted glyph */
168 _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
176 USHORT substFormat; /* Format identifier */
177 SingleSubstFormat1 format1;
178 SingleSubstFormat2 format2;
181 DEFINE_NULL (SingleSubst, 2);
186 friend struct MultipleSubstFormat1;
189 /* GlyphID tables, in Coverage Index order */
190 DEFINE_OFFSET_ARRAY_TYPE (GlyphID, substitute, glyphCount);
192 inline void set_glyph_class (hb_ot_layout_t *layout, unsigned int property) const {
193 unsigned int n, count = glyphCount;
195 for (n = 0; n < count; n++)
196 _hb_ot_layout_set_glyph_property (layout, substitute[n], property);
200 USHORT glyphCount; /* Number of GlyphIDs in the Substitute
201 * array. This should always be
203 GlyphID substitute[]; /* String of GlyphIDs to substitute */
205 DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
207 struct MultipleSubstFormat1 {
209 friend struct MultipleSubst;
212 /* Sequence tables, in Coverage Index order */
213 DEFINE_OFFSET_ARRAY_TYPE (Sequence, sequence, sequenceCount);
214 DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
215 DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
217 inline SUBTABLE_SUBSTITUTE {
219 hb_codepoint_t glyph_id;
221 unsigned int property;
223 HB_UNUSED (nesting_level_left);
225 if (HB_UNLIKELY (context_length < 1))
228 if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
231 glyph_id = IN_CURGLYPH ();
233 index = get_glyph_coverage (glyph_id);
234 if (index >= sequenceCount)
237 const Sequence &seq = (*this)[index];
238 _hb_buffer_add_output_glyph_ids (buffer, 1,
239 seq.glyphCount, seq.substitute,
242 if ( _hb_ot_layout_has_new_glyph_classes (layout) )
244 /* this is a guess only ... */
246 if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
247 property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
249 seq.set_glyph_class (layout, property);
256 USHORT substFormat; /* Format identifier--format = 1 */
257 Offset coverage; /* Offset to Coverage table--from
258 * beginning of Substitution table */
259 USHORT sequenceCount; /* Number of Sequence table offsets in
260 * the Sequence array */
261 Offset sequence[]; /* Array of offsets to Sequence
262 * tables--from beginning of
263 * Substitution table--ordered by
266 ASSERT_SIZE (MultipleSubstFormat1, 6);
268 struct MultipleSubst {
270 unsigned int get_size (void) const {
271 switch (u.substFormat) {
272 case 1: return sizeof (u.format1);
273 default:return sizeof (u.substFormat);
278 inline SUBTABLE_SUBSTITUTE {
279 switch (u.substFormat) {
280 case 1: return SUBTABLE_SUBSTITUTE_CHAIN(u.format1);
281 default:return false;
287 USHORT substFormat; /* Format identifier */
288 MultipleSubstFormat1 format1;
291 DEFINE_NULL (MultipleSubst, 2);
294 struct AlternateSet {
298 USHORT glyphCount; /* Number of GlyphIDs in the Alternate
300 GlyphID alternate[]; /* Array of alternate GlyphIDs--in
303 DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
305 struct AlternateSubstFormat1 {
309 USHORT substFormat; /* Format identifier--format = 1 */
310 Offset coverage; /* Offset to Coverage table--from
311 * beginning of Substitution table */
312 USHORT alternateSetCount; /* Number of AlternateSet tables */
313 Offset alternateSet[]; /* Array of offsets to AlternateSet
314 * tables--from beginning of
315 * Substitution table--ordered by
318 ASSERT_SIZE (AlternateSubstFormat1, 6);
325 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
326 USHORT compCount; /* Number of components in the ligature */
327 GlyphID component[]; /* Array of component GlyphIDs--start
328 * with the second component--ordered
329 * in writing direction */
331 DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
337 USHORT ligatureCount; /* Number of Ligature tables */
338 Offset ligature[]; /* Array of offsets to Ligature
339 * tables--from beginning of
340 * LigatureSet table--ordered by
343 DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
345 struct LigatureSubstFormat1 {
349 USHORT substFormat; /* Format identifier--format = 1 */
350 Offset coverage; /* Offset to Coverage table--from
351 * beginning of Substitution table */
352 USHORT ligSetCount; /* Number of LigatureSet tables */
353 Offset ligatureSet[]; /* Array of offsets to LigatureSet
354 * tables--from beginning of
355 * Substitution table--ordered by
358 ASSERT_SIZE (LigatureSubstFormat1, 6);
361 struct SubstLookupRecord {
365 USHORT sequenceIndex; /* Index into current glyph
366 * sequence--first glyph = 0 */
367 USHORT lookupListIndex; /* Lookup to apply to that
368 * position--zero--based */
370 DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4);
372 struct ContextSubstFormat1 {
376 USHORT substFormat; /* Format identifier--format = 1 */
377 Offset coverage; /* Offset to Coverage table--from
378 * beginning of Substitution table */
379 USHORT subRuleSetCount; /* Number of SubRuleSet tables--must
380 * equal GlyphCount in Coverage table */
381 Offset subRuleSet[]; /* Array of offsets to SubRuleSet
382 * tables--from beginning of
383 * Substitution table--ordered by
386 ASSERT_SIZE (ContextSubstFormat1, 6);
392 USHORT subRuleCount; /* Number of SubRule tables */
393 Offset subRule[]; /* Array of offsets to SubRule
394 * tables--from beginning of SubRuleSet
395 * table--ordered by preference */
397 DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2);
403 USHORT glyphCount; /* Total number of glyphs in input
404 * glyph sequence--includes the first
406 USHORT substCount; /* Number of SubstLookupRecords */
407 GlyphID input[]; /* Array of input GlyphIDs--start with
409 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
412 DEFINE_NULL_ASSERT_SIZE (SubRule, 4);
414 struct ContextSubstFormat2 {
418 USHORT substFormat; /* Format identifier--format = 2 */
419 Offset coverage; /* Offset to Coverage table--from
420 * beginning of Substitution table */
421 Offset classDef; /* Offset to glyph ClassDef table--from
422 * beginning of Substitution table */
423 USHORT subClassSetCnt; /* Number of SubClassSet tables */
424 Offset subClassSet[]; /* Array of offsets to SubClassSet
425 * tables--from beginning of
426 * Substitution table--ordered by
427 * class--may be NULL */
429 ASSERT_SIZE (ContextSubstFormat2, 8);
435 USHORT subClassRuleCnt; /* Number of SubClassRule tables */
436 Offset subClassRule[]; /* Array of offsets to SubClassRule
437 * tables--from beginning of
438 * SubClassSet--ordered by preference */
440 DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2);
442 struct SubClassRule {
446 USHORT glyphCount; /* Total number of classes
447 * specified for the context in the
448 * rule--includes the first class */
449 USHORT substCount; /* Number of SubstLookupRecords */
450 USHORT klass[]; /* Array of classes--beginning with the
451 * second class--to be matched to the
452 * input glyph class sequence */
453 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
456 DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4);
458 struct ContextSubstFormat3 {
462 USHORT substFormat; /* Format identifier--format = 3 */
463 USHORT glyphCount; /* Number of glyphs in the input glyph
465 USHORT substCount; /* Number of SubstLookupRecords */
466 Offset coverage[]; /* Array of offsets to Coverage
467 * table--from beginning of
468 * Substitution table--in glyph
470 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
473 ASSERT_SIZE (ContextSubstFormat3, 6);
475 struct ChainContextSubstFormat1 {
479 USHORT substFormat; /* Format identifier--format = 1 */
480 Offset coverage; /* Offset to Coverage table--from
481 * beginning of Substitution table */
482 USHORT chainSubRuleSetCount; /* Number of ChainSubRuleSet
483 * tables--must equal GlyphCount in
485 Offset chainSubRuleSet[]; /* Array of offsets to ChainSubRuleSet
486 * tables--from beginning of
487 * Substitution table--ordered by
490 ASSERT_SIZE (ChainContextSubstFormat1, 6);
492 struct ChainSubRuleSet {
496 USHORT chainSubRuleCount; /* Number of ChainSubRule tables */
497 Offset chainSubRule[]; /* Array of offsets to ChainSubRule
498 * tables--from beginning of
499 * ChainSubRuleSet table--ordered
502 DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2);
504 struct ChainSubRule {
508 USHORT backtrackGlyphCount; /* Total number of glyphs in the
509 * backtrack sequence (number of
510 * glyphs to be matched before the
512 GlyphID backtrack[]; /* Array of backtracking GlyphID's
513 * (to be matched before the input
515 USHORT inputGlyphCount; /* Total number of glyphs in the input
516 * sequence (includes the first glyph) */
517 GlyphID input[]; /* Array of input GlyphIDs (start with
519 USHORT lookaheadGlyphCount; /* Total number of glyphs in the look
520 * ahead sequence (number of glyphs to
521 * be matched after the input sequence) */
522 GlyphID lookAhead[]; /* Array of lookahead GlyphID's (to be
523 * matched after the input sequence) */
524 USHORT substCount; /* Number of SubstLookupRecords */
525 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
528 DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8);
530 struct ChainContextSubstFormat2 {
534 USHORT substFormat; /* Format identifier--format = 2 */
535 Offset coverage; /* Offset to Coverage table--from
536 * beginning of Substitution table */
537 Offset backtrackClassDef; /* Offset to glyph ClassDef table
538 * containing backtrack sequence
539 * data--from beginning of Substitution
541 Offset inputClassDef; /* Offset to glyph ClassDef
542 * table containing input sequence
543 * data--from beginning of Substitution
545 Offset lookaheadClassDef; /* Offset to glyph ClassDef table
546 * containing lookahead sequence
547 * data--from beginning of Substitution
549 USHORT chainSubClassSetCnt; /* Number of ChainSubClassSet tables */
550 Offset chainSubClassSet[]; /* Array of offsets to ChainSubClassSet
551 * tables--from beginning of
552 * Substitution table--ordered by input
553 * class--may be NULL */
555 ASSERT_SIZE (ChainContextSubstFormat2, 12);
557 struct ChainSubClassSet {
561 USHORT chainSubClassRuleCnt; /* Number of ChainSubClassRule tables */
562 Offset chainSubClassRule[]; /* Array of offsets
563 * to ChainSubClassRule
564 * tables--from beginning of
565 * ChainSubClassSet--ordered by
568 DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2);
570 struct ChainSubClassRule {
574 USHORT backtrackGlyphCount; /* Total number of glyphs in the
575 * backtrack sequence (number of
576 * glyphs to be matched before the
578 USHORT backtrack[]; /* Array of backtracking classes(to be
579 * matched before the input sequence) */
580 USHORT inputGlyphCount; /* Total number of classes in the input
581 * sequence (includes the first class) */
582 USHORT input[]; /* Array of input classes(start with
583 * second class; to be matched with
584 * the input glyph sequence) */
585 USHORT lookaheadGlyphCount; /* Total number of classes in the
586 * look ahead sequence (number of
587 * classes to be matched after the
589 USHORT lookAhead[]; /* Array of lookahead classes(to be
590 * matched after the input sequence) */
591 USHORT substCount; /* Number of SubstLookupRecords */
592 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
595 DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8);
597 struct ChainContextSubstFormat3 {
601 USHORT substFormat; /* Format identifier--format = 3 */
602 USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking
604 Offset backtrackCoverage[]; /* Array of offsets to coverage tables
605 * in backtracking sequence, in glyph
607 USHORT inputGlyphCount; /* Number of glyphs in input sequence */
608 Offset inputCoverage[]; /* Array of offsets to coverage
609 * tables in input sequence, in glyph
611 USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead
613 Offset lookaheadCoverage[]; /* Array of offsets to coverage tables
614 * in lookahead sequence, in glyph
616 USHORT substCount; /* Number of SubstLookupRecords */
617 SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
620 ASSERT_SIZE (ChainContextSubstFormat3, 10);
622 struct ExtensionSubstFormat1 {
626 USHORT substFormat; /* Format identifier. Set to 1. */
627 USHORT extensionLookupType; /* Lookup type of subtable referenced
628 * by ExtensionOffset (i.e. the
629 * extension subtable). */
630 ULONG extensionOffset; /* Offset to the extension subtable,
631 * of lookup type subtable. */
633 ASSERT_SIZE (ExtensionSubstFormat1, 8);
635 struct ReverseChainSingleSubstFormat1 {
639 USHORT substFormat; /* Format identifier--format = 1 */
640 Offset coverage; /* Offset to Coverage table -- from
641 * beginning of Substitution table */
642 USHORT backtrackGlyphCount; /* Number of glyphs in the backtracking
644 Offset backtrackCoverage[]; /* Array of offsets to coverage tables
645 * in backtracking sequence, in glyph
647 USHORT lookaheadGlyphCount; /* Number of glyphs in lookahead
649 Offset lookaheadCoverage[]; /* Array of offsets to coverage tables
650 * in lookahead sequence, in glyph
652 USHORT glyphCount; /* Number of GlyphIDs in the Substitute
654 GlyphID substitute[]; /* Array of substitute
655 * GlyphIDs--ordered by Coverage Index */
657 ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
669 GSUB_ChainingContext = 6,
671 GSUB_ReverseChainingContextSingle = 8,
674 struct SubstLookupSubTable {
675 DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
677 friend struct SubstLookup;
679 unsigned int get_size (unsigned int lookup_type) const {
680 switch (lookup_type) {
681 // case 1: return u.format1.get_size ();
682 // case 2: return u.format2.get_size ();
689 case GSUB_ChainingContext:
691 case GSUB_ReverseChainingContextSingle:
693 default:return sizeof (LookupSubTable);
697 inline bool substitute (hb_ot_layout_t *layout,
699 unsigned int context_length,
700 unsigned int nesting_level_left,
701 unsigned int lookup_type,
702 unsigned int lookup_flag) const {
703 switch (lookup_type) {
704 case GSUB_Single: return SUBTABLE_SUBSTITUTE_CHAIN (u.singleSubst);
710 case GSUB_ChainingContext:
712 case GSUB_ReverseChainingContextSingle:
714 default:return false;
721 SingleSubst singleSubst;
725 struct SubstLookup : Lookup {
727 DEFINE_NON_INSTANTIABLE(SubstLookup);
729 inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
730 return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
733 /* Like get_type(), but looks through extension lookups.
734 * Never returns Extension */
735 inline unsigned int get_effective_type (void) const {
736 unsigned int type = get_type ();
738 if (HB_UNLIKELY (type == GSUB_Extension)) {
739 /* Return lookup type of first extension subtable.
740 * The spec says all of them should have the same type.
741 * XXX check for that somehow */
742 //XXX type = get_subtable(0).v.extension.get_type ();
748 inline bool is_reverse (void) const {
749 switch (get_effective_type ()) {
750 case GSUB_ReverseChainingContextSingle: return true;
751 default: return false;
755 inline bool substitute_once (hb_ot_layout_t *layout,
757 unsigned int context_length,
758 unsigned int nesting_level_left) const {
760 unsigned int lookup_type = get_type ();
761 unsigned int lookup_flag = get_flag ();
763 if (HB_UNLIKELY (nesting_level_left == 0))
765 nesting_level_left--;
767 for (unsigned int i = 0; i < get_subtable_count (); i++)
768 if (get_subtable (i).substitute (layout, buffer,
769 context_length, nesting_level_left,
770 lookup_type, lookup_flag))
776 inline bool substitute_string (hb_ot_layout_t *layout,
778 hb_ot_layout_feature_mask_t mask) const {
782 if (!is_reverse ()) {
784 /* in/out forward substitution */
785 _hb_buffer_clear_output (buffer);
787 while (buffer->in_pos < buffer->in_length) {
789 if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
790 substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
793 _hb_buffer_copy_output_glyph (buffer);
797 _hb_buffer_swap (buffer);
801 /* in-place backward substitution */
802 buffer->in_pos = buffer->in_length - 1;
805 if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
806 substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
811 } while (buffer->in_pos);
817 DEFINE_NULL_ALIAS (SubstLookup, Lookup);
823 struct GSUB : GSUBGPOS {
824 static const hb_tag_t Tag = HB_TAG ('G','S','U','B');
826 STATIC_DEFINE_GET_FOR_DATA (GSUB);
827 /* XXX check version here? */
829 inline const SubstLookup& get_lookup (unsigned int i) const {
830 return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
835 DEFINE_NULL_ALIAS (GSUB, GSUBGPOS);
838 #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */