Imported Upstream version 0.9.3
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-gsub-table.hh
1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2010,2012  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Red Hat Author(s): Behdad Esfahbod
26  * Google Author(s): Behdad Esfahbod
27  */
28
29 #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
30 #define HB_OT_LAYOUT_GSUB_TABLE_HH
31
32 #include "hb-ot-layout-gsubgpos-private.hh"
33
34
35
36 struct SingleSubstFormat1
37 {
38   friend struct SingleSubst;
39
40   private:
41
42   inline void closure (hb_closure_context_t *c) const
43   {
44     TRACE_CLOSURE ();
45     Coverage::Iter iter;
46     for (iter.init (this+coverage); iter.more (); iter.next ()) {
47       hb_codepoint_t glyph_id = iter.get_glyph ();
48       if (c->glyphs->has (glyph_id))
49         c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
50     }
51   }
52
53   inline const Coverage &get_coverage (void) const
54   {
55     return this+coverage;
56   }
57
58   inline bool apply (hb_apply_context_t *c) const
59   {
60     TRACE_APPLY ();
61     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
62     unsigned int index = (this+coverage) (glyph_id);
63     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
64
65     /* According to the Adobe Annotated OpenType Suite, result is always
66      * limited to 16bit. */
67     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
68     c->replace_glyph (glyph_id);
69
70     return TRACE_RETURN (true);
71   }
72
73   inline bool sanitize (hb_sanitize_context_t *c) {
74     TRACE_SANITIZE ();
75     return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
76   }
77
78   protected:
79   USHORT        format;                 /* Format identifier--format = 1 */
80   OffsetTo<Coverage>
81                 coverage;               /* Offset to Coverage table--from
82                                          * beginning of Substitution table */
83   SHORT         deltaGlyphID;           /* Add to original GlyphID to get
84                                          * substitute GlyphID */
85   public:
86   DEFINE_SIZE_STATIC (6);
87 };
88
89 struct SingleSubstFormat2
90 {
91   friend struct SingleSubst;
92
93   private:
94
95   inline void closure (hb_closure_context_t *c) const
96   {
97     TRACE_CLOSURE ();
98     Coverage::Iter iter;
99     for (iter.init (this+coverage); iter.more (); iter.next ()) {
100       if (c->glyphs->has (iter.get_glyph ()))
101         c->glyphs->add (substitute[iter.get_coverage ()]);
102     }
103   }
104
105   inline const Coverage &get_coverage (void) const
106   {
107     return this+coverage;
108   }
109
110   inline bool apply (hb_apply_context_t *c) const
111   {
112     TRACE_APPLY ();
113     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
114     unsigned int index = (this+coverage) (glyph_id);
115     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
116
117     if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
118
119     glyph_id = substitute[index];
120     c->replace_glyph (glyph_id);
121
122     return TRACE_RETURN (true);
123   }
124
125   inline bool sanitize (hb_sanitize_context_t *c) {
126     TRACE_SANITIZE ();
127     return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
128   }
129
130   protected:
131   USHORT        format;                 /* Format identifier--format = 2 */
132   OffsetTo<Coverage>
133                 coverage;               /* Offset to Coverage table--from
134                                          * beginning of Substitution table */
135   ArrayOf<GlyphID>
136                 substitute;             /* Array of substitute
137                                          * GlyphIDs--ordered by Coverage Index */
138   public:
139   DEFINE_SIZE_ARRAY (6, substitute);
140 };
141
142 struct SingleSubst
143 {
144   friend struct SubstLookupSubTable;
145
146   private:
147
148   inline void closure (hb_closure_context_t *c) const
149   {
150     TRACE_CLOSURE ();
151     switch (u.format) {
152     case 1: u.format1.closure (c); break;
153     case 2: u.format2.closure (c); break;
154     default:                       break;
155     }
156   }
157
158   inline const Coverage &get_coverage (void) const
159   {
160     switch (u.format) {
161     case 1: return u.format1.get_coverage ();
162     case 2: return u.format2.get_coverage ();
163     default:return Null(Coverage);
164     }
165   }
166
167   inline bool apply (hb_apply_context_t *c) const
168   {
169     TRACE_APPLY ();
170     switch (u.format) {
171     case 1: return TRACE_RETURN (u.format1.apply (c));
172     case 2: return TRACE_RETURN (u.format2.apply (c));
173     default:return TRACE_RETURN (false);
174     }
175   }
176
177   inline bool sanitize (hb_sanitize_context_t *c) {
178     TRACE_SANITIZE ();
179     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
180     switch (u.format) {
181     case 1: return TRACE_RETURN (u.format1.sanitize (c));
182     case 2: return TRACE_RETURN (u.format2.sanitize (c));
183     default:return TRACE_RETURN (true);
184     }
185   }
186
187   protected:
188   union {
189   USHORT                format;         /* Format identifier */
190   SingleSubstFormat1    format1;
191   SingleSubstFormat2    format2;
192   } u;
193 };
194
195
196 struct Sequence
197 {
198   friend struct MultipleSubstFormat1;
199
200   private:
201
202   inline void closure (hb_closure_context_t *c) const
203   {
204     TRACE_CLOSURE ();
205     unsigned int count = substitute.len;
206     for (unsigned int i = 0; i < count; i++)
207       c->glyphs->add (substitute[i]);
208   }
209
210   inline bool apply (hb_apply_context_t *c) const
211   {
212     TRACE_APPLY ();
213     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
214
215     unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
216     unsigned int count = substitute.len;
217     for (unsigned int i = 0; i < count; i++) {
218       set_lig_props_for_component (c->buffer->cur(), i);
219       c->output_glyph (substitute.array[i], klass);
220     }
221     c->buffer->skip_glyph ();
222
223     return TRACE_RETURN (true);
224   }
225
226   public:
227   inline bool sanitize (hb_sanitize_context_t *c) {
228     TRACE_SANITIZE ();
229     return TRACE_RETURN (substitute.sanitize (c));
230   }
231
232   protected:
233   ArrayOf<GlyphID>
234                 substitute;             /* String of GlyphIDs to substitute */
235   public:
236   DEFINE_SIZE_ARRAY (2, substitute);
237 };
238
239 struct MultipleSubstFormat1
240 {
241   friend struct MultipleSubst;
242
243   private:
244
245   inline void closure (hb_closure_context_t *c) const
246   {
247     TRACE_CLOSURE ();
248     Coverage::Iter iter;
249     for (iter.init (this+coverage); iter.more (); iter.next ()) {
250       if (c->glyphs->has (iter.get_glyph ()))
251         (this+sequence[iter.get_coverage ()]).closure (c);
252     }
253   }
254
255   inline const Coverage &get_coverage (void) const
256   {
257     return this+coverage;
258   }
259
260   inline bool apply (hb_apply_context_t *c) const
261   {
262     TRACE_APPLY ();
263
264     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
265     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
266
267     return TRACE_RETURN ((this+sequence[index]).apply (c));
268   }
269
270   inline bool sanitize (hb_sanitize_context_t *c) {
271     TRACE_SANITIZE ();
272     return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
273   }
274
275   protected:
276   USHORT        format;                 /* Format identifier--format = 1 */
277   OffsetTo<Coverage>
278                 coverage;               /* Offset to Coverage table--from
279                                          * beginning of Substitution table */
280   OffsetArrayOf<Sequence>
281                 sequence;               /* Array of Sequence tables
282                                          * ordered by Coverage Index */
283   public:
284   DEFINE_SIZE_ARRAY (6, sequence);
285 };
286
287 struct MultipleSubst
288 {
289   friend struct SubstLookupSubTable;
290
291   private:
292
293   inline void closure (hb_closure_context_t *c) const
294   {
295     TRACE_CLOSURE ();
296     switch (u.format) {
297     case 1: u.format1.closure (c); break;
298     default:                       break;
299     }
300   }
301
302   inline const Coverage &get_coverage (void) const
303   {
304     switch (u.format) {
305     case 1: return u.format1.get_coverage ();
306     default:return Null(Coverage);
307     }
308   }
309
310   inline bool apply (hb_apply_context_t *c) const
311   {
312     TRACE_APPLY ();
313     switch (u.format) {
314     case 1: return TRACE_RETURN (u.format1.apply (c));
315     default:return TRACE_RETURN (false);
316     }
317   }
318
319   inline bool sanitize (hb_sanitize_context_t *c) {
320     TRACE_SANITIZE ();
321     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
322     switch (u.format) {
323     case 1: return TRACE_RETURN (u.format1.sanitize (c));
324     default:return TRACE_RETURN (true);
325     }
326   }
327
328   protected:
329   union {
330   USHORT                format;         /* Format identifier */
331   MultipleSubstFormat1  format1;
332   } u;
333 };
334
335
336 typedef ArrayOf<GlyphID> AlternateSet;  /* Array of alternate GlyphIDs--in
337                                          * arbitrary order */
338
339 struct AlternateSubstFormat1
340 {
341   friend struct AlternateSubst;
342
343   private:
344
345   inline void closure (hb_closure_context_t *c) const
346   {
347     TRACE_CLOSURE ();
348     Coverage::Iter iter;
349     for (iter.init (this+coverage); iter.more (); iter.next ()) {
350       if (c->glyphs->has (iter.get_glyph ())) {
351         const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
352         unsigned int count = alt_set.len;
353         for (unsigned int i = 0; i < count; i++)
354           c->glyphs->add (alt_set[i]);
355       }
356     }
357   }
358
359   inline const Coverage &get_coverage (void) const
360   {
361     return this+coverage;
362   }
363
364   inline bool apply (hb_apply_context_t *c) const
365   {
366     TRACE_APPLY ();
367     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
368
369     unsigned int index = (this+coverage) (glyph_id);
370     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
371
372     const AlternateSet &alt_set = this+alternateSet[index];
373
374     if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
375
376     hb_mask_t glyph_mask = c->buffer->cur().mask;
377     hb_mask_t lookup_mask = c->lookup_mask;
378
379     /* Note: This breaks badly if two features enabled this lookup together. */
380     unsigned int shift = _hb_ctz (lookup_mask);
381     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
382
383     if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
384
385     glyph_id = alt_set[alt_index - 1];
386
387     c->replace_glyph (glyph_id);
388
389     return TRACE_RETURN (true);
390   }
391
392   inline bool sanitize (hb_sanitize_context_t *c) {
393     TRACE_SANITIZE ();
394     return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
395   }
396
397   protected:
398   USHORT        format;                 /* Format identifier--format = 1 */
399   OffsetTo<Coverage>
400                 coverage;               /* Offset to Coverage table--from
401                                          * beginning of Substitution table */
402   OffsetArrayOf<AlternateSet>
403                 alternateSet;           /* Array of AlternateSet tables
404                                          * ordered by Coverage Index */
405   public:
406   DEFINE_SIZE_ARRAY (6, alternateSet);
407 };
408
409 struct AlternateSubst
410 {
411   friend struct SubstLookupSubTable;
412
413   private:
414
415   inline void closure (hb_closure_context_t *c) const
416   {
417     TRACE_CLOSURE ();
418     switch (u.format) {
419     case 1: u.format1.closure (c); break;
420     default:                       break;
421     }
422   }
423
424   inline const Coverage &get_coverage (void) const
425   {
426     switch (u.format) {
427     case 1: return u.format1.get_coverage ();
428     default:return Null(Coverage);
429     }
430   }
431
432   inline bool apply (hb_apply_context_t *c) const
433   {
434     TRACE_APPLY ();
435     switch (u.format) {
436     case 1: return TRACE_RETURN (u.format1.apply (c));
437     default:return TRACE_RETURN (false);
438     }
439   }
440
441   inline bool sanitize (hb_sanitize_context_t *c) {
442     TRACE_SANITIZE ();
443     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
444     switch (u.format) {
445     case 1: return TRACE_RETURN (u.format1.sanitize (c));
446     default:return TRACE_RETURN (true);
447     }
448   }
449
450   protected:
451   union {
452   USHORT                format;         /* Format identifier */
453   AlternateSubstFormat1 format1;
454   } u;
455 };
456
457
458 struct Ligature
459 {
460   friend struct LigatureSet;
461
462   private:
463
464   inline void closure (hb_closure_context_t *c) const
465   {
466     TRACE_CLOSURE ();
467     unsigned int count = component.len;
468     for (unsigned int i = 1; i < count; i++)
469       if (!c->glyphs->has (component[i]))
470         return;
471     c->glyphs->add (ligGlyph);
472   }
473
474   inline bool would_apply (hb_would_apply_context_t *c) const
475   {
476     if (c->len != component.len)
477       return false;
478
479     for (unsigned int i = 1; i < c->len; i++)
480       if (likely (c->glyphs[i] != component[i]))
481         return false;
482
483     return true;
484   }
485
486   inline bool apply (hb_apply_context_t *c) const
487   {
488     TRACE_APPLY ();
489     unsigned int count = component.len;
490     if (unlikely (count < 1)) return TRACE_RETURN (false);
491
492     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
493     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
494
495     /*
496      * This is perhaps the trickiest part of GSUB...  Remarks:
497      *
498      * - If all components of the ligature were marks, we call this a mark ligature.
499      *
500      * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
501      *   it as a ligature glyph.  Though, really, this will not really be used...
502      *
503      * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
504      *   the ligature to keep its old ligature id.  This will allow it to attach to
505      *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
506      *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
507      *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
508      *   later, we don't want them to lose their ligature id/component, otherwise
509      *   GPOS will fail to correctly position the mark ligature on top of the
510      *   LAM,LAM,HEH ligature.  See:
511      *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
512      *
513      * - If a ligature is formed of components that some of which are also ligatures
514      *   themselves, and those ligature components had marks attached to *their*
515      *   components, we have to attach the marks to the new ligature component
516      *   positions!  Now *that*'s tricky!  And these marks may be following the
517      *   last component of the whole sequence, so we should loop forward looking
518      *   for them and update them.
519      *
520      *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
521      *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
522      *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
523      *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
524      *   the new ligature with a component value of 2.
525      *
526      *   This in fact happened to a font...  See:
527      *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
528      *
529      * - Ligatures cannot be formed across glyphs attached to different components
530      *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
531      *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
532      *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
533      *   There is an exception to this: If a ligature tries ligating with marks that
534      *   belong to it itself, go ahead, assuming that the font designer knows what
535      *   they are doing (otherwise it can break Indic stuff when a matra wants to
536      *   ligate with a conjunct...)
537      */
538
539     bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
540
541     unsigned int total_component_count = 0;
542     total_component_count += get_lig_num_comps (c->buffer->cur());
543
544     unsigned int first_lig_id = get_lig_id (c->buffer->cur());
545     unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
546
547     for (unsigned int i = 1; i < count; i++)
548     {
549       unsigned int property;
550
551       if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
552
553       if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (false);
554
555       unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
556       unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
557
558       if (first_lig_id && first_lig_comp) {
559         /* If first component was attached to a previous ligature component,
560          * all subsequent components should be attached to the same ligature
561          * component, otherwise we shouldn't ligate them. */
562         if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
563           return TRACE_RETURN (false);
564       } else {
565         /* If first component was NOT attached to a previous ligature component,
566          * all subsequent components should also NOT be attached to any ligature
567          * component, unless they are attached to the first component itself! */
568         if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
569           return TRACE_RETURN (false);
570       }
571
572       is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
573       total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
574     }
575
576     /* Deal, we are forming the ligature. */
577     c->buffer->merge_clusters (c->buffer->idx, skippy_iter.idx + 1);
578
579     unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
580     unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
581     unsigned int last_lig_id = get_lig_id (c->buffer->cur());
582     unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
583     unsigned int components_so_far = last_num_components;
584
585     if (!is_mark_ligature)
586       set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
587     c->replace_glyph (ligGlyph, klass);
588
589     for (unsigned int i = 1; i < count; i++)
590     {
591       while (c->should_mark_skip_current_glyph ())
592       {
593         if (!is_mark_ligature) {
594           unsigned int new_lig_comp = components_so_far - last_num_components +
595                                       MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
596           set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
597         }
598         c->buffer->next_glyph ();
599       }
600
601       last_lig_id = get_lig_id (c->buffer->cur());
602       last_num_components = get_lig_num_comps (c->buffer->cur());
603       components_so_far += last_num_components;
604
605       /* Skip the base glyph */
606       c->buffer->idx++;
607     }
608
609     if (!is_mark_ligature && last_lig_id) {
610       /* Re-adjust components for any marks following. */
611       for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
612         if (last_lig_id == get_lig_id (c->buffer->info[i])) {
613           unsigned int new_lig_comp = components_so_far - last_num_components +
614                                       MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
615           set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
616         } else
617           break;
618       }
619     }
620
621     return TRACE_RETURN (true);
622   }
623
624   public:
625   inline bool sanitize (hb_sanitize_context_t *c) {
626     TRACE_SANITIZE ();
627     return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
628   }
629
630   protected:
631   GlyphID       ligGlyph;               /* GlyphID of ligature to substitute */
632   HeadlessArrayOf<GlyphID>
633                 component;              /* Array of component GlyphIDs--start
634                                          * with the second  component--ordered
635                                          * in writing direction */
636   public:
637   DEFINE_SIZE_ARRAY (4, component);
638 };
639
640 struct LigatureSet
641 {
642   friend struct LigatureSubstFormat1;
643
644   private:
645
646   inline void closure (hb_closure_context_t *c) const
647   {
648     TRACE_CLOSURE ();
649     unsigned int num_ligs = ligature.len;
650     for (unsigned int i = 0; i < num_ligs; i++)
651       (this+ligature[i]).closure (c);
652   }
653
654   inline bool would_apply (hb_would_apply_context_t *c) const
655   {
656     unsigned int num_ligs = ligature.len;
657     for (unsigned int i = 0; i < num_ligs; i++)
658     {
659       const Ligature &lig = this+ligature[i];
660       if (lig.would_apply (c))
661         return true;
662     }
663     return false;
664   }
665
666   inline bool apply (hb_apply_context_t *c) const
667   {
668     TRACE_APPLY ();
669     unsigned int num_ligs = ligature.len;
670     for (unsigned int i = 0; i < num_ligs; i++)
671     {
672       const Ligature &lig = this+ligature[i];
673       if (lig.apply (c)) return TRACE_RETURN (true);
674     }
675
676     return TRACE_RETURN (false);
677   }
678
679   public:
680   inline bool sanitize (hb_sanitize_context_t *c) {
681     TRACE_SANITIZE ();
682     return TRACE_RETURN (ligature.sanitize (c, this));
683   }
684
685   protected:
686   OffsetArrayOf<Ligature>
687                 ligature;               /* Array LigatureSet tables
688                                          * ordered by preference */
689   public:
690   DEFINE_SIZE_ARRAY (2, ligature);
691 };
692
693 struct LigatureSubstFormat1
694 {
695   friend struct LigatureSubst;
696
697   private:
698
699   inline void closure (hb_closure_context_t *c) const
700   {
701     TRACE_CLOSURE ();
702     Coverage::Iter iter;
703     for (iter.init (this+coverage); iter.more (); iter.next ()) {
704       if (c->glyphs->has (iter.get_glyph ()))
705         (this+ligatureSet[iter.get_coverage ()]).closure (c);
706     }
707   }
708
709   inline const Coverage &get_coverage (void) const
710   {
711     return this+coverage;
712   }
713
714   inline bool would_apply (hb_would_apply_context_t *c) const
715   {
716     return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c);
717   }
718
719   inline bool apply (hb_apply_context_t *c) const
720   {
721     TRACE_APPLY ();
722     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
723
724     unsigned int index = (this+coverage) (glyph_id);
725     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
726
727     const LigatureSet &lig_set = this+ligatureSet[index];
728     return TRACE_RETURN (lig_set.apply (c));
729   }
730
731   inline bool sanitize (hb_sanitize_context_t *c) {
732     TRACE_SANITIZE ();
733     return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
734   }
735
736   protected:
737   USHORT        format;                 /* Format identifier--format = 1 */
738   OffsetTo<Coverage>
739                 coverage;               /* Offset to Coverage table--from
740                                          * beginning of Substitution table */
741   OffsetArrayOf<LigatureSet>
742                 ligatureSet;            /* Array LigatureSet tables
743                                          * ordered by Coverage Index */
744   public:
745   DEFINE_SIZE_ARRAY (6, ligatureSet);
746 };
747
748 struct LigatureSubst
749 {
750   friend struct SubstLookupSubTable;
751
752   private:
753
754   inline void closure (hb_closure_context_t *c) const
755   {
756     TRACE_CLOSURE ();
757     switch (u.format) {
758     case 1: u.format1.closure (c); break;
759     default:                       break;
760     }
761   }
762
763   inline const Coverage &get_coverage (void) const
764   {
765     switch (u.format) {
766     case 1: return u.format1.get_coverage ();
767     default:return Null(Coverage);
768     }
769   }
770
771   inline bool would_apply (hb_would_apply_context_t *c) const
772   {
773     switch (u.format) {
774     case 1: return u.format1.would_apply (c);
775     default:return false;
776     }
777   }
778
779   inline bool apply (hb_apply_context_t *c) const
780   {
781     TRACE_APPLY ();
782     switch (u.format) {
783     case 1: return TRACE_RETURN (u.format1.apply (c));
784     default:return TRACE_RETURN (false);
785     }
786   }
787
788   inline bool sanitize (hb_sanitize_context_t *c) {
789     TRACE_SANITIZE ();
790     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
791     switch (u.format) {
792     case 1: return TRACE_RETURN (u.format1.sanitize (c));
793     default:return TRACE_RETURN (true);
794     }
795   }
796
797   protected:
798   union {
799   USHORT                format;         /* Format identifier */
800   LigatureSubstFormat1  format1;
801   } u;
802 };
803
804
805 static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
806 static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
807
808 struct ContextSubst : Context
809 {
810   friend struct SubstLookupSubTable;
811
812   private:
813
814   inline void closure (hb_closure_context_t *c) const
815   {
816     TRACE_CLOSURE ();
817     return Context::closure (c, closure_lookup);
818   }
819
820   inline bool apply (hb_apply_context_t *c) const
821   {
822     TRACE_APPLY ();
823     return TRACE_RETURN (Context::apply (c, substitute_lookup));
824   }
825 };
826
827 struct ChainContextSubst : ChainContext
828 {
829   friend struct SubstLookupSubTable;
830
831   private:
832
833   inline void closure (hb_closure_context_t *c) const
834   {
835     TRACE_CLOSURE ();
836     return ChainContext::closure (c, closure_lookup);
837   }
838
839   inline bool apply (hb_apply_context_t *c) const
840   {
841     TRACE_APPLY ();
842     return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
843   }
844 };
845
846
847 struct ExtensionSubst : Extension
848 {
849   friend struct SubstLookupSubTable;
850   friend struct SubstLookup;
851
852   private:
853   inline const struct SubstLookupSubTable& get_subtable (void) const
854   {
855     unsigned int offset = get_offset ();
856     if (unlikely (!offset)) return Null(SubstLookupSubTable);
857     return StructAtOffset<SubstLookupSubTable> (this, offset);
858   }
859
860   inline void closure (hb_closure_context_t *c) const;
861
862   inline const Coverage &get_coverage (void) const;
863
864   inline bool would_apply (hb_would_apply_context_t *c) const;
865
866   inline bool apply (hb_apply_context_t *c) const;
867
868   inline bool sanitize (hb_sanitize_context_t *c);
869
870   inline bool is_reverse (void) const;
871 };
872
873
874 struct ReverseChainSingleSubstFormat1
875 {
876   friend struct ReverseChainSingleSubst;
877
878   private:
879
880   inline void closure (hb_closure_context_t *c) const
881   {
882     TRACE_CLOSURE ();
883     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
884
885     unsigned int count;
886
887     count = backtrack.len;
888     for (unsigned int i = 0; i < count; i++)
889       if (!(this+backtrack[i]).intersects (c->glyphs))
890         return;
891
892     count = lookahead.len;
893     for (unsigned int i = 0; i < count; i++)
894       if (!(this+lookahead[i]).intersects (c->glyphs))
895         return;
896
897     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
898     Coverage::Iter iter;
899     for (iter.init (this+coverage); iter.more (); iter.next ()) {
900       if (c->glyphs->has (iter.get_glyph ()))
901         c->glyphs->add (substitute[iter.get_coverage ()]);
902     }
903   }
904
905   inline const Coverage &get_coverage (void) const
906   {
907     return this+coverage;
908   }
909
910   inline bool apply (hb_apply_context_t *c) const
911   {
912     TRACE_APPLY ();
913     if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
914       return TRACE_RETURN (false); /* No chaining to this type */
915
916     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
917     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
918
919     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
920     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
921
922     if (match_backtrack (c,
923                          backtrack.len, (USHORT *) backtrack.array,
924                          match_coverage, this) &&
925         match_lookahead (c,
926                          lookahead.len, (USHORT *) lookahead.array,
927                          match_coverage, this,
928                          1))
929     {
930       c->replace_glyph_inplace (substitute[index]);
931       c->buffer->idx--; /* Reverse! */
932       return TRACE_RETURN (true);
933     }
934
935     return TRACE_RETURN (false);
936   }
937
938   inline bool sanitize (hb_sanitize_context_t *c) {
939     TRACE_SANITIZE ();
940     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
941       return TRACE_RETURN (false);
942     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
943     if (!lookahead.sanitize (c, this))
944       return TRACE_RETURN (false);
945     ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
946     return TRACE_RETURN (substitute.sanitize (c));
947   }
948
949   protected:
950   USHORT        format;                 /* Format identifier--format = 1 */
951   OffsetTo<Coverage>
952                 coverage;               /* Offset to Coverage table--from
953                                          * beginning of table */
954   OffsetArrayOf<Coverage>
955                 backtrack;              /* Array of coverage tables
956                                          * in backtracking sequence, in  glyph
957                                          * sequence order */
958   OffsetArrayOf<Coverage>
959                 lookaheadX;             /* Array of coverage tables
960                                          * in lookahead sequence, in glyph
961                                          * sequence order */
962   ArrayOf<GlyphID>
963                 substituteX;            /* Array of substitute
964                                          * GlyphIDs--ordered by Coverage Index */
965   public:
966   DEFINE_SIZE_MIN (10);
967 };
968
969 struct ReverseChainSingleSubst
970 {
971   friend struct SubstLookupSubTable;
972
973   private:
974
975   inline void closure (hb_closure_context_t *c) const
976   {
977     TRACE_CLOSURE ();
978     switch (u.format) {
979     case 1: u.format1.closure (c); break;
980     default:                       break;
981     }
982   }
983
984   inline const Coverage &get_coverage (void) const
985   {
986     switch (u.format) {
987     case 1: return u.format1.get_coverage ();
988     default:return Null(Coverage);
989     }
990   }
991
992   inline bool apply (hb_apply_context_t *c) const
993   {
994     TRACE_APPLY ();
995     switch (u.format) {
996     case 1: return TRACE_RETURN (u.format1.apply (c));
997     default:return TRACE_RETURN (false);
998     }
999   }
1000
1001   inline bool sanitize (hb_sanitize_context_t *c) {
1002     TRACE_SANITIZE ();
1003     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1004     switch (u.format) {
1005     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1006     default:return TRACE_RETURN (true);
1007     }
1008   }
1009
1010   protected:
1011   union {
1012   USHORT                                format;         /* Format identifier */
1013   ReverseChainSingleSubstFormat1        format1;
1014   } u;
1015 };
1016
1017
1018
1019 /*
1020  * SubstLookup
1021  */
1022
1023 struct SubstLookupSubTable
1024 {
1025   friend struct SubstLookup;
1026
1027   enum Type {
1028     Single              = 1,
1029     Multiple            = 2,
1030     Alternate           = 3,
1031     Ligature            = 4,
1032     Context             = 5,
1033     ChainContext        = 6,
1034     Extension           = 7,
1035     ReverseChainSingle  = 8
1036   };
1037
1038   inline void closure (hb_closure_context_t *c,
1039                        unsigned int    lookup_type) const
1040   {
1041     TRACE_CLOSURE ();
1042     switch (lookup_type) {
1043     case Single:                u.single.closure (c); break;
1044     case Multiple:              u.multiple.closure (c); break;
1045     case Alternate:             u.alternate.closure (c); break;
1046     case Ligature:              u.ligature.closure (c); break;
1047     case Context:               u.context.closure (c); break;
1048     case ChainContext:          u.chainContext.closure (c); break;
1049     case Extension:             u.extension.closure (c); break;
1050     case ReverseChainSingle:    u.reverseChainContextSingle.closure (c); break;
1051     default:                    break;
1052     }
1053   }
1054
1055   inline const Coverage &get_coverage (unsigned int lookup_type) const
1056   {
1057     switch (lookup_type) {
1058     case Single:                return u.single.get_coverage ();
1059     case Multiple:              return u.multiple.get_coverage ();
1060     case Alternate:             return u.alternate.get_coverage ();
1061     case Ligature:              return u.ligature.get_coverage ();
1062     case Context:               return u.context.get_coverage ();
1063     case ChainContext:          return u.chainContext.get_coverage ();
1064     case Extension:             return u.extension.get_coverage ();
1065     case ReverseChainSingle:    return u.reverseChainContextSingle.get_coverage ();
1066     default:                    return Null(Coverage);
1067     }
1068   }
1069
1070   inline bool would_apply (hb_would_apply_context_t *c,
1071                            unsigned int lookup_type) const
1072   {
1073     TRACE_WOULD_APPLY ();
1074     if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false;
1075     if (c->len == 1) {
1076       switch (lookup_type) {
1077       case Single:
1078       case Multiple:
1079       case Alternate:
1080       case ReverseChainSingle:
1081         return true;
1082       }
1083     }
1084
1085     /* Only need to look further for lookups that support substitutions
1086      * of input longer than 1. */
1087     switch (lookup_type) {
1088     case Ligature:              return u.ligature.would_apply (c);
1089     case Context:               return u.context.would_apply (c);
1090     case ChainContext:          return u.chainContext.would_apply (c);
1091     case Extension:             return u.extension.would_apply (c);
1092     default:                    return false;
1093     }
1094   }
1095
1096   inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1097   {
1098     TRACE_APPLY ();
1099     switch (lookup_type) {
1100     case Single:                return TRACE_RETURN (u.single.apply (c));
1101     case Multiple:              return TRACE_RETURN (u.multiple.apply (c));
1102     case Alternate:             return TRACE_RETURN (u.alternate.apply (c));
1103     case Ligature:              return TRACE_RETURN (u.ligature.apply (c));
1104     case Context:               return TRACE_RETURN (u.context.apply (c));
1105     case ChainContext:          return TRACE_RETURN (u.chainContext.apply (c));
1106     case Extension:             return TRACE_RETURN (u.extension.apply (c));
1107     case ReverseChainSingle:    return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
1108     default:                    return TRACE_RETURN (false);
1109     }
1110   }
1111
1112   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1113     TRACE_SANITIZE ();
1114     if (!u.header.sub_format.sanitize (c))
1115       return TRACE_RETURN (false);
1116     switch (lookup_type) {
1117     case Single:                return TRACE_RETURN (u.single.sanitize (c));
1118     case Multiple:              return TRACE_RETURN (u.multiple.sanitize (c));
1119     case Alternate:             return TRACE_RETURN (u.alternate.sanitize (c));
1120     case Ligature:              return TRACE_RETURN (u.ligature.sanitize (c));
1121     case Context:               return TRACE_RETURN (u.context.sanitize (c));
1122     case ChainContext:          return TRACE_RETURN (u.chainContext.sanitize (c));
1123     case Extension:             return TRACE_RETURN (u.extension.sanitize (c));
1124     case ReverseChainSingle:    return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
1125     default:                    return TRACE_RETURN (true);
1126     }
1127   }
1128
1129   protected:
1130   union {
1131   struct {
1132     USHORT                      sub_format;
1133   } header;
1134   SingleSubst                   single;
1135   MultipleSubst                 multiple;
1136   AlternateSubst                alternate;
1137   LigatureSubst                 ligature;
1138   ContextSubst                  context;
1139   ChainContextSubst             chainContext;
1140   ExtensionSubst                extension;
1141   ReverseChainSingleSubst       reverseChainContextSingle;
1142   } u;
1143   public:
1144   DEFINE_SIZE_UNION (2, header.sub_format);
1145 };
1146
1147
1148 struct SubstLookup : Lookup
1149 {
1150   inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1151   { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
1152
1153   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1154   { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1155
1156   inline bool is_reverse (void) const
1157   {
1158     unsigned int type = get_type ();
1159     if (unlikely (type == SubstLookupSubTable::Extension))
1160       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1161     return lookup_type_is_reverse (type);
1162   }
1163
1164   inline void closure (hb_closure_context_t *c) const
1165   {
1166     unsigned int lookup_type = get_type ();
1167     unsigned int count = get_subtable_count ();
1168     for (unsigned int i = 0; i < count; i++)
1169       get_subtable (i).closure (c, lookup_type);
1170   }
1171
1172   template <typename set_t>
1173   inline void add_coverage (set_t *glyphs) const
1174   {
1175     const Coverage *last = NULL;
1176     unsigned int count = get_subtable_count ();
1177     for (unsigned int i = 0; i < count; i++) {
1178       const Coverage *c = &get_subtable (i).get_coverage (get_type ());
1179       if (c != last) {
1180         c->add_coverage (glyphs);
1181         last = c;
1182       }
1183     }
1184   }
1185
1186   inline bool would_apply (hb_would_apply_context_t *c) const
1187   {
1188     if (unlikely (!c->len)) return false;
1189     if (!c->digest.may_have (c->glyphs[0])) return false;
1190     unsigned int lookup_type = get_type ();
1191     unsigned int count = get_subtable_count ();
1192     for (unsigned int i = 0; i < count; i++)
1193       if (get_subtable (i).would_apply (c, lookup_type))
1194         return true;
1195     return false;
1196   }
1197
1198   inline bool apply_once (hb_apply_context_t *c) const
1199   {
1200     unsigned int lookup_type = get_type ();
1201
1202     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
1203       return false;
1204
1205     unsigned int count = get_subtable_count ();
1206     for (unsigned int i = 0; i < count; i++)
1207       if (get_subtable (i).apply (c, lookup_type))
1208         return true;
1209
1210     return false;
1211   }
1212
1213   inline bool apply_string (hb_apply_context_t *c) const
1214   {
1215     bool ret = false;
1216
1217     if (unlikely (!c->buffer->len))
1218       return false;
1219
1220     c->set_lookup (*this);
1221
1222     if (likely (!is_reverse ()))
1223     {
1224         /* in/out forward substitution */
1225         c->buffer->clear_output ();
1226         c->buffer->idx = 0;
1227
1228         while (c->buffer->idx < c->buffer->len)
1229         {
1230           if ((c->buffer->cur().mask & c->lookup_mask) &&
1231               c->digest.may_have (c->buffer->cur().codepoint) &&
1232               apply_once (c))
1233             ret = true;
1234           else
1235             c->buffer->next_glyph ();
1236         }
1237         if (ret)
1238           c->buffer->swap_buffers ();
1239     }
1240     else
1241     {
1242         /* in-place backward substitution */
1243         c->buffer->idx = c->buffer->len - 1;
1244         do
1245         {
1246           if ((c->buffer->cur().mask & c->lookup_mask) &&
1247               c->digest.may_have (c->buffer->cur().codepoint) &&
1248               apply_once (c))
1249             ret = true;
1250           else
1251             c->buffer->idx--;
1252
1253         }
1254         while ((int) c->buffer->idx >= 0);
1255     }
1256
1257     return ret;
1258   }
1259
1260   inline bool sanitize (hb_sanitize_context_t *c) {
1261     TRACE_SANITIZE ();
1262     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1263     OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
1264     if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
1265
1266     if (unlikely (get_type () == SubstLookupSubTable::Extension))
1267     {
1268       /* The spec says all subtables of an Extension lookup should
1269        * have the same type.  This is specially important if one has
1270        * a reverse type!
1271        *
1272        * We just check that they are all either forward, or reverse. */
1273       unsigned int type = get_subtable (0).u.extension.get_type ();
1274       unsigned int count = get_subtable_count ();
1275       for (unsigned int i = 1; i < count; i++)
1276         if (get_subtable (i).u.extension.get_type () != type)
1277           return TRACE_RETURN (false);
1278     }
1279     return TRACE_RETURN (true);
1280   }
1281 };
1282
1283 typedef OffsetListOf<SubstLookup> SubstLookupList;
1284
1285 /*
1286  * GSUB -- The Glyph Substitution Table
1287  */
1288
1289 struct GSUB : GSUBGPOS
1290 {
1291   static const hb_tag_t Tag     = HB_OT_TAG_GSUB;
1292
1293   inline const SubstLookup& get_lookup (unsigned int i) const
1294   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1295
1296   template <typename set_t>
1297   inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
1298   { get_lookup (lookup_index).add_coverage (glyphs); }
1299
1300   inline bool would_substitute_lookup (hb_would_apply_context_t *c, unsigned int lookup_index) const
1301   { return get_lookup (lookup_index).would_apply (c); }
1302
1303   inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
1304   { return get_lookup (lookup_index).apply_string (c); }
1305
1306   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1307   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
1308
1309   inline void closure_lookup (hb_closure_context_t *c,
1310                               unsigned int          lookup_index) const
1311   { return get_lookup (lookup_index).closure (c); }
1312
1313   inline bool sanitize (hb_sanitize_context_t *c) {
1314     TRACE_SANITIZE ();
1315     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1316     OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1317     return TRACE_RETURN (list.sanitize (c, this));
1318   }
1319   public:
1320   DEFINE_SIZE_STATIC (10);
1321 };
1322
1323
1324 void
1325 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1326 {
1327   HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
1328   HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1329   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1330
1331   const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1332   unsigned int count = buffer->len;
1333   for (unsigned int i = 0; i < count; i++) {
1334     buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
1335     buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
1336   }
1337 }
1338
1339 void
1340 GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
1341 {
1342 }
1343
1344
1345 /* Out-of-class implementation for methods recursing */
1346
1347 inline void ExtensionSubst::closure (hb_closure_context_t *c) const
1348 {
1349   get_subtable ().closure (c, get_type ());
1350 }
1351
1352 inline const Coverage & ExtensionSubst::get_coverage (void) const
1353 {
1354   return get_subtable ().get_coverage (get_type ());
1355 }
1356
1357 inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
1358 {
1359   return get_subtable ().would_apply (c, get_type ());
1360 }
1361
1362 inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
1363 {
1364   TRACE_APPLY ();
1365   return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
1366 }
1367
1368 inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
1369 {
1370   TRACE_SANITIZE ();
1371   if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
1372   unsigned int offset = get_offset ();
1373   if (unlikely (!offset)) return TRACE_RETURN (true);
1374   return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
1375 }
1376
1377 inline bool ExtensionSubst::is_reverse (void) const
1378 {
1379   unsigned int type = get_type ();
1380   if (unlikely (type == SubstLookupSubTable::Extension))
1381     return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
1382   return SubstLookup::lookup_type_is_reverse (type);
1383 }
1384
1385 static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
1386 {
1387   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1388   const SubstLookup &l = gsub.get_lookup (lookup_index);
1389
1390   if (unlikely (c->nesting_level_left == 0))
1391     return;
1392
1393   c->nesting_level_left--;
1394   l.closure (c);
1395   c->nesting_level_left++;
1396 }
1397
1398 static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1399 {
1400   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1401   const SubstLookup &l = gsub.get_lookup (lookup_index);
1402
1403   if (unlikely (c->nesting_level_left == 0))
1404     return false;
1405
1406   hb_apply_context_t new_c (*c);
1407   new_c.nesting_level_left--;
1408   new_c.set_lookup (l);
1409   return l.apply_once (&new_c);
1410 }
1411
1412
1413
1414 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */