[GSUB] Start Ligature subtable support
[framework/uifw/harfbuzz.git] / src / hb-ot-layout-gsub-private.h
1 /*
2  * Copyright (C) 2007,2008,2009  Red Hat, Inc.
3  *
4  *  This is part of HarfBuzz, an OpenType Layout engine library.
5  *
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.
11  *
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
16  * DAMAGE.
17  *
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.
23  *
24  * Red Hat Author(s): Behdad Esfahbod
25  */
26
27 #ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H
28 #define HB_OT_LAYOUT_GSUB_PRIVATE_H
29
30 #include "hb-ot-layout-private.h"
31
32 #include "hb-ot-layout-open-private.h"
33 #include "hb-ot-layout-gdef-private.h"
34
35 #include "harfbuzz-buffer-private.h" /* XXX */
36
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); \
41   }
42
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 \
50         layout, \
51         buffer, \
52         context_length, \
53         nesting_level_left, \
54         lookup_flag
55
56 struct SingleSubstFormat1 {
57
58   friend struct SingleSubst;
59
60   private:
61   DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
62   DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
63
64   inline bool single_substitute (hb_codepoint_t &glyph_id) const {
65
66     unsigned int index = get_glyph_coverage (glyph_id);
67     if (NOT_COVERED == index)
68       return false;
69
70     glyph_id += deltaGlyphID;
71
72     return true;
73   }
74
75   private:
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 */
81 };
82 ASSERT_SIZE (SingleSubstFormat1, 6);
83
84 struct SingleSubstFormat2 {
85
86   friend struct SingleSubst;
87
88   private:
89   DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
90   DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
91
92   inline bool single_substitute (hb_codepoint_t &glyph_id) const {
93
94     unsigned int index = get_glyph_coverage (glyph_id);
95
96     if (index >= glyphCount)
97       return false;
98
99     glyph_id = substitute[index];
100     return true;
101   }
102
103   private:
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
108                                          * array */
109   GlyphID       substitute[];           /* Array of substitute
110                                          * GlyphIDs--ordered by Coverage  Index */
111 };
112 ASSERT_SIZE (SingleSubstFormat2, 6);
113
114 struct SingleSubst {
115
116   friend struct SubstLookupSubTable;
117
118   private:
119
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);
125     }
126   }
127
128   inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
129
130     HB_UNUSED (nesting_level_left);
131
132     if (HB_UNLIKELY (context_length < 1))
133       return false;
134
135     unsigned int property;
136     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
137       return false;
138
139     hb_codepoint_t glyph_id = IN_CURGLYPH ();
140
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;
145     }
146
147     _hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
148
149     if ( _hb_ot_layout_has_new_glyph_classes (layout) )
150     {
151       /* we inherit the old glyph class to the substituted glyph */
152       _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
153     }
154
155     return true;
156   }
157
158   private:
159   union {
160   USHORT        substFormat;    /* Format identifier */
161   SingleSubstFormat1    format1;
162   SingleSubstFormat2    format2;
163   } u;
164 };
165 DEFINE_NULL (SingleSubst, 2);
166
167
168 struct Sequence {
169
170   friend struct MultipleSubstFormat1;
171
172   private:
173   /* GlyphID tables, in Coverage Index order */
174   DEFINE_OFFSET_ARRAY_TYPE (GlyphID, substitute, glyphCount);
175
176   inline void set_glyph_class (hb_ot_layout_t *layout, unsigned int property) const {
177
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);
181   }
182
183   private:
184   USHORT        glyphCount;             /* Number of GlyphIDs in the Substitute
185                                          * array. This should always  be
186                                          * greater than 0. */
187   GlyphID       substitute[];           /* String of GlyphIDs to substitute */
188 };
189 DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
190
191 struct MultipleSubstFormat1 {
192
193   friend struct MultipleSubst;
194
195   private:
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);
200
201   inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
202
203     HB_UNUSED (nesting_level_left);
204
205     if (HB_UNLIKELY (context_length < 1))
206       return false;
207
208     unsigned int property;
209     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
210       return false;
211
212     hb_codepoint_t glyph_id = IN_CURGLYPH ();
213
214     unsigned int index = get_glyph_coverage (glyph_id);
215
216     const Sequence &seq = (*this)[index];
217
218     if (HB_UNLIKELY (!seq.get_len ()))
219       return false;
220
221     _hb_buffer_add_output_glyph_ids (buffer, 1,
222                                      seq.glyphCount, seq.substitute,
223                                      0xFFFF, 0xFFFF);
224
225     if ( _hb_ot_layout_has_new_glyph_classes (layout) )
226     {
227       /* this is a guess only ... */
228
229       if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
230         property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
231
232       seq.set_glyph_class (layout, property);
233     }
234
235     return true;
236   }
237
238   private:
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
247                                          * Coverage Index */
248 };
249 ASSERT_SIZE (MultipleSubstFormat1, 6);
250
251 struct MultipleSubst {
252
253   friend struct SubstLookupSubTable;
254
255   private:
256
257   unsigned int get_size (void) const {
258     switch (u.substFormat) {
259     case 1: return sizeof (u.format1);
260     default:return sizeof (u.substFormat);
261     }
262   }
263
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;
268     }
269   }
270
271   private:
272   union {
273   USHORT        substFormat;    /* Format identifier */
274   MultipleSubstFormat1  format1;
275   } u;
276 };
277 DEFINE_NULL (MultipleSubst, 2);
278
279
280 struct AlternateSet {
281
282   /* GlyphIDs, in no particular order */
283   DEFINE_ARRAY_TYPE (GlyphID, alternate, glyphCount);
284
285   private:
286   USHORT        glyphCount;             /* Number of GlyphIDs in the Alternate
287                                          * array */
288   GlyphID       alternate[];            /* Array of alternate GlyphIDs--in
289                                          * arbitrary order */
290 };
291 DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
292
293 struct AlternateSubstFormat1 {
294
295   friend struct AlternateSubst;
296
297   private:
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);
302
303   inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
304
305     HB_UNUSED (nesting_level_left);
306
307     if (HB_UNLIKELY (context_length < 1))
308       return false;
309
310     unsigned int property;
311     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
312       return false;
313
314     hb_codepoint_t glyph_id = IN_CURGLYPH ();
315
316     unsigned int index = get_glyph_coverage (glyph_id);
317
318     const AlternateSet &alt_set = (*this)[index];
319
320     if (HB_UNLIKELY (!alt_set.get_len ()))
321       return false;
322
323     unsigned int alt_index = 0;
324
325     /* XXX callback to user to choose alternate
326     if ( gsub->altfunc )
327       alt_index = (gsub->altfunc)( buffer->out_pos, glyph_id,
328                                    aset.GlyphCount, aset.Alternate,
329                                    gsub->data );
330                                    */
331
332     if (HB_UNLIKELY (alt_index >= alt_set.get_len ()))
333       return false;
334
335     glyph_id = alt_set[alt_index];
336
337     _hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
338
339     if ( _hb_ot_layout_has_new_glyph_classes (layout) )
340     {
341       /* we inherit the old glyph class to the substituted glyph */
342       _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
343     }
344
345     return true;
346   }
347
348   private:
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
356                                          * Coverage Index */
357 };
358 ASSERT_SIZE (AlternateSubstFormat1, 6);
359
360 struct AlternateSubst {
361
362   friend struct SubstLookupSubTable;
363
364   private:
365
366   unsigned int get_size (void) const {
367     switch (u.substFormat) {
368     case 1: return sizeof (u.format1);
369     default:return sizeof (u.substFormat);
370     }
371   }
372
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;
377     }
378   }
379
380   private:
381   union {
382   USHORT        substFormat;    /* Format identifier */
383   AlternateSubstFormat1 format1;
384   } u;
385 };
386 DEFINE_NULL (AlternateSubst, 2);
387
388
389 struct Ligature {
390   /* TODO */
391
392   private:
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 */
398 };
399 DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
400
401 struct LigatureSet {
402   /* TODO */
403
404   private:
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
409                                          * preference */
410 };
411 DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
412
413 struct LigatureSubstFormat1 {
414
415   friend struct LigatureSubst;
416
417   private:
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);
422
423   inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
424
425     HB_UNUSED (nesting_level_left);
426
427     unsigned int property;
428     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
429       return false;
430
431     hb_codepoint_t glyph_id = IN_CURGLYPH ();
432
433     unsigned int index = get_glyph_coverage (glyph_id);
434
435     const LigatureSet &lig_set = (*this)[index];
436
437     bool first_is_mark = (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK ||
438                           property &  LookupFlag::MarkAttachmentType);
439
440     unsigned int num_sets = get_len ();
441     for (unsigned int i = 0; i < num_sets; i++) {
442
443       const LigatureSet &lig_set = (*this)[i];
444
445
446     }
447
448     return false;
449   }
450
451   private:
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
459                                          * Coverage Index */
460 };
461 ASSERT_SIZE (LigatureSubstFormat1, 6);
462
463 struct LigatureSubst {
464
465   friend struct SubstLookupSubTable;
466
467   private:
468
469   unsigned int get_size (void) const {
470     switch (u.substFormat) {
471     case 1: return sizeof (u.format1);
472     default:return sizeof (u.substFormat);
473     }
474   }
475
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;
480     }
481   }
482
483   private:
484   union {
485   USHORT        substFormat;    /* Format identifier */
486   LigatureSubstFormat1  format1;
487   } u;
488 };
489 DEFINE_NULL (LigatureSubst, 2);
490
491
492 struct SubstLookupRecord {
493   /* TODO */
494
495   private:
496   USHORT        sequenceIndex;          /* Index into current glyph
497                                          * sequence--first glyph = 0 */
498   USHORT        lookupListIndex;        /* Lookup to apply to that
499                                          * position--zero--based */
500 };
501 DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4);
502
503 struct ContextSubstFormat1 {
504   /* TODO */
505
506   private:
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
515                                          * Coverage Index */
516 };
517 ASSERT_SIZE (ContextSubstFormat1, 6);
518
519 struct SubRuleSet {
520   /* TODO */
521
522   private:
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 */
527 };
528 DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2);
529
530 struct SubRule {
531   /* TODO */
532
533   private:
534   USHORT        glyphCount;             /* Total number of glyphs in input
535                                          * glyph sequence--includes the  first
536                                          * glyph */
537   USHORT        substCount;             /* Number of SubstLookupRecords */
538   GlyphID       input[];                /* Array of input GlyphIDs--start with
539                                          * second glyph */
540   SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
541                                          * design order */
542 };
543 DEFINE_NULL_ASSERT_SIZE (SubRule, 4);
544
545 struct ContextSubstFormat2 {
546   /* TODO */
547
548   private:
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 */
559 };
560 ASSERT_SIZE (ContextSubstFormat2, 8);
561
562 struct SubClassSet {
563   /* TODO */
564
565   private:
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 */
570 };
571 DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2);
572
573 struct SubClassRule {
574   /* TODO */
575
576   private:
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
585                                          * design order */
586 };
587 DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4);
588
589 struct ContextSubstFormat3 {
590   /* TODO */
591
592   private:
593   USHORT        substFormat;            /* Format identifier--format = 3 */
594   USHORT        glyphCount;             /* Number of glyphs in the input glyph
595                                          * sequence */
596   USHORT        substCount;             /* Number of SubstLookupRecords */
597   Offset        coverage[];             /* Array of offsets to Coverage
598                                          * table--from beginning of
599                                          * Substitution table--in glyph
600                                          * sequence order */
601   SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
602                                          * design order */
603 };
604 ASSERT_SIZE (ContextSubstFormat3, 6);
605
606 struct ChainContextSubstFormat1 {
607   /* TODO */
608
609   private:
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
615                                          * Coverage table */
616   Offset        chainSubRuleSet[];      /* Array of offsets to ChainSubRuleSet
617                                          * tables--from beginning of
618                                          * Substitution table--ordered by
619                                          * Coverage Index */
620 };
621 ASSERT_SIZE (ChainContextSubstFormat1, 6);
622
623 struct ChainSubRuleSet {
624   /* TODO */
625
626   private:
627   USHORT        chainSubRuleCount;      /* Number of ChainSubRule tables */
628   Offset        chainSubRule[];         /* Array of offsets to ChainSubRule
629                                          * tables--from beginning of
630                                          * ChainSubRuleSet table--ordered
631                                          * by preference */
632 };
633 DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2);
634
635 struct ChainSubRule {
636   /* TODO */
637
638   private:
639   USHORT        backtrackGlyphCount;    /* Total number of glyphs in the
640                                          * backtrack sequence (number of
641                                          * glyphs to be matched before the
642                                          * first glyph) */
643   GlyphID       backtrack[];            /* Array of backtracking GlyphID's
644                                          * (to be matched before the input
645                                          * sequence) */
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
649                                          * second glyph) */
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
657                                          * design order) */
658 };
659 DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8);
660
661 struct ChainContextSubstFormat2 {
662   /* TODO */
663
664   private:
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
671                                          * table */
672   Offset        inputClassDef;          /* Offset to glyph ClassDef
673                                          * table containing input sequence
674                                          * data--from beginning of Substitution
675                                          * table */
676   Offset        lookaheadClassDef;      /* Offset to glyph ClassDef table
677                                          * containing lookahead sequence
678                                          * data--from beginning of Substitution
679                                          * table */
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 */
685 };
686 ASSERT_SIZE (ChainContextSubstFormat2, 12);
687
688 struct ChainSubClassSet {
689   /* TODO */
690
691   private:
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
697                                          * preference */
698 };
699 DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2);
700
701 struct ChainSubClassRule {
702   /* TODO */
703
704   private:
705   USHORT        backtrackGlyphCount;    /* Total number of glyphs in the
706                                          * backtrack sequence (number of
707                                          * glyphs to be matched before the
708                                          * first glyph) */
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
719                                          * input sequence) */
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
724                                          * design order) */
725 };
726 DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8);
727
728 struct ChainContextSubstFormat3 {
729   /* TODO */
730
731   private:
732   USHORT        substFormat;            /* Format identifier--format = 3 */
733   USHORT        backtrackGlyphCount;    /* Number of glyphs in the backtracking
734                                          * sequence */
735   Offset        backtrackCoverage[];    /* Array of offsets to coverage tables
736                                          * in backtracking sequence, in  glyph
737                                          * sequence order */
738   USHORT        inputGlyphCount;        /* Number of glyphs in input sequence */
739   Offset        inputCoverage[];        /* Array of offsets to coverage
740                                          * tables in input sequence, in glyph
741                                          * sequence order */
742   USHORT        lookaheadGlyphCount;    /* Number of glyphs in lookahead
743                                          * sequence */
744   Offset        lookaheadCoverage[];    /* Array of offsets to coverage tables
745                                          * in lookahead sequence, in  glyph
746                                          * sequence order */
747   USHORT        substCount;             /* Number of SubstLookupRecords */
748   SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
749                                          * design order */
750 };
751 ASSERT_SIZE (ChainContextSubstFormat3, 10);
752
753
754 struct ExtensionSubstFormat1 {
755
756   friend struct ExtensionSubst;
757
758   private:
759   inline unsigned int get_type (void) const { return extensionLookupType; }
760   inline bool substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const;
761
762   private:
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. */
769 };
770 ASSERT_SIZE (ExtensionSubstFormat1, 8);
771
772 struct ExtensionSubst {
773
774   friend struct SubstLookup;
775   friend struct SubstLookupSubTable;
776
777   private:
778
779   unsigned int get_size (void) const {
780     switch (u.substFormat) {
781     case 1: return sizeof (u.format1);
782     default:return sizeof (u.substFormat);
783     }
784   }
785
786   inline unsigned int get_type (void) const {
787     switch (u.substFormat) {
788     case 1: return u.format1.get_type ();
789     default:return 0;
790     }
791   }
792
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;
797     }
798   }
799
800   private:
801   union {
802   USHORT        substFormat;    /* Format identifier */
803   ExtensionSubstFormat1 format1;
804   } u;
805 };
806 DEFINE_NULL (ExtensionSubst, 2);
807
808
809
810 struct ReverseChainSingleSubstFormat1 {
811   /* TODO */
812
813   private:
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
818                                          * sequence */
819   Offset        backtrackCoverage[];    /* Array of offsets to coverage tables
820                                          * in backtracking sequence, in  glyph
821                                          * sequence order */
822   USHORT        lookaheadGlyphCount;    /* Number of glyphs in lookahead
823                                          * sequence */
824   Offset        lookaheadCoverage[];    /* Array of offsets to coverage tables
825                                          * in lookahead sequence, in  glyph
826                                          * sequence order */
827   USHORT        glyphCount;             /* Number of GlyphIDs in the Substitute
828                                          * array */
829   GlyphID       substitute[];           /* Array of substitute
830                                          * GlyphIDs--ordered by Coverage  Index */
831 };
832 ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
833
834 /*
835  * SubstLookup
836  */
837
838 enum {
839   GSUB_Single                           = 1,
840   GSUB_Multiple                         = 2,
841   GSUB_Alternate                        = 3,
842   GSUB_Ligature                         = 4,
843   GSUB_Context                          = 5,
844   GSUB_ChainingContext                  = 6,
845   GSUB_Extension                        = 7,
846   GSUB_ReverseChainingContextSingle     = 8,
847 };
848
849 struct SubstLookupSubTable {
850   DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
851
852   friend struct SubstLookup;
853
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 ();
860    /*
861     case GSUB_Context:
862     case GSUB_ChainingContext:
863    */
864     case GSUB_Extension:                        return u.extension.get_size ();
865  /*
866     case GSUB_ReverseChainingContextSingle:
867   */
868     default:return sizeof (LookupSubTable);
869     }
870   }
871
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);
879     /*
880     case GSUB_Context:                          return u.context.substitute (SUBTABLE_SUBSTITUTE_ARGS);
881     case GSUB_ChainingContext:                  return u.chainingContext.substitute (SUBTABLE_SUBSTITUTE_ARGS);
882     */
883     case GSUB_Extension:                        return u.extension.substitute (SUBTABLE_SUBSTITUTE_ARGS);
884                         /*
885     case GSUB_ReverseChainingContextSingle:     return u.reverseChainingContextSingle.substitute (SUBTABLE_SUBSTITUTE_ARGS);
886     */
887     default:return false;
888     }
889   }
890
891   private:
892   union {
893   USHORT                                substFormat;
894   SingleSubst                           single;
895   MultipleSubst                         multiple;
896   AlternateSubst                        alternate;
897   LigatureSubst                         ligature;
898   /*
899   ContextSubst                          context;
900   ChainingContextSubst                  chainingContext;
901   */
902   ExtensionSubst                        extension;
903   /*
904   ReverseChainingContextSingleSubst     reverseChainingContextSingle;
905   */
906   } u;
907 };
908
909
910 /* Out-of-class implementation for methods chaining */
911
912 inline bool ExtensionSubstFormat1::substitute (SUBTABLE_SUBSTITUTE_ARGS_DEF) const {
913   return (*(SubstLookupSubTable *)(((char *) this) + extensionOffset)).substitute (SUBTABLE_SUBSTITUTE_ARGS,
914                                                                                    get_type ());
915 }
916
917
918
919 struct SubstLookup : Lookup {
920
921   DEFINE_NON_INSTANTIABLE(SubstLookup);
922
923   inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
924     return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
925   }
926
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 ();
931
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 ();
937     }
938
939     return type;
940   }
941
942   inline bool is_reverse (void) const {
943     switch (get_effective_type ()) {
944     case GSUB_ReverseChainingContextSingle:     return true;
945     default:                                    return false;
946     }
947   }
948
949   bool substitute_once (hb_ot_layout_t *layout,
950                         hb_buffer_t    *buffer,
951                         unsigned int    context_length,
952                         unsigned int    nesting_level_left) const {
953
954     unsigned int lookup_type = get_type ();
955     unsigned int lookup_flag = get_flag ();
956
957     if (HB_UNLIKELY (nesting_level_left == 0))
958       return false;
959     nesting_level_left--;
960
961     for (unsigned int i = 0; i < get_subtable_count (); i++)
962       if (get_subtable (i).substitute (SUBTABLE_SUBSTITUTE_ARGS,
963                                        lookup_type))
964         return true;
965
966     return false;
967   }
968
969   bool substitute_string (hb_ot_layout_t *layout,
970                           hb_buffer_t    *buffer,
971                           hb_ot_layout_feature_mask_t mask) const {
972
973     bool ret = false;
974
975     if (HB_LIKELY (!is_reverse ())) {
976
977         /* in/out forward substitution */
978         _hb_buffer_clear_output (buffer);
979         buffer->in_pos = 0;
980         while (buffer->in_pos < buffer->in_length) {
981
982           if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
983               substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
984             ret = true;
985           else
986             _hb_buffer_copy_output_glyph (buffer);
987
988         }
989         if (ret)
990           _hb_buffer_swap (buffer);
991
992     } else {
993
994         /* in-place backward substitution */
995         buffer->in_pos = buffer->in_length - 1;
996         do {
997
998           if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
999               substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
1000             ret = true;
1001           else
1002             buffer->in_pos--;
1003
1004         } while ((int) buffer->in_pos >= 0);
1005     }
1006
1007     return ret;
1008   }
1009 };
1010 DEFINE_NULL_ALIAS (SubstLookup, Lookup);
1011
1012 /*
1013  * GSUB
1014  */
1015
1016 struct GSUB : GSUBGPOS {
1017   static const hb_tag_t Tag             = HB_TAG ('G','S','U','B');
1018
1019   STATIC_DEFINE_GET_FOR_DATA (GSUB);
1020   /* XXX check version here? */
1021
1022   inline const SubstLookup& get_lookup (unsigned int i) const {
1023     return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
1024   }
1025
1026
1027 };
1028 DEFINE_NULL_ALIAS (GSUB, GSUBGPOS);
1029
1030
1031 #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */