hb-ot-layout-gsub-table.hh revision a973b5ce86051e8ef0d20df362db1a50488842ab
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
36struct 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
89struct 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
142struct 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
196struct 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
239struct 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
287struct 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
336typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
337					 * arbitrary order */
338
339struct 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
409struct 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
458struct 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    return c->len == 1 || (c->len == 2 && component.len == 2 && component[1] == c->second);
477  }
478
479  inline bool apply (hb_apply_context_t *c) const
480  {
481    TRACE_APPLY ();
482    unsigned int count = component.len;
483    if (unlikely (count < 1)) return TRACE_RETURN (false);
484
485    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
486    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
487
488    /*
489     * This is perhaps the trickiest part of GSUB...  Remarks:
490     *
491     * - If all components of the ligature were marks, we call this a mark ligature.
492     *
493     * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
494     *   it as a ligature glyph.  Though, really, this will not really be used...
495     *
496     * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
497     *   the ligature to keep its old ligature id.  This will allow it to attach to
498     *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
499     *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
500     *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
501     *   later, we don't want them to lose their ligature id/component, otherwise
502     *   GPOS will fail to correctly position the mark ligature on top of the
503     *   LAM,LAM,HEH ligature.  See:
504     *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
505     *
506     * - If a ligature is formed of components that some of which are also ligatures
507     *   themselves, and those ligature components had marks attached to *their*
508     *   components, we have to attach the marks to the new ligature component
509     *   positions!  Now *that*'s tricky!  And these marks may be following the
510     *   last component of the whole sequence, so we should loop forward looking
511     *   for them and update them.
512     *
513     *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
514     *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
515     *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
516     *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
517     *   the new ligature with a component value of 2.
518     *
519     *   This in fact happened to a font...  See:
520     *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
521     *
522     * - Ligatures cannot be formed across glyphs attached to different components
523     *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
524     *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
525     *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
526     *   There is an exception to this: If a ligature tries ligating with marks that
527     *   belong to it itself, go ahead, assuming that the font designer knows what
528     *   they are doing (otherwise it can break Indic stuff when a matra wants to
529     *   ligate with a conjunct...)
530     */
531
532    bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
533
534    unsigned int total_component_count = 0;
535    total_component_count += get_lig_num_comps (c->buffer->cur());
536
537    unsigned int first_lig_id = get_lig_id (c->buffer->cur());
538    unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
539
540    for (unsigned int i = 1; i < count; i++)
541    {
542      unsigned int property;
543
544      if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
545
546      if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (false);
547
548      unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
549      unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
550
551      if (first_lig_id && first_lig_comp) {
552        /* If first component was attached to a previous ligature component,
553	 * all subsequent components should be attached to the same ligature
554	 * component, otherwise we shouldn't ligate them. */
555        if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
556	  return TRACE_RETURN (false);
557      } else {
558        /* If first component was NOT attached to a previous ligature component,
559	 * all subsequent components should also NOT be attached to any ligature
560	 * component, unless they are attached to the first component itself! */
561        if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
562	  return TRACE_RETURN (false);
563      }
564
565      is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
566      total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
567    }
568
569    /* Deal, we are forming the ligature. */
570    c->buffer->merge_clusters (c->buffer->idx, skippy_iter.idx + 1);
571
572    unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
573    unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
574    unsigned int last_lig_id = get_lig_id (c->buffer->cur());
575    unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
576    unsigned int components_so_far = last_num_components;
577
578    if (!is_mark_ligature)
579      set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
580    c->replace_glyph (ligGlyph, klass);
581
582    for (unsigned int i = 1; i < count; i++)
583    {
584      while (c->should_mark_skip_current_glyph ())
585      {
586	if (!is_mark_ligature) {
587	  unsigned int new_lig_comp = components_so_far - last_num_components +
588				      MIN (MAX (get_lig_comp (c->buffer->cur()), 1), last_num_components);
589	  set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
590	}
591	c->buffer->next_glyph ();
592      }
593
594      last_lig_id = get_lig_id (c->buffer->cur());
595      last_num_components = get_lig_num_comps (c->buffer->cur());
596      components_so_far += last_num_components;
597
598      /* Skip the base glyph */
599      c->buffer->idx++;
600    }
601
602    if (!is_mark_ligature && last_lig_id) {
603      /* Re-adjust components for any marks following. */
604      for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
605	if (last_lig_id == get_lig_id (c->buffer->info[i])) {
606	  unsigned int new_lig_comp = components_so_far - last_num_components +
607				      MIN (MAX (get_lig_comp (c->buffer->info[i]), 1), last_num_components);
608	  set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
609	} else
610	  break;
611      }
612    }
613
614    return TRACE_RETURN (true);
615  }
616
617  public:
618  inline bool sanitize (hb_sanitize_context_t *c) {
619    TRACE_SANITIZE ();
620    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
621  }
622
623  protected:
624  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
625  HeadlessArrayOf<GlyphID>
626		component;		/* Array of component GlyphIDs--start
627					 * with the second  component--ordered
628					 * in writing direction */
629  public:
630  DEFINE_SIZE_ARRAY (4, component);
631};
632
633struct LigatureSet
634{
635  friend struct LigatureSubstFormat1;
636
637  private:
638
639  inline void closure (hb_closure_context_t *c) const
640  {
641    TRACE_CLOSURE ();
642    unsigned int num_ligs = ligature.len;
643    for (unsigned int i = 0; i < num_ligs; i++)
644      (this+ligature[i]).closure (c);
645  }
646
647  inline bool would_apply (hb_would_apply_context_t *c) const
648  {
649    unsigned int num_ligs = ligature.len;
650    for (unsigned int i = 0; i < num_ligs; i++)
651    {
652      const Ligature &lig = this+ligature[i];
653      if (lig.would_apply (c))
654        return true;
655    }
656    return false;
657  }
658
659  inline bool apply (hb_apply_context_t *c) const
660  {
661    TRACE_APPLY ();
662    unsigned int num_ligs = ligature.len;
663    for (unsigned int i = 0; i < num_ligs; i++)
664    {
665      const Ligature &lig = this+ligature[i];
666      if (lig.apply (c)) return TRACE_RETURN (true);
667    }
668
669    return TRACE_RETURN (false);
670  }
671
672  public:
673  inline bool sanitize (hb_sanitize_context_t *c) {
674    TRACE_SANITIZE ();
675    return TRACE_RETURN (ligature.sanitize (c, this));
676  }
677
678  protected:
679  OffsetArrayOf<Ligature>
680		ligature;		/* Array LigatureSet tables
681					 * ordered by preference */
682  public:
683  DEFINE_SIZE_ARRAY (2, ligature);
684};
685
686struct LigatureSubstFormat1
687{
688  friend struct LigatureSubst;
689
690  private:
691
692  inline void closure (hb_closure_context_t *c) const
693  {
694    TRACE_CLOSURE ();
695    Coverage::Iter iter;
696    for (iter.init (this+coverage); iter.more (); iter.next ()) {
697      if (c->glyphs->has (iter.get_glyph ()))
698	(this+ligatureSet[iter.get_coverage ()]).closure (c);
699    }
700  }
701
702  inline const Coverage &get_coverage (void) const
703  {
704    return this+coverage;
705  }
706
707  inline bool would_apply (hb_would_apply_context_t *c) const
708  {
709    return (this+ligatureSet[(this+coverage) (c->first)]).would_apply (c);
710  }
711
712  inline bool apply (hb_apply_context_t *c) const
713  {
714    TRACE_APPLY ();
715    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
716
717    unsigned int index = (this+coverage) (glyph_id);
718    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
719
720    const LigatureSet &lig_set = this+ligatureSet[index];
721    return TRACE_RETURN (lig_set.apply (c));
722  }
723
724  inline bool sanitize (hb_sanitize_context_t *c) {
725    TRACE_SANITIZE ();
726    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
727  }
728
729  protected:
730  USHORT	format;			/* Format identifier--format = 1 */
731  OffsetTo<Coverage>
732		coverage;		/* Offset to Coverage table--from
733					 * beginning of Substitution table */
734  OffsetArrayOf<LigatureSet>
735		ligatureSet;		/* Array LigatureSet tables
736					 * ordered by Coverage Index */
737  public:
738  DEFINE_SIZE_ARRAY (6, ligatureSet);
739};
740
741struct LigatureSubst
742{
743  friend struct SubstLookupSubTable;
744
745  private:
746
747  inline void closure (hb_closure_context_t *c) const
748  {
749    TRACE_CLOSURE ();
750    switch (u.format) {
751    case 1: u.format1.closure (c); break;
752    default:                       break;
753    }
754  }
755
756  inline const Coverage &get_coverage (void) const
757  {
758    switch (u.format) {
759    case 1: return u.format1.get_coverage ();
760    default:return Null(Coverage);
761    }
762  }
763
764  inline bool would_apply (hb_would_apply_context_t *c) const
765  {
766    switch (u.format) {
767    case 1: return u.format1.would_apply (c);
768    default:return false;
769    }
770  }
771
772  inline bool apply (hb_apply_context_t *c) const
773  {
774    TRACE_APPLY ();
775    switch (u.format) {
776    case 1: return TRACE_RETURN (u.format1.apply (c));
777    default:return TRACE_RETURN (false);
778    }
779  }
780
781  inline bool sanitize (hb_sanitize_context_t *c) {
782    TRACE_SANITIZE ();
783    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
784    switch (u.format) {
785    case 1: return TRACE_RETURN (u.format1.sanitize (c));
786    default:return TRACE_RETURN (true);
787    }
788  }
789
790  protected:
791  union {
792  USHORT		format;		/* Format identifier */
793  LigatureSubstFormat1	format1;
794  } u;
795};
796
797
798static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
799static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
800
801struct ContextSubst : Context
802{
803  friend struct SubstLookupSubTable;
804
805  private:
806
807  inline void closure (hb_closure_context_t *c) const
808  {
809    TRACE_CLOSURE ();
810    return Context::closure (c, closure_lookup);
811  }
812
813  inline bool apply (hb_apply_context_t *c) const
814  {
815    TRACE_APPLY ();
816    return TRACE_RETURN (Context::apply (c, substitute_lookup));
817  }
818};
819
820struct ChainContextSubst : ChainContext
821{
822  friend struct SubstLookupSubTable;
823
824  private:
825
826  inline void closure (hb_closure_context_t *c) const
827  {
828    TRACE_CLOSURE ();
829    return ChainContext::closure (c, closure_lookup);
830  }
831
832  inline bool apply (hb_apply_context_t *c) const
833  {
834    TRACE_APPLY ();
835    return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
836  }
837};
838
839
840struct ExtensionSubst : Extension
841{
842  friend struct SubstLookupSubTable;
843  friend struct SubstLookup;
844
845  private:
846  inline const struct SubstLookupSubTable& get_subtable (void) const
847  {
848    unsigned int offset = get_offset ();
849    if (unlikely (!offset)) return Null(SubstLookupSubTable);
850    return StructAtOffset<SubstLookupSubTable> (this, offset);
851  }
852
853  inline void closure (hb_closure_context_t *c) const;
854
855  inline const Coverage &get_coverage (void) const;
856
857  inline bool would_apply (hb_would_apply_context_t *c) const;
858
859  inline bool apply (hb_apply_context_t *c) const;
860
861  inline bool sanitize (hb_sanitize_context_t *c);
862
863  inline bool is_reverse (void) const;
864};
865
866
867struct ReverseChainSingleSubstFormat1
868{
869  friend struct ReverseChainSingleSubst;
870
871  private:
872
873  inline void closure (hb_closure_context_t *c) const
874  {
875    TRACE_CLOSURE ();
876    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
877
878    unsigned int count;
879
880    count = backtrack.len;
881    for (unsigned int i = 0; i < count; i++)
882      if (!(this+backtrack[i]).intersects (c->glyphs))
883        return;
884
885    count = lookahead.len;
886    for (unsigned int i = 0; i < count; i++)
887      if (!(this+lookahead[i]).intersects (c->glyphs))
888        return;
889
890    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
891    Coverage::Iter iter;
892    for (iter.init (this+coverage); iter.more (); iter.next ()) {
893      if (c->glyphs->has (iter.get_glyph ()))
894	c->glyphs->add (substitute[iter.get_coverage ()]);
895    }
896  }
897
898  inline const Coverage &get_coverage (void) const
899  {
900    return this+coverage;
901  }
902
903  inline bool apply (hb_apply_context_t *c) const
904  {
905    TRACE_APPLY ();
906    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
907      return TRACE_RETURN (false); /* No chaining to this type */
908
909    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
910    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
911
912    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
913    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
914
915    if (match_backtrack (c,
916			 backtrack.len, (USHORT *) backtrack.array,
917			 match_coverage, this) &&
918        match_lookahead (c,
919			 lookahead.len, (USHORT *) lookahead.array,
920			 match_coverage, this,
921			 1))
922    {
923      c->buffer->cur().codepoint = substitute[index];
924      c->buffer->idx--; /* Reverse! */
925      return TRACE_RETURN (true);
926    }
927
928    return TRACE_RETURN (false);
929  }
930
931  inline bool sanitize (hb_sanitize_context_t *c) {
932    TRACE_SANITIZE ();
933    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
934      return TRACE_RETURN (false);
935    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
936    if (!lookahead.sanitize (c, this))
937      return TRACE_RETURN (false);
938    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
939    return TRACE_RETURN (substitute.sanitize (c));
940  }
941
942  protected:
943  USHORT	format;			/* Format identifier--format = 1 */
944  OffsetTo<Coverage>
945		coverage;		/* Offset to Coverage table--from
946					 * beginning of table */
947  OffsetArrayOf<Coverage>
948		backtrack;		/* Array of coverage tables
949					 * in backtracking sequence, in  glyph
950					 * sequence order */
951  OffsetArrayOf<Coverage>
952		lookaheadX;		/* Array of coverage tables
953					 * in lookahead sequence, in glyph
954					 * sequence order */
955  ArrayOf<GlyphID>
956		substituteX;		/* Array of substitute
957					 * GlyphIDs--ordered by Coverage Index */
958  public:
959  DEFINE_SIZE_MIN (10);
960};
961
962struct ReverseChainSingleSubst
963{
964  friend struct SubstLookupSubTable;
965
966  private:
967
968  inline void closure (hb_closure_context_t *c) const
969  {
970    TRACE_CLOSURE ();
971    switch (u.format) {
972    case 1: u.format1.closure (c); break;
973    default:                       break;
974    }
975  }
976
977  inline const Coverage &get_coverage (void) const
978  {
979    switch (u.format) {
980    case 1: return u.format1.get_coverage ();
981    default:return Null(Coverage);
982    }
983  }
984
985  inline bool apply (hb_apply_context_t *c) const
986  {
987    TRACE_APPLY ();
988    switch (u.format) {
989    case 1: return TRACE_RETURN (u.format1.apply (c));
990    default:return TRACE_RETURN (false);
991    }
992  }
993
994  inline bool sanitize (hb_sanitize_context_t *c) {
995    TRACE_SANITIZE ();
996    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
997    switch (u.format) {
998    case 1: return TRACE_RETURN (u.format1.sanitize (c));
999    default:return TRACE_RETURN (true);
1000    }
1001  }
1002
1003  protected:
1004  union {
1005  USHORT				format;		/* Format identifier */
1006  ReverseChainSingleSubstFormat1	format1;
1007  } u;
1008};
1009
1010
1011
1012/*
1013 * SubstLookup
1014 */
1015
1016struct SubstLookupSubTable
1017{
1018  friend struct SubstLookup;
1019
1020  enum Type {
1021    Single		= 1,
1022    Multiple		= 2,
1023    Alternate		= 3,
1024    Ligature		= 4,
1025    Context		= 5,
1026    ChainContext	= 6,
1027    Extension		= 7,
1028    ReverseChainSingle	= 8
1029  };
1030
1031  inline void closure (hb_closure_context_t *c,
1032		       unsigned int    lookup_type) const
1033  {
1034    TRACE_CLOSURE ();
1035    switch (lookup_type) {
1036    case Single:		u.single.closure (c); break;
1037    case Multiple:		u.multiple.closure (c); break;
1038    case Alternate:		u.alternate.closure (c); break;
1039    case Ligature:		u.ligature.closure (c); break;
1040    case Context:		u.context.closure (c); break;
1041    case ChainContext:		u.chainContext.closure (c); break;
1042    case Extension:		u.extension.closure (c); break;
1043    case ReverseChainSingle:	u.reverseChainContextSingle.closure (c); break;
1044    default:                    break;
1045    }
1046  }
1047
1048  inline const Coverage &get_coverage (unsigned int lookup_type) const
1049  {
1050    switch (lookup_type) {
1051    case Single:		return u.single.get_coverage ();
1052    case Multiple:		return u.multiple.get_coverage ();
1053    case Alternate:		return u.alternate.get_coverage ();
1054    case Ligature:		return u.ligature.get_coverage ();
1055    case Context:		return u.context.get_coverage ();
1056    case ChainContext:		return u.chainContext.get_coverage ();
1057    case Extension:		return u.extension.get_coverage ();
1058    case ReverseChainSingle:	return u.reverseChainContextSingle.get_coverage ();
1059    default:			return Null(Coverage);
1060    }
1061  }
1062
1063  inline bool would_apply (hb_would_apply_context_t *c,
1064			   unsigned int lookup_type) const
1065  {
1066    TRACE_WOULD_APPLY ();
1067    if (get_coverage (lookup_type).get_coverage (c->first) == NOT_COVERED) return false;
1068    if (c->len == 1) return true; /* Done! */
1069
1070    /* Only need to look further for lookups that support substitutions
1071     * of input longer than 1. */
1072    switch (lookup_type) {
1073    case Ligature:		return u.ligature.would_apply (c);
1074    case Context:		return u.context.would_apply (c);
1075    case ChainContext:		return u.chainContext.would_apply (c);
1076    case Extension:		return u.extension.would_apply (c);
1077    default:			return false;
1078    }
1079  }
1080
1081  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1082  {
1083    TRACE_APPLY ();
1084    switch (lookup_type) {
1085    case Single:		return TRACE_RETURN (u.single.apply (c));
1086    case Multiple:		return TRACE_RETURN (u.multiple.apply (c));
1087    case Alternate:		return TRACE_RETURN (u.alternate.apply (c));
1088    case Ligature:		return TRACE_RETURN (u.ligature.apply (c));
1089    case Context:		return TRACE_RETURN (u.context.apply (c));
1090    case ChainContext:		return TRACE_RETURN (u.chainContext.apply (c));
1091    case Extension:		return TRACE_RETURN (u.extension.apply (c));
1092    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
1093    default:			return TRACE_RETURN (false);
1094    }
1095  }
1096
1097  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1098    TRACE_SANITIZE ();
1099    if (!u.header.sub_format.sanitize (c))
1100      return TRACE_RETURN (false);
1101    switch (lookup_type) {
1102    case Single:		return TRACE_RETURN (u.single.sanitize (c));
1103    case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
1104    case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
1105    case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
1106    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1107    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
1108    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
1109    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
1110    default:			return TRACE_RETURN (true);
1111    }
1112  }
1113
1114  protected:
1115  union {
1116  struct {
1117    USHORT			sub_format;
1118  } header;
1119  SingleSubst			single;
1120  MultipleSubst			multiple;
1121  AlternateSubst		alternate;
1122  LigatureSubst			ligature;
1123  ContextSubst			context;
1124  ChainContextSubst		chainContext;
1125  ExtensionSubst		extension;
1126  ReverseChainSingleSubst	reverseChainContextSingle;
1127  } u;
1128  public:
1129  DEFINE_SIZE_UNION (2, header.sub_format);
1130};
1131
1132
1133struct SubstLookup : Lookup
1134{
1135  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1136  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
1137
1138  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1139  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1140
1141  inline bool is_reverse (void) const
1142  {
1143    unsigned int type = get_type ();
1144    if (unlikely (type == SubstLookupSubTable::Extension))
1145      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1146    return lookup_type_is_reverse (type);
1147  }
1148
1149  inline void closure (hb_closure_context_t *c) const
1150  {
1151    unsigned int lookup_type = get_type ();
1152    unsigned int count = get_subtable_count ();
1153    for (unsigned int i = 0; i < count; i++)
1154      get_subtable (i).closure (c, lookup_type);
1155  }
1156
1157  inline const Coverage *get_coverage (void) const
1158  {
1159    /* Only return non-NULL if there's just one Coverage table we care about. */
1160    const Coverage *c = &get_subtable (0).get_coverage (get_type ());
1161    unsigned int count = get_subtable_count ();
1162    for (unsigned int i = 1; i < count; i++)
1163      if (c != &get_subtable (i).get_coverage (get_type ()))
1164        return NULL;
1165    return c;
1166  }
1167
1168  inline bool would_apply (hb_would_apply_context_t *c) const
1169  {
1170    unsigned int lookup_type = get_type ();
1171    unsigned int count = get_subtable_count ();
1172    for (unsigned int i = 0; i < count; i++)
1173      if (get_subtable (i).would_apply (c, lookup_type))
1174	return true;
1175    return false;
1176  }
1177
1178  inline bool apply_once (hb_apply_context_t *c) const
1179  {
1180    unsigned int lookup_type = get_type ();
1181
1182    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property))
1183      return false;
1184
1185    unsigned int count = get_subtable_count ();
1186    for (unsigned int i = 0; i < count; i++)
1187      if (get_subtable (i).apply (c, lookup_type))
1188	return true;
1189
1190    return false;
1191  }
1192
1193  inline bool apply_string (hb_apply_context_t *c) const
1194  {
1195    bool ret = false;
1196
1197    if (unlikely (!c->buffer->len))
1198      return false;
1199
1200    c->set_lookup (*this);
1201
1202    if (likely (!is_reverse ()))
1203    {
1204	/* in/out forward substitution */
1205	c->buffer->clear_output ();
1206	c->buffer->idx = 0;
1207
1208	/* Fast path for lookups with one coverage only (which is most). */
1209	const Coverage *coverage = get_coverage ();
1210	if (coverage)
1211	  while (c->buffer->idx < c->buffer->len)
1212	  {
1213	    if ((c->buffer->cur().mask & c->lookup_mask) &&
1214		coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED &&
1215		apply_once (c))
1216	      ret = true;
1217	    else
1218	      c->buffer->next_glyph ();
1219	  }
1220	else
1221	  while (c->buffer->idx < c->buffer->len)
1222	  {
1223	    if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
1224	      ret = true;
1225	    else
1226	      c->buffer->next_glyph ();
1227
1228	  }
1229	if (ret)
1230	  c->buffer->swap_buffers ();
1231    }
1232    else
1233    {
1234	/* in-place backward substitution */
1235	c->buffer->idx = c->buffer->len - 1;
1236	do
1237	{
1238	  if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
1239	    ret = true;
1240	  else
1241	    c->buffer->idx--;
1242
1243	}
1244	while ((int) c->buffer->idx >= 0);
1245    }
1246
1247    return ret;
1248  }
1249
1250  inline bool sanitize (hb_sanitize_context_t *c) {
1251    TRACE_SANITIZE ();
1252    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1253    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
1254    if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
1255
1256    if (unlikely (get_type () == SubstLookupSubTable::Extension))
1257    {
1258      /* The spec says all subtables of an Extension lookup should
1259       * have the same type.  This is specially important if one has
1260       * a reverse type!
1261       *
1262       * We just check that they are all either forward, or reverse. */
1263      unsigned int type = get_subtable (0).u.extension.get_type ();
1264      unsigned int count = get_subtable_count ();
1265      for (unsigned int i = 1; i < count; i++)
1266        if (get_subtable (i).u.extension.get_type () != type)
1267	  return TRACE_RETURN (false);
1268    }
1269    return TRACE_RETURN (true);
1270  }
1271};
1272
1273typedef OffsetListOf<SubstLookup> SubstLookupList;
1274
1275/*
1276 * GSUB -- The Glyph Substitution Table
1277 */
1278
1279struct GSUB : GSUBGPOS
1280{
1281  static const hb_tag_t Tag	= HB_OT_TAG_GSUB;
1282
1283  inline const SubstLookup& get_lookup (unsigned int i) const
1284  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1285
1286  inline bool would_substitute_lookup (hb_would_apply_context_t *c, unsigned int lookup_index) const
1287  { return get_lookup (lookup_index).would_apply (c); }
1288
1289  inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
1290  { return get_lookup (lookup_index).apply_string (c); }
1291
1292  static inline void substitute_start (hb_buffer_t *buffer);
1293  static inline void substitute_finish (hb_buffer_t *buffer);
1294
1295  inline void closure_lookup (hb_closure_context_t *c,
1296			      unsigned int          lookup_index) const
1297  { return get_lookup (lookup_index).closure (c); }
1298
1299  inline bool sanitize (hb_sanitize_context_t *c) {
1300    TRACE_SANITIZE ();
1301    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1302    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1303    return TRACE_RETURN (list.sanitize (c, this));
1304  }
1305  public:
1306  DEFINE_SIZE_STATIC (10);
1307};
1308
1309
1310void
1311GSUB::substitute_start (hb_buffer_t *buffer)
1312{
1313  HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
1314  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1315  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1316
1317  unsigned int count = buffer->len;
1318  for (unsigned int i = 0; i < count; i++)
1319    buffer->info[i].props_cache() = buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
1320}
1321
1322void
1323GSUB::substitute_finish (hb_buffer_t *buffer HB_UNUSED)
1324{
1325}
1326
1327
1328/* Out-of-class implementation for methods recursing */
1329
1330inline void ExtensionSubst::closure (hb_closure_context_t *c) const
1331{
1332  get_subtable ().closure (c, get_type ());
1333}
1334
1335inline const Coverage & ExtensionSubst::get_coverage (void) const
1336{
1337  return get_subtable ().get_coverage (get_type ());
1338}
1339
1340inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
1341{
1342  return get_subtable ().would_apply (c, get_type ());
1343}
1344
1345inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
1346{
1347  TRACE_APPLY ();
1348  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
1349}
1350
1351inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
1352{
1353  TRACE_SANITIZE ();
1354  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
1355  unsigned int offset = get_offset ();
1356  if (unlikely (!offset)) return TRACE_RETURN (true);
1357  return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
1358}
1359
1360inline bool ExtensionSubst::is_reverse (void) const
1361{
1362  unsigned int type = get_type ();
1363  if (unlikely (type == SubstLookupSubTable::Extension))
1364    return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
1365  return SubstLookup::lookup_type_is_reverse (type);
1366}
1367
1368static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
1369{
1370  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1371  const SubstLookup &l = gsub.get_lookup (lookup_index);
1372
1373  if (unlikely (c->nesting_level_left == 0))
1374    return;
1375
1376  c->nesting_level_left--;
1377  l.closure (c);
1378  c->nesting_level_left++;
1379}
1380
1381static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1382{
1383  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1384  const SubstLookup &l = gsub.get_lookup (lookup_index);
1385
1386  if (unlikely (c->nesting_level_left == 0))
1387    return false;
1388
1389  hb_apply_context_t new_c (*c);
1390  new_c.nesting_level_left--;
1391  new_c.set_lookup (l);
1392  return l.apply_once (&new_c);
1393}
1394
1395
1396
1397#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
1398