[GSUB] Fix reverse lookup loop like we did in the old code before
[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 \
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, \
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;
67
68     index = get_glyph_coverage (glyph_id);
69     if (NOT_COVERED == index)
70       return false;
71
72     glyph_id += deltaGlyphID;
73
74     return true;
75   }
76
77 #if 0
78
79   case 2:
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 ) )
84       return error;
85     break;
86 #endif
87
88   private:
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 */
94 };
95 ASSERT_SIZE (SingleSubstFormat1, 6);
96
97 struct SingleSubstFormat2 {
98
99   friend struct SingleSubst;
100
101   private:
102   DEFINE_GET_ACCESSOR (Coverage, coverage, coverage);
103   DEFINE_GET_GLYPH_COVERAGE (glyph_coverage);
104
105   inline bool single_substitute (hb_codepoint_t &glyph_id) const {
106
107     unsigned int index;
108
109     index = get_glyph_coverage (glyph_id);
110
111     if (index >= glyphCount)
112       return false;
113
114     glyph_id = substitute[index];
115     return true;
116   }
117
118   private:
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
123                                          * array */
124   GlyphID       substitute[];           /* Array of substitute
125                                          * GlyphIDs--ordered by Coverage  Index */
126 };
127 ASSERT_SIZE (SingleSubstFormat2, 6);
128
129 struct SingleSubst {
130
131   friend struct SubstLookupSubTable;
132
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);
138     }
139   }
140
141   private:
142   inline SUBTABLE_SUBSTITUTE {
143
144     hb_codepoint_t glyph_id;
145     unsigned int property;
146
147     HB_UNUSED (nesting_level_left);
148
149     if (HB_UNLIKELY (context_length < 1))
150       return false;
151
152     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
153       return false;
154
155     glyph_id = IN_CURGLYPH ();
156
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;
161     }
162
163     _hb_buffer_replace_output_glyph (buffer, glyph_id, context_length == NO_CONTEXT);
164
165     if ( _hb_ot_layout_has_new_glyph_classes (layout) )
166     {
167       /* we inherit the old glyph class to the substituted glyph */
168       _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
169     }
170
171     return true;
172   }
173
174   private:
175   union {
176   USHORT        substFormat;    /* Format identifier */
177   SingleSubstFormat1    format1;
178   SingleSubstFormat2    format2;
179   } u;
180 };
181 DEFINE_NULL (SingleSubst, 2);
182
183
184 struct Sequence {
185
186   friend struct MultipleSubstFormat1;
187
188   private:
189   /* GlyphID tables, in Coverage Index order */
190   DEFINE_OFFSET_ARRAY_TYPE (GlyphID, substitute, glyphCount);
191
192   inline void set_glyph_class (hb_ot_layout_t *layout, unsigned int property) const {
193     unsigned int n, count = glyphCount;
194
195     for (n = 0; n < count; n++)
196       _hb_ot_layout_set_glyph_property (layout, substitute[n], property);
197   }
198
199   private:
200   USHORT        glyphCount;             /* Number of GlyphIDs in the Substitute
201                                          * array. This should always  be
202                                          * greater than 0. */
203   GlyphID       substitute[];           /* String of GlyphIDs to substitute */
204 };
205 DEFINE_NULL_ASSERT_SIZE (Sequence, 2);
206
207 struct MultipleSubstFormat1 {
208
209   friend struct MultipleSubst;
210
211   private:
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);
216
217   inline SUBTABLE_SUBSTITUTE {
218
219     hb_codepoint_t glyph_id;
220     unsigned int index;
221     unsigned int property;
222
223     HB_UNUSED (nesting_level_left);
224
225     if (HB_UNLIKELY (context_length < 1))
226       return false;
227
228     if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
229       return false;
230
231     glyph_id = IN_CURGLYPH ();
232
233     index = get_glyph_coverage (glyph_id);
234     if (index >= sequenceCount)
235       return false;
236
237     const Sequence &seq = (*this)[index];
238     _hb_buffer_add_output_glyph_ids (buffer, 1,
239                                      seq.glyphCount, seq.substitute,
240                                      0xFFFF, 0xFFFF);
241
242     if ( _hb_ot_layout_has_new_glyph_classes (layout) )
243     {
244       /* this is a guess only ... */
245
246       if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
247         property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
248
249       seq.set_glyph_class (layout, property);
250     }
251
252     return true;
253   }
254
255   private:
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
264                                          * Coverage Index */
265 };
266 ASSERT_SIZE (MultipleSubstFormat1, 6);
267
268 struct MultipleSubst {
269
270   unsigned int get_size (void) const {
271     switch (u.substFormat) {
272     case 1: return sizeof (u.format1);
273     default:return sizeof (u.substFormat);
274     }
275   }
276
277   private:
278   inline SUBTABLE_SUBSTITUTE {
279     switch (u.substFormat) {
280     case 1: return SUBTABLE_SUBSTITUTE_CHAIN(u.format1);
281     default:return false;
282     }
283   }
284
285   private:
286   union {
287   USHORT        substFormat;    /* Format identifier */
288   MultipleSubstFormat1  format1;
289   } u;
290 };
291 DEFINE_NULL (MultipleSubst, 2);
292
293
294 struct AlternateSet {
295   /* TODO */
296
297   private:
298   USHORT        glyphCount;             /* Number of GlyphIDs in the Alternate
299                                          * array */
300   GlyphID       alternate[];            /* Array of alternate GlyphIDs--in
301                                          * arbitrary order */
302 };
303 DEFINE_NULL_ASSERT_SIZE (AlternateSet, 2);
304
305 struct AlternateSubstFormat1 {
306   /* TODO */
307
308   private:
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
316                                          * Coverage Index */
317 };
318 ASSERT_SIZE (AlternateSubstFormat1, 6);
319
320
321 struct Ligature {
322   /* TODO */
323
324   private:
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 */
330 };
331 DEFINE_NULL_ASSERT_SIZE (Ligature, 4);
332
333 struct LigatureSet {
334   /* TODO */
335
336   private:
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
341                                          * preference */
342 };
343 DEFINE_NULL_ASSERT_SIZE (LigatureSet, 2);
344
345 struct LigatureSubstFormat1 {
346   /* TODO */
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        ligSetCount;            /* Number of LigatureSet tables */
353   Offset        ligatureSet[];          /* Array of offsets to LigatureSet
354                                          * tables--from beginning of
355                                          * Substitution table--ordered by
356                                          * Coverage Index */
357 };
358 ASSERT_SIZE (LigatureSubstFormat1, 6);
359
360
361 struct SubstLookupRecord {
362   /* TODO */
363
364   private:
365   USHORT        sequenceIndex;          /* Index into current glyph
366                                          * sequence--first glyph = 0 */
367   USHORT        lookupListIndex;        /* Lookup to apply to that
368                                          * position--zero--based */
369 };
370 DEFINE_NULL_ASSERT_SIZE (SubstLookupRecord, 4);
371
372 struct ContextSubstFormat1 {
373   /* TODO */
374
375   private:
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
384                                          * Coverage Index */
385 };
386 ASSERT_SIZE (ContextSubstFormat1, 6);
387
388 struct SubRuleSet {
389   /* TODO */
390
391   private:
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 */
396 };
397 DEFINE_NULL_ASSERT_SIZE (SubRuleSet, 2);
398
399 struct SubRule {
400   /* TODO */
401
402   private:
403   USHORT        glyphCount;             /* Total number of glyphs in input
404                                          * glyph sequence--includes the  first
405                                          * glyph */
406   USHORT        substCount;             /* Number of SubstLookupRecords */
407   GlyphID       input[];                /* Array of input GlyphIDs--start with
408                                          * second glyph */
409   SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
410                                          * design order */
411 };
412 DEFINE_NULL_ASSERT_SIZE (SubRule, 4);
413
414 struct ContextSubstFormat2 {
415   /* TODO */
416
417   private:
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 */
428 };
429 ASSERT_SIZE (ContextSubstFormat2, 8);
430
431 struct SubClassSet {
432   /* TODO */
433
434   private:
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 */
439 };
440 DEFINE_NULL_ASSERT_SIZE (SubClassSet, 2);
441
442 struct SubClassRule {
443   /* TODO */
444
445   private:
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
454                                          * design order */
455 };
456 DEFINE_NULL_ASSERT_SIZE (SubClassRule, 4);
457
458 struct ContextSubstFormat3 {
459   /* TODO */
460
461   private:
462   USHORT        substFormat;            /* Format identifier--format = 3 */
463   USHORT        glyphCount;             /* Number of glyphs in the input glyph
464                                          * sequence */
465   USHORT        substCount;             /* Number of SubstLookupRecords */
466   Offset        coverage[];             /* Array of offsets to Coverage
467                                          * table--from beginning of
468                                          * Substitution table--in glyph
469                                          * sequence order */
470   SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
471                                          * design order */
472 };
473 ASSERT_SIZE (ContextSubstFormat3, 6);
474
475 struct ChainContextSubstFormat1 {
476   /* TODO */
477
478   private:
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
484                                          * Coverage table */
485   Offset        chainSubRuleSet[];      /* Array of offsets to ChainSubRuleSet
486                                          * tables--from beginning of
487                                          * Substitution table--ordered by
488                                          * Coverage Index */
489 };
490 ASSERT_SIZE (ChainContextSubstFormat1, 6);
491
492 struct ChainSubRuleSet {
493   /* TODO */
494
495   private:
496   USHORT        chainSubRuleCount;      /* Number of ChainSubRule tables */
497   Offset        chainSubRule[];         /* Array of offsets to ChainSubRule
498                                          * tables--from beginning of
499                                          * ChainSubRuleSet table--ordered
500                                          * by preference */
501 };
502 DEFINE_NULL_ASSERT_SIZE (ChainSubRuleSet, 2);
503
504 struct ChainSubRule {
505   /* TODO */
506
507   private:
508   USHORT        backtrackGlyphCount;    /* Total number of glyphs in the
509                                          * backtrack sequence (number of
510                                          * glyphs to be matched before the
511                                          * first glyph) */
512   GlyphID       backtrack[];            /* Array of backtracking GlyphID's
513                                          * (to be matched before the input
514                                          * sequence) */
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
518                                          * second glyph) */
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
526                                          * design order) */
527 };
528 DEFINE_NULL_ASSERT_SIZE (ChainSubRule, 8);
529
530 struct ChainContextSubstFormat2 {
531   /* TODO */
532
533   private:
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
540                                          * table */
541   Offset        inputClassDef;          /* Offset to glyph ClassDef
542                                          * table containing input sequence
543                                          * data--from beginning of Substitution
544                                          * table */
545   Offset        lookaheadClassDef;      /* Offset to glyph ClassDef table
546                                          * containing lookahead sequence
547                                          * data--from beginning of Substitution
548                                          * table */
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 */
554 };
555 ASSERT_SIZE (ChainContextSubstFormat2, 12);
556
557 struct ChainSubClassSet {
558   /* TODO */
559
560   private:
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
566                                          * preference */
567 };
568 DEFINE_NULL_ASSERT_SIZE (ChainSubClassSet, 2);
569
570 struct ChainSubClassRule {
571   /* TODO */
572
573   private:
574   USHORT        backtrackGlyphCount;    /* Total number of glyphs in the
575                                          * backtrack sequence (number of
576                                          * glyphs to be matched before the
577                                          * first glyph) */
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
588                                          * input sequence) */
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
593                                          * design order) */
594 };
595 DEFINE_NULL_ASSERT_SIZE (ChainSubClassRule, 8);
596
597 struct ChainContextSubstFormat3 {
598   /* TODO */
599
600   private:
601   USHORT        substFormat;            /* Format identifier--format = 3 */
602   USHORT        backtrackGlyphCount;    /* Number of glyphs in the backtracking
603                                          * sequence */
604   Offset        backtrackCoverage[];    /* Array of offsets to coverage tables
605                                          * in backtracking sequence, in  glyph
606                                          * sequence order */
607   USHORT        inputGlyphCount;        /* Number of glyphs in input sequence */
608   Offset        inputCoverage[];        /* Array of offsets to coverage
609                                          * tables in input sequence, in glyph
610                                          * sequence order */
611   USHORT        lookaheadGlyphCount;    /* Number of glyphs in lookahead
612                                          * sequence */
613   Offset        lookaheadCoverage[];    /* Array of offsets to coverage tables
614                                          * in lookahead sequence, in  glyph
615                                          * sequence order */
616   USHORT        substCount;             /* Number of SubstLookupRecords */
617   SubstLookupRecord substLookupRecord[];/* Array of SubstLookupRecords--in
618                                          * design order */
619 };
620 ASSERT_SIZE (ChainContextSubstFormat3, 10);
621
622 struct ExtensionSubstFormat1 {
623   /* TODO */
624
625   private:
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. */
632 };
633 ASSERT_SIZE (ExtensionSubstFormat1, 8);
634
635 struct ReverseChainSingleSubstFormat1 {
636   /* TODO */
637
638   private:
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
643                                          * sequence */
644   Offset        backtrackCoverage[];    /* Array of offsets to coverage tables
645                                          * in backtracking sequence, in  glyph
646                                          * sequence order */
647   USHORT        lookaheadGlyphCount;    /* Number of glyphs in lookahead
648                                          * sequence */
649   Offset        lookaheadCoverage[];    /* Array of offsets to coverage tables
650                                          * in lookahead sequence, in  glyph
651                                          * sequence order */
652   USHORT        glyphCount;             /* Number of GlyphIDs in the Substitute
653                                          * array */
654   GlyphID       substitute[];           /* Array of substitute
655                                          * GlyphIDs--ordered by Coverage  Index */
656 };
657 ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
658
659 /*
660  * SubstLookup
661  */
662
663 enum {
664   GSUB_Single                           = 1,
665   GSUB_Multiple                         = 2,
666   GSUB_Alternate                                = 3,
667   GSUB_Ligature                         = 4,
668   GSUB_Context                          = 5,
669   GSUB_ChainingContext                  = 6,
670   GSUB_Extension                                = 7,
671   GSUB_ReverseChainingContextSingle             = 8,
672 };
673
674 struct SubstLookupSubTable {
675   DEFINE_NON_INSTANTIABLE(SubstLookupSubTable);
676
677   friend struct SubstLookup;
678
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 ();
683     /*
684     case GSUB_Single:
685     case GSUB_Multiple:
686     case GSUB_Alternate:
687     case GSUB_Ligature:
688     case GSUB_Context:
689     case GSUB_ChainingContext:
690     case GSUB_Extension:
691     case GSUB_ReverseChainingContextSingle:
692     */
693     default:return sizeof (LookupSubTable);
694     }
695   }
696
697   inline bool substitute (hb_ot_layout_t *layout,
698                           hb_buffer_t    *buffer,
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);
705     /*
706     case GSUB_Multiple:
707     case GSUB_Alternate:
708     case GSUB_Ligature:
709     case GSUB_Context:
710     case GSUB_ChainingContext:
711     case GSUB_Extension:
712     case GSUB_ReverseChainingContextSingle:
713     */
714     default:return false;
715     }
716   }
717
718   private:
719   union {
720   USHORT                substFormat;
721   SingleSubst           singleSubst;
722   } u;
723 };
724
725 struct SubstLookup : Lookup {
726
727   DEFINE_NON_INSTANTIABLE(SubstLookup);
728
729   inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
730     return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
731   }
732
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 ();
737
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 ();
743     }
744
745     return type;
746   }
747
748   inline bool is_reverse (void) const {
749     switch (get_effective_type ()) {
750     case GSUB_ReverseChainingContextSingle:     return true;
751     default:                                    return false;
752     }
753   }
754
755   inline bool substitute_once (hb_ot_layout_t *layout,
756                                hb_buffer_t    *buffer,
757                                unsigned int    context_length,
758                                unsigned int    nesting_level_left) const {
759
760     unsigned int lookup_type = get_type ();
761     unsigned int lookup_flag = get_flag ();
762
763     if (HB_UNLIKELY (nesting_level_left == 0))
764       return false;
765     nesting_level_left--;
766
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))
771         return true;
772
773     return false;
774   }
775
776   inline bool substitute_string (hb_ot_layout_t *layout,
777                                  hb_buffer_t    *buffer,
778                                  hb_ot_layout_feature_mask_t mask) const {
779
780     bool ret = false;
781
782     if (!is_reverse ()) {
783
784         /* in/out forward substitution */
785         _hb_buffer_clear_output (buffer);
786         buffer->in_pos = 0;
787         while (buffer->in_pos < buffer->in_length) {
788
789           if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
790               substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
791             ret = true;
792           else
793             _hb_buffer_copy_output_glyph (buffer);
794
795         }
796         if (ret)
797           _hb_buffer_swap (buffer);
798
799     } else {
800
801         /* in-place backward substitution */
802         buffer->in_pos = buffer->in_length - 1;
803         do {
804
805           if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
806               substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
807             ret = true;
808           else
809             buffer->in_pos--;
810
811         } while ((int) buffer->in_pos >= 0);
812     }
813
814     return ret;
815   }
816 };
817 DEFINE_NULL_ALIAS (SubstLookup, Lookup);
818
819 /*
820  * GSUB
821  */
822
823 struct GSUB : GSUBGPOS {
824   static const hb_tag_t Tag             = HB_TAG ('G','S','U','B');
825
826   STATIC_DEFINE_GET_FOR_DATA (GSUB);
827   /* XXX check version here? */
828
829   inline const SubstLookup& get_lookup (unsigned int i) const {
830     return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
831   }
832
833
834 };
835 DEFINE_NULL_ALIAS (GSUB, GSUBGPOS);
836
837
838 #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */