hb-ot-layout-gsub-table.hh revision 1d3947a6bda6986c9c7d993589053051c119cc81
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
35namespace OT {
36
37
38struct SingleSubstFormat1
39{
40  friend struct SingleSubst;
41
42  private:
43
44  inline void closure (hb_closure_context_t *c) const
45  {
46    TRACE_CLOSURE ();
47    Coverage::Iter iter;
48    for (iter.init (this+coverage); iter.more (); iter.next ()) {
49      hb_codepoint_t glyph_id = iter.get_glyph ();
50      if (c->glyphs->has (glyph_id))
51	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
52    }
53  }
54
55  inline const Coverage &get_coverage (void) const
56  {
57    return this+coverage;
58  }
59
60  inline bool apply (hb_apply_context_t *c) const
61  {
62    TRACE_APPLY ();
63    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
64    unsigned int index = (this+coverage) (glyph_id);
65    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
66
67    /* According to the Adobe Annotated OpenType Suite, result is always
68     * limited to 16bit. */
69    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
70    c->replace_glyph (glyph_id);
71
72    return TRACE_RETURN (true);
73  }
74
75  inline bool serialize (hb_serialize_context_t *c,
76			 Supplier<GlyphID> &glyphs,
77			 unsigned int num_glyphs,
78			 int delta)
79  {
80    TRACE_SERIALIZE ();
81    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
82    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
83    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
84    return TRACE_RETURN (true);
85  }
86
87  inline bool sanitize (hb_sanitize_context_t *c) {
88    TRACE_SANITIZE ();
89    return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
90  }
91
92  protected:
93  USHORT	format;			/* Format identifier--format = 1 */
94  OffsetTo<Coverage>
95		coverage;		/* Offset to Coverage table--from
96					 * beginning of Substitution table */
97  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
98					 * substitute GlyphID */
99  public:
100  DEFINE_SIZE_STATIC (6);
101};
102
103struct SingleSubstFormat2
104{
105  friend struct SingleSubst;
106
107  private:
108
109  inline void closure (hb_closure_context_t *c) const
110  {
111    TRACE_CLOSURE ();
112    Coverage::Iter iter;
113    for (iter.init (this+coverage); iter.more (); iter.next ()) {
114      if (c->glyphs->has (iter.get_glyph ()))
115	c->glyphs->add (substitute[iter.get_coverage ()]);
116    }
117  }
118
119  inline const Coverage &get_coverage (void) const
120  {
121    return this+coverage;
122  }
123
124  inline bool apply (hb_apply_context_t *c) const
125  {
126    TRACE_APPLY ();
127    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
128    unsigned int index = (this+coverage) (glyph_id);
129    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
130
131    if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
132
133    glyph_id = substitute[index];
134    c->replace_glyph (glyph_id);
135
136    return TRACE_RETURN (true);
137  }
138
139  inline bool serialize (hb_serialize_context_t *c,
140			 Supplier<GlyphID> &glyphs,
141			 Supplier<GlyphID> &substitutes,
142			 unsigned int num_glyphs)
143  {
144    TRACE_SERIALIZE ();
145    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
146    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
147    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
148    return TRACE_RETURN (true);
149  }
150
151  inline bool sanitize (hb_sanitize_context_t *c) {
152    TRACE_SANITIZE ();
153    return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
154  }
155
156  protected:
157  USHORT	format;			/* Format identifier--format = 2 */
158  OffsetTo<Coverage>
159		coverage;		/* Offset to Coverage table--from
160					 * beginning of Substitution table */
161  ArrayOf<GlyphID>
162		substitute;		/* Array of substitute
163					 * GlyphIDs--ordered by Coverage Index */
164  public:
165  DEFINE_SIZE_ARRAY (6, substitute);
166};
167
168struct SingleSubst
169{
170  friend struct SubstLookupSubTable;
171  friend struct SubstLookup;
172
173  private:
174
175  inline void closure (hb_closure_context_t *c) const
176  {
177    TRACE_CLOSURE ();
178    switch (u.format) {
179    case 1: u.format1.closure (c); break;
180    case 2: u.format2.closure (c); break;
181    default:                       break;
182    }
183  }
184
185  inline const Coverage &get_coverage (void) const
186  {
187    switch (u.format) {
188    case 1: return u.format1.get_coverage ();
189    case 2: return u.format2.get_coverage ();
190    default:return Null(Coverage);
191    }
192  }
193
194  inline bool apply (hb_apply_context_t *c) const
195  {
196    TRACE_APPLY ();
197    switch (u.format) {
198    case 1: return TRACE_RETURN (u.format1.apply (c));
199    case 2: return TRACE_RETURN (u.format2.apply (c));
200    default:return TRACE_RETURN (false);
201    }
202  }
203
204  inline bool serialize (hb_serialize_context_t *c,
205			 Supplier<GlyphID> &glyphs,
206			 Supplier<GlyphID> &substitutes,
207			 unsigned int num_glyphs)
208  {
209    TRACE_SERIALIZE ();
210    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
211    unsigned int format = 2;
212    int delta;
213    if (num_glyphs) {
214      format = 1;
215      /* TODO(serialize) check for wrap-around */
216      delta = substitutes[0] - glyphs[0];
217      for (unsigned int i = 1; i < num_glyphs; i++)
218	if (delta != substitutes[i] - glyphs[i]) {
219	  format = 2;
220	  break;
221	}
222    }
223    u.format.set (format);
224    switch (u.format) {
225    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
226    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
227    default:return TRACE_RETURN (false);
228    }
229  }
230
231  inline bool sanitize (hb_sanitize_context_t *c) {
232    TRACE_SANITIZE ();
233    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
234    switch (u.format) {
235    case 1: return TRACE_RETURN (u.format1.sanitize (c));
236    case 2: return TRACE_RETURN (u.format2.sanitize (c));
237    default:return TRACE_RETURN (true);
238    }
239  }
240
241  protected:
242  union {
243  USHORT		format;		/* Format identifier */
244  SingleSubstFormat1	format1;
245  SingleSubstFormat2	format2;
246  } u;
247};
248
249
250struct Sequence
251{
252  friend struct MultipleSubstFormat1;
253
254  private:
255
256  inline void closure (hb_closure_context_t *c) const
257  {
258    TRACE_CLOSURE ();
259    unsigned int count = substitute.len;
260    for (unsigned int i = 0; i < count; i++)
261      c->glyphs->add (substitute[i]);
262  }
263
264  inline bool apply (hb_apply_context_t *c) const
265  {
266    TRACE_APPLY ();
267    if (unlikely (!substitute.len)) return TRACE_RETURN (false);
268
269    unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
270    unsigned int count = substitute.len;
271    for (unsigned int i = 0; i < count; i++) {
272      set_lig_props_for_component (c->buffer->cur(), i);
273      c->output_glyph (substitute.array[i], klass);
274    }
275    c->buffer->skip_glyph ();
276
277    return TRACE_RETURN (true);
278  }
279
280  inline bool serialize (hb_serialize_context_t *c,
281			 Supplier<GlyphID> &glyphs,
282			 unsigned int num_glyphs)
283  {
284    TRACE_SERIALIZE ();
285    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
286    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
287    return TRACE_RETURN (true);
288  }
289
290  public:
291  inline bool sanitize (hb_sanitize_context_t *c) {
292    TRACE_SANITIZE ();
293    return TRACE_RETURN (substitute.sanitize (c));
294  }
295
296  protected:
297  ArrayOf<GlyphID>
298		substitute;		/* String of GlyphIDs to substitute */
299  public:
300  DEFINE_SIZE_ARRAY (2, substitute);
301};
302
303struct MultipleSubstFormat1
304{
305  friend struct MultipleSubst;
306
307  private:
308
309  inline void closure (hb_closure_context_t *c) const
310  {
311    TRACE_CLOSURE ();
312    Coverage::Iter iter;
313    for (iter.init (this+coverage); iter.more (); iter.next ()) {
314      if (c->glyphs->has (iter.get_glyph ()))
315	(this+sequence[iter.get_coverage ()]).closure (c);
316    }
317  }
318
319  inline const Coverage &get_coverage (void) const
320  {
321    return this+coverage;
322  }
323
324  inline bool apply (hb_apply_context_t *c) const
325  {
326    TRACE_APPLY ();
327
328    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
329    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
330
331    return TRACE_RETURN ((this+sequence[index]).apply (c));
332  }
333
334  inline bool serialize (hb_serialize_context_t *c,
335			 Supplier<GlyphID> &glyphs,
336			 Supplier<unsigned int> &substitute_len_list,
337			 unsigned int num_glyphs,
338			 Supplier<GlyphID> &substitute_glyphs_list)
339  {
340    TRACE_SERIALIZE ();
341    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
342    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
343    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
344    for (unsigned int i = 0; i < num_glyphs; i++)
345      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
346								substitute_glyphs_list,
347								substitute_len_list[i]))) return TRACE_RETURN (false);
348    substitute_len_list.advance (num_glyphs);
349    return TRACE_RETURN (true);
350  }
351
352  inline bool sanitize (hb_sanitize_context_t *c) {
353    TRACE_SANITIZE ();
354    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
355  }
356
357  protected:
358  USHORT	format;			/* Format identifier--format = 1 */
359  OffsetTo<Coverage>
360		coverage;		/* Offset to Coverage table--from
361					 * beginning of Substitution table */
362  OffsetArrayOf<Sequence>
363		sequence;		/* Array of Sequence tables
364					 * ordered by Coverage Index */
365  public:
366  DEFINE_SIZE_ARRAY (6, sequence);
367};
368
369struct MultipleSubst
370{
371  friend struct SubstLookupSubTable;
372  friend struct SubstLookup;
373
374  private:
375
376  inline void closure (hb_closure_context_t *c) const
377  {
378    TRACE_CLOSURE ();
379    switch (u.format) {
380    case 1: u.format1.closure (c); break;
381    default:                       break;
382    }
383  }
384
385  inline const Coverage &get_coverage (void) const
386  {
387    switch (u.format) {
388    case 1: return u.format1.get_coverage ();
389    default:return Null(Coverage);
390    }
391  }
392
393  inline bool apply (hb_apply_context_t *c) const
394  {
395    TRACE_APPLY ();
396    switch (u.format) {
397    case 1: return TRACE_RETURN (u.format1.apply (c));
398    default:return TRACE_RETURN (false);
399    }
400  }
401
402  inline bool serialize (hb_serialize_context_t *c,
403			 Supplier<GlyphID> &glyphs,
404			 Supplier<unsigned int> &substitute_len_list,
405			 unsigned int num_glyphs,
406			 Supplier<GlyphID> &substitute_glyphs_list)
407  {
408    TRACE_SERIALIZE ();
409    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
410    unsigned int format = 1;
411    u.format.set (format);
412    switch (u.format) {
413    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
414    default:return TRACE_RETURN (false);
415    }
416  }
417
418  inline bool sanitize (hb_sanitize_context_t *c) {
419    TRACE_SANITIZE ();
420    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
421    switch (u.format) {
422    case 1: return TRACE_RETURN (u.format1.sanitize (c));
423    default:return TRACE_RETURN (true);
424    }
425  }
426
427  protected:
428  union {
429  USHORT		format;		/* Format identifier */
430  MultipleSubstFormat1	format1;
431  } u;
432};
433
434
435typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
436					 * arbitrary order */
437
438struct AlternateSubstFormat1
439{
440  friend struct AlternateSubst;
441
442  private:
443
444  inline void closure (hb_closure_context_t *c) const
445  {
446    TRACE_CLOSURE ();
447    Coverage::Iter iter;
448    for (iter.init (this+coverage); iter.more (); iter.next ()) {
449      if (c->glyphs->has (iter.get_glyph ())) {
450	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
451	unsigned int count = alt_set.len;
452	for (unsigned int i = 0; i < count; i++)
453	  c->glyphs->add (alt_set[i]);
454      }
455    }
456  }
457
458  inline const Coverage &get_coverage (void) const
459  {
460    return this+coverage;
461  }
462
463  inline bool apply (hb_apply_context_t *c) const
464  {
465    TRACE_APPLY ();
466    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
467
468    unsigned int index = (this+coverage) (glyph_id);
469    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
470
471    const AlternateSet &alt_set = this+alternateSet[index];
472
473    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
474
475    hb_mask_t glyph_mask = c->buffer->cur().mask;
476    hb_mask_t lookup_mask = c->lookup_mask;
477
478    /* Note: This breaks badly if two features enabled this lookup together. */
479    unsigned int shift = _hb_ctz (lookup_mask);
480    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
481
482    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
483
484    glyph_id = alt_set[alt_index - 1];
485
486    c->replace_glyph (glyph_id);
487
488    return TRACE_RETURN (true);
489  }
490
491  inline bool serialize (hb_serialize_context_t *c,
492			 Supplier<GlyphID> &glyphs,
493			 Supplier<unsigned int> &alternate_len_list,
494			 unsigned int num_glyphs,
495			 Supplier<GlyphID> &alternate_glyphs_list)
496  {
497    TRACE_SERIALIZE ();
498    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
499    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
500    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
501    for (unsigned int i = 0; i < num_glyphs; i++)
502      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
503								    alternate_glyphs_list,
504								    alternate_len_list[i]))) return TRACE_RETURN (false);
505    alternate_len_list.advance (num_glyphs);
506    return TRACE_RETURN (true);
507  }
508
509  inline bool sanitize (hb_sanitize_context_t *c) {
510    TRACE_SANITIZE ();
511    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
512  }
513
514  protected:
515  USHORT	format;			/* Format identifier--format = 1 */
516  OffsetTo<Coverage>
517		coverage;		/* Offset to Coverage table--from
518					 * beginning of Substitution table */
519  OffsetArrayOf<AlternateSet>
520		alternateSet;		/* Array of AlternateSet tables
521					 * ordered by Coverage Index */
522  public:
523  DEFINE_SIZE_ARRAY (6, alternateSet);
524};
525
526struct AlternateSubst
527{
528  friend struct SubstLookupSubTable;
529  friend struct SubstLookup;
530
531  private:
532
533  inline void closure (hb_closure_context_t *c) const
534  {
535    TRACE_CLOSURE ();
536    switch (u.format) {
537    case 1: u.format1.closure (c); break;
538    default:                       break;
539    }
540  }
541
542  inline const Coverage &get_coverage (void) const
543  {
544    switch (u.format) {
545    case 1: return u.format1.get_coverage ();
546    default:return Null(Coverage);
547    }
548  }
549
550  inline bool apply (hb_apply_context_t *c) const
551  {
552    TRACE_APPLY ();
553    switch (u.format) {
554    case 1: return TRACE_RETURN (u.format1.apply (c));
555    default:return TRACE_RETURN (false);
556    }
557  }
558
559  inline bool serialize (hb_serialize_context_t *c,
560			 Supplier<GlyphID> &glyphs,
561			 Supplier<unsigned int> &alternate_len_list,
562			 unsigned int num_glyphs,
563			 Supplier<GlyphID> &alternate_glyphs_list)
564  {
565    TRACE_SERIALIZE ();
566    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
567    unsigned int format = 1;
568    u.format.set (format);
569    switch (u.format) {
570    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
571    default:return TRACE_RETURN (false);
572    }
573  }
574
575  inline bool sanitize (hb_sanitize_context_t *c) {
576    TRACE_SANITIZE ();
577    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
578    switch (u.format) {
579    case 1: return TRACE_RETURN (u.format1.sanitize (c));
580    default:return TRACE_RETURN (true);
581    }
582  }
583
584  protected:
585  union {
586  USHORT		format;		/* Format identifier */
587  AlternateSubstFormat1	format1;
588  } u;
589};
590
591
592struct Ligature
593{
594  friend struct LigatureSet;
595
596  private:
597
598  inline void closure (hb_closure_context_t *c) const
599  {
600    TRACE_CLOSURE ();
601    unsigned int count = component.len;
602    for (unsigned int i = 1; i < count; i++)
603      if (!c->glyphs->has (component[i]))
604        return;
605    c->glyphs->add (ligGlyph);
606  }
607
608  inline bool would_apply (hb_would_apply_context_t *c) const
609  {
610    if (c->len != component.len)
611      return false;
612
613    for (unsigned int i = 1; i < c->len; i++)
614      if (likely (c->glyphs[i] != component[i]))
615	return false;
616
617    return true;
618  }
619
620  inline bool apply (hb_apply_context_t *c) const
621  {
622    TRACE_APPLY ();
623    unsigned int count = component.len;
624    if (unlikely (count < 1)) return TRACE_RETURN (false);
625
626    unsigned int end_offset;
627    bool is_mark_ligature;
628    unsigned int total_component_count;
629
630    if (likely (!match_input (c, count,
631			      &component[1],
632			      match_glyph,
633			      NULL,
634			      &end_offset,
635			      &is_mark_ligature,
636			      &total_component_count)))
637      return TRACE_RETURN (false);
638
639    /* Deal, we are forming the ligature. */
640    c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
641
642    ligate_input (c,
643		  count,
644		  &component[1],
645		  ligGlyph,
646		  match_glyph,
647		  NULL,
648		  is_mark_ligature,
649		  total_component_count);
650
651    return TRACE_RETURN (true);
652  }
653
654  inline bool serialize (hb_serialize_context_t *c,
655			 GlyphID ligature,
656			 Supplier<GlyphID> &components, /* Starting from second */
657			 unsigned int num_components /* Including first component */)
658  {
659    TRACE_SERIALIZE ();
660    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
661    ligGlyph.set (ligature);
662    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
663    return TRACE_RETURN (true);
664  }
665
666  public:
667  inline bool sanitize (hb_sanitize_context_t *c) {
668    TRACE_SANITIZE ();
669    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
670  }
671
672  protected:
673  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
674  HeadlessArrayOf<GlyphID>
675		component;		/* Array of component GlyphIDs--start
676					 * with the second  component--ordered
677					 * in writing direction */
678  public:
679  DEFINE_SIZE_ARRAY (4, component);
680};
681
682struct LigatureSet
683{
684  friend struct LigatureSubstFormat1;
685
686  private:
687
688  inline void closure (hb_closure_context_t *c) const
689  {
690    TRACE_CLOSURE ();
691    unsigned int num_ligs = ligature.len;
692    for (unsigned int i = 0; i < num_ligs; i++)
693      (this+ligature[i]).closure (c);
694  }
695
696  inline bool would_apply (hb_would_apply_context_t *c) const
697  {
698    unsigned int num_ligs = ligature.len;
699    for (unsigned int i = 0; i < num_ligs; i++)
700    {
701      const Ligature &lig = this+ligature[i];
702      if (lig.would_apply (c))
703        return true;
704    }
705    return false;
706  }
707
708  inline bool apply (hb_apply_context_t *c) const
709  {
710    TRACE_APPLY ();
711    unsigned int num_ligs = ligature.len;
712    for (unsigned int i = 0; i < num_ligs; i++)
713    {
714      const Ligature &lig = this+ligature[i];
715      if (lig.apply (c)) return TRACE_RETURN (true);
716    }
717
718    return TRACE_RETURN (false);
719  }
720
721  inline bool serialize (hb_serialize_context_t *c,
722			 Supplier<GlyphID> &ligatures,
723			 Supplier<unsigned int> &component_count_list,
724			 unsigned int num_ligatures,
725			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
726  {
727    TRACE_SERIALIZE ();
728    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
729    if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
730    for (unsigned int i = 0; i < num_ligatures; i++)
731      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
732								ligatures[i],
733								component_list,
734								component_count_list[i]))) return TRACE_RETURN (false);
735    component_count_list.advance (num_ligatures);
736    return TRACE_RETURN (true);
737  }
738
739  public:
740  inline bool sanitize (hb_sanitize_context_t *c) {
741    TRACE_SANITIZE ();
742    return TRACE_RETURN (ligature.sanitize (c, this));
743  }
744
745  protected:
746  OffsetArrayOf<Ligature>
747		ligature;		/* Array LigatureSet tables
748					 * ordered by preference */
749  public:
750  DEFINE_SIZE_ARRAY (2, ligature);
751};
752
753struct LigatureSubstFormat1
754{
755  friend struct LigatureSubst;
756
757  private:
758
759  inline void closure (hb_closure_context_t *c) const
760  {
761    TRACE_CLOSURE ();
762    Coverage::Iter iter;
763    for (iter.init (this+coverage); iter.more (); iter.next ()) {
764      if (c->glyphs->has (iter.get_glyph ()))
765	(this+ligatureSet[iter.get_coverage ()]).closure (c);
766    }
767  }
768
769  inline const Coverage &get_coverage (void) const
770  {
771    return this+coverage;
772  }
773
774  inline bool would_apply (hb_would_apply_context_t *c) const
775  {
776    return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c);
777  }
778
779  inline bool apply (hb_apply_context_t *c) const
780  {
781    TRACE_APPLY ();
782    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
783
784    unsigned int index = (this+coverage) (glyph_id);
785    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
786
787    const LigatureSet &lig_set = this+ligatureSet[index];
788    return TRACE_RETURN (lig_set.apply (c));
789  }
790
791  inline bool serialize (hb_serialize_context_t *c,
792			 Supplier<GlyphID> &first_glyphs,
793			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
794			 unsigned int num_first_glyphs,
795			 Supplier<GlyphID> &ligatures_list,
796			 Supplier<unsigned int> &component_count_list,
797			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
798  {
799    TRACE_SERIALIZE ();
800    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
801    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
802    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
803    for (unsigned int i = 0; i < num_first_glyphs; i++)
804      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
805								   ligatures_list,
806								   component_count_list,
807								   ligature_per_first_glyph_count_list[i],
808								   component_list))) return TRACE_RETURN (false);
809    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
810    return TRACE_RETURN (true);
811  }
812
813  inline bool sanitize (hb_sanitize_context_t *c) {
814    TRACE_SANITIZE ();
815    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
816  }
817
818  protected:
819  USHORT	format;			/* Format identifier--format = 1 */
820  OffsetTo<Coverage>
821		coverage;		/* Offset to Coverage table--from
822					 * beginning of Substitution table */
823  OffsetArrayOf<LigatureSet>
824		ligatureSet;		/* Array LigatureSet tables
825					 * ordered by Coverage Index */
826  public:
827  DEFINE_SIZE_ARRAY (6, ligatureSet);
828};
829
830struct LigatureSubst
831{
832  friend struct SubstLookupSubTable;
833  friend struct SubstLookup;
834
835  private:
836
837  inline void closure (hb_closure_context_t *c) const
838  {
839    TRACE_CLOSURE ();
840    switch (u.format) {
841    case 1: u.format1.closure (c); break;
842    default:                       break;
843    }
844  }
845
846  inline const Coverage &get_coverage (void) const
847  {
848    switch (u.format) {
849    case 1: return u.format1.get_coverage ();
850    default:return Null(Coverage);
851    }
852  }
853
854  inline bool would_apply (hb_would_apply_context_t *c) const
855  {
856    switch (u.format) {
857    case 1: return u.format1.would_apply (c);
858    default:return false;
859    }
860  }
861
862  inline bool apply (hb_apply_context_t *c) const
863  {
864    TRACE_APPLY ();
865    switch (u.format) {
866    case 1: return TRACE_RETURN (u.format1.apply (c));
867    default:return TRACE_RETURN (false);
868    }
869  }
870
871  inline bool serialize (hb_serialize_context_t *c,
872			 Supplier<GlyphID> &first_glyphs,
873			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
874			 unsigned int num_first_glyphs,
875			 Supplier<GlyphID> &ligatures_list,
876			 Supplier<unsigned int> &component_count_list,
877			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
878  {
879    TRACE_SERIALIZE ();
880    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
881    unsigned int format = 1;
882    u.format.set (format);
883    switch (u.format) {
884    case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
885						      ligatures_list, component_count_list, component_list));
886    default:return TRACE_RETURN (false);
887    }
888  }
889
890  inline bool sanitize (hb_sanitize_context_t *c) {
891    TRACE_SANITIZE ();
892    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
893    switch (u.format) {
894    case 1: return TRACE_RETURN (u.format1.sanitize (c));
895    default:return TRACE_RETURN (true);
896    }
897  }
898
899  protected:
900  union {
901  USHORT		format;		/* Format identifier */
902  LigatureSubstFormat1	format1;
903  } u;
904};
905
906
907static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
908static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
909
910struct ContextSubst : Context
911{
912  friend struct SubstLookupSubTable;
913
914  private:
915
916  inline void closure (hb_closure_context_t *c) const
917  {
918    TRACE_CLOSURE ();
919    return Context::closure (c, closure_lookup);
920  }
921
922  inline bool apply (hb_apply_context_t *c) const
923  {
924    TRACE_APPLY ();
925    return TRACE_RETURN (Context::apply (c, substitute_lookup));
926  }
927};
928
929struct ChainContextSubst : ChainContext
930{
931  friend struct SubstLookupSubTable;
932
933  private:
934
935  inline void closure (hb_closure_context_t *c) const
936  {
937    TRACE_CLOSURE ();
938    return ChainContext::closure (c, closure_lookup);
939  }
940
941  inline bool apply (hb_apply_context_t *c) const
942  {
943    TRACE_APPLY ();
944    return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
945  }
946};
947
948
949struct ExtensionSubst : Extension
950{
951  friend struct SubstLookupSubTable;
952  friend struct SubstLookup;
953
954  private:
955  inline const struct SubstLookupSubTable& get_subtable (void) const
956  {
957    unsigned int offset = get_offset ();
958    if (unlikely (!offset)) return Null(SubstLookupSubTable);
959    return StructAtOffset<SubstLookupSubTable> (this, offset);
960  }
961
962  inline void closure (hb_closure_context_t *c) const;
963
964  inline const Coverage &get_coverage (void) const;
965
966  inline bool would_apply (hb_would_apply_context_t *c) const;
967
968  inline bool apply (hb_apply_context_t *c) const;
969
970  inline bool sanitize (hb_sanitize_context_t *c);
971
972  inline bool is_reverse (void) const;
973};
974
975
976struct ReverseChainSingleSubstFormat1
977{
978  friend struct ReverseChainSingleSubst;
979
980  private:
981
982  inline void closure (hb_closure_context_t *c) const
983  {
984    TRACE_CLOSURE ();
985    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
986
987    unsigned int count;
988
989    count = backtrack.len;
990    for (unsigned int i = 0; i < count; i++)
991      if (!(this+backtrack[i]).intersects (c->glyphs))
992        return;
993
994    count = lookahead.len;
995    for (unsigned int i = 0; i < count; i++)
996      if (!(this+lookahead[i]).intersects (c->glyphs))
997        return;
998
999    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1000    Coverage::Iter iter;
1001    for (iter.init (this+coverage); iter.more (); iter.next ()) {
1002      if (c->glyphs->has (iter.get_glyph ()))
1003	c->glyphs->add (substitute[iter.get_coverage ()]);
1004    }
1005  }
1006
1007  inline const Coverage &get_coverage (void) const
1008  {
1009    return this+coverage;
1010  }
1011
1012  inline bool apply (hb_apply_context_t *c) const
1013  {
1014    TRACE_APPLY ();
1015    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
1016      return TRACE_RETURN (false); /* No chaining to this type */
1017
1018    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1019    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1020
1021    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1022    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1023
1024    if (match_backtrack (c,
1025			 backtrack.len, (USHORT *) backtrack.array,
1026			 match_coverage, this) &&
1027        match_lookahead (c,
1028			 lookahead.len, (USHORT *) lookahead.array,
1029			 match_coverage, this,
1030			 1))
1031    {
1032      c->replace_glyph_inplace (substitute[index]);
1033      c->buffer->idx--; /* Reverse! */
1034      return TRACE_RETURN (true);
1035    }
1036
1037    return TRACE_RETURN (false);
1038  }
1039
1040  inline bool sanitize (hb_sanitize_context_t *c) {
1041    TRACE_SANITIZE ();
1042    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1043      return TRACE_RETURN (false);
1044    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1045    if (!lookahead.sanitize (c, this))
1046      return TRACE_RETURN (false);
1047    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1048    return TRACE_RETURN (substitute.sanitize (c));
1049  }
1050
1051  protected:
1052  USHORT	format;			/* Format identifier--format = 1 */
1053  OffsetTo<Coverage>
1054		coverage;		/* Offset to Coverage table--from
1055					 * beginning of table */
1056  OffsetArrayOf<Coverage>
1057		backtrack;		/* Array of coverage tables
1058					 * in backtracking sequence, in  glyph
1059					 * sequence order */
1060  OffsetArrayOf<Coverage>
1061		lookaheadX;		/* Array of coverage tables
1062					 * in lookahead sequence, in glyph
1063					 * sequence order */
1064  ArrayOf<GlyphID>
1065		substituteX;		/* Array of substitute
1066					 * GlyphIDs--ordered by Coverage Index */
1067  public:
1068  DEFINE_SIZE_MIN (10);
1069};
1070
1071struct ReverseChainSingleSubst
1072{
1073  friend struct SubstLookupSubTable;
1074
1075  private:
1076
1077  inline void closure (hb_closure_context_t *c) const
1078  {
1079    TRACE_CLOSURE ();
1080    switch (u.format) {
1081    case 1: u.format1.closure (c); break;
1082    default:                       break;
1083    }
1084  }
1085
1086  inline const Coverage &get_coverage (void) const
1087  {
1088    switch (u.format) {
1089    case 1: return u.format1.get_coverage ();
1090    default:return Null(Coverage);
1091    }
1092  }
1093
1094  inline bool apply (hb_apply_context_t *c) const
1095  {
1096    TRACE_APPLY ();
1097    switch (u.format) {
1098    case 1: return TRACE_RETURN (u.format1.apply (c));
1099    default:return TRACE_RETURN (false);
1100    }
1101  }
1102
1103  inline bool sanitize (hb_sanitize_context_t *c) {
1104    TRACE_SANITIZE ();
1105    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1106    switch (u.format) {
1107    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1108    default:return TRACE_RETURN (true);
1109    }
1110  }
1111
1112  protected:
1113  union {
1114  USHORT				format;		/* Format identifier */
1115  ReverseChainSingleSubstFormat1	format1;
1116  } u;
1117};
1118
1119
1120
1121/*
1122 * SubstLookup
1123 */
1124
1125struct SubstLookupSubTable
1126{
1127  friend struct SubstLookup;
1128
1129  enum Type {
1130    Single		= 1,
1131    Multiple		= 2,
1132    Alternate		= 3,
1133    Ligature		= 4,
1134    Context		= 5,
1135    ChainContext	= 6,
1136    Extension		= 7,
1137    ReverseChainSingle	= 8
1138  };
1139
1140  inline void closure (hb_closure_context_t *c,
1141		       unsigned int    lookup_type) const
1142  {
1143    TRACE_CLOSURE ();
1144    switch (lookup_type) {
1145    case Single:		u.single.closure (c); break;
1146    case Multiple:		u.multiple.closure (c); break;
1147    case Alternate:		u.alternate.closure (c); break;
1148    case Ligature:		u.ligature.closure (c); break;
1149    case Context:		u.context.closure (c); break;
1150    case ChainContext:		u.chainContext.closure (c); break;
1151    case Extension:		u.extension.closure (c); break;
1152    case ReverseChainSingle:	u.reverseChainContextSingle.closure (c); break;
1153    default:                    break;
1154    }
1155  }
1156
1157  inline const Coverage &get_coverage (unsigned int lookup_type) const
1158  {
1159    switch (lookup_type) {
1160    case Single:		return u.single.get_coverage ();
1161    case Multiple:		return u.multiple.get_coverage ();
1162    case Alternate:		return u.alternate.get_coverage ();
1163    case Ligature:		return u.ligature.get_coverage ();
1164    case Context:		return u.context.get_coverage ();
1165    case ChainContext:		return u.chainContext.get_coverage ();
1166    case Extension:		return u.extension.get_coverage ();
1167    case ReverseChainSingle:	return u.reverseChainContextSingle.get_coverage ();
1168    default:			return Null(Coverage);
1169    }
1170  }
1171
1172  inline bool would_apply (hb_would_apply_context_t *c,
1173			   unsigned int lookup_type) const
1174  {
1175    TRACE_WOULD_APPLY ();
1176    if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false;
1177    if (c->len == 1) {
1178      switch (lookup_type) {
1179      case Single:
1180      case Multiple:
1181      case Alternate:
1182      case ReverseChainSingle:
1183        return true;
1184      }
1185    }
1186
1187    /* Only need to look further for lookups that support substitutions
1188     * of input longer than 1. */
1189    switch (lookup_type) {
1190    case Ligature:		return u.ligature.would_apply (c);
1191    case Context:		return u.context.would_apply (c);
1192    case ChainContext:		return u.chainContext.would_apply (c);
1193    case Extension:		return u.extension.would_apply (c);
1194    default:			return false;
1195    }
1196  }
1197
1198  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1199  {
1200    TRACE_APPLY ();
1201    switch (lookup_type) {
1202    case Single:		return TRACE_RETURN (u.single.apply (c));
1203    case Multiple:		return TRACE_RETURN (u.multiple.apply (c));
1204    case Alternate:		return TRACE_RETURN (u.alternate.apply (c));
1205    case Ligature:		return TRACE_RETURN (u.ligature.apply (c));
1206    case Context:		return TRACE_RETURN (u.context.apply (c));
1207    case ChainContext:		return TRACE_RETURN (u.chainContext.apply (c));
1208    case Extension:		return TRACE_RETURN (u.extension.apply (c));
1209    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
1210    default:			return TRACE_RETURN (false);
1211    }
1212  }
1213
1214  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1215    TRACE_SANITIZE ();
1216    if (!u.header.sub_format.sanitize (c))
1217      return TRACE_RETURN (false);
1218    switch (lookup_type) {
1219    case Single:		return TRACE_RETURN (u.single.sanitize (c));
1220    case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
1221    case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
1222    case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
1223    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1224    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
1225    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
1226    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
1227    default:			return TRACE_RETURN (true);
1228    }
1229  }
1230
1231  protected:
1232  union {
1233  struct {
1234    USHORT			sub_format;
1235  } header;
1236  SingleSubst			single;
1237  MultipleSubst			multiple;
1238  AlternateSubst		alternate;
1239  LigatureSubst			ligature;
1240  ContextSubst			context;
1241  ChainContextSubst		chainContext;
1242  ExtensionSubst		extension;
1243  ReverseChainSingleSubst	reverseChainContextSingle;
1244  } u;
1245  public:
1246  DEFINE_SIZE_UNION (2, header.sub_format);
1247};
1248
1249
1250struct SubstLookup : Lookup
1251{
1252  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1253  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
1254
1255  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1256  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
1257
1258  inline bool is_reverse (void) const
1259  {
1260    unsigned int type = get_type ();
1261    if (unlikely (type == SubstLookupSubTable::Extension))
1262      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
1263    return lookup_type_is_reverse (type);
1264  }
1265
1266  inline void closure (hb_closure_context_t *c) const
1267  {
1268    unsigned int lookup_type = get_type ();
1269    unsigned int count = get_subtable_count ();
1270    for (unsigned int i = 0; i < count; i++)
1271      get_subtable (i).closure (c, lookup_type);
1272  }
1273
1274  template <typename set_t>
1275  inline void add_coverage (set_t *glyphs) const
1276  {
1277    const Coverage *last = NULL;
1278    unsigned int count = get_subtable_count ();
1279    for (unsigned int i = 0; i < count; i++) {
1280      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
1281      if (c != last) {
1282        c->add_coverage (glyphs);
1283        last = c;
1284      }
1285    }
1286  }
1287
1288  inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
1289  {
1290    if (unlikely (!c->len)) return false;
1291    if (!digest->may_have (c->glyphs[0])) return false;
1292    unsigned int lookup_type = get_type ();
1293    unsigned int count = get_subtable_count ();
1294    for (unsigned int i = 0; i < count; i++)
1295      if (get_subtable (i).would_apply (c, lookup_type))
1296	return true;
1297    return false;
1298  }
1299
1300  inline bool apply_once (hb_apply_context_t *c) const
1301  {
1302    unsigned int lookup_type = get_type ();
1303
1304    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
1305      return false;
1306
1307    unsigned int count = get_subtable_count ();
1308    for (unsigned int i = 0; i < count; i++)
1309      if (get_subtable (i).apply (c, lookup_type))
1310	return true;
1311
1312    return false;
1313  }
1314
1315  inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
1316  {
1317    bool ret = false;
1318
1319    if (unlikely (!c->buffer->len || !c->lookup_mask))
1320      return false;
1321
1322    c->set_lookup (*this);
1323
1324    if (likely (!is_reverse ()))
1325    {
1326	/* in/out forward substitution */
1327	c->buffer->clear_output ();
1328	c->buffer->idx = 0;
1329
1330	while (c->buffer->idx < c->buffer->len)
1331	{
1332	  if ((c->buffer->cur().mask & c->lookup_mask) &&
1333	      digest->may_have (c->buffer->cur().codepoint) &&
1334	      apply_once (c))
1335	    ret = true;
1336	  else
1337	    c->buffer->next_glyph ();
1338	}
1339	if (ret)
1340	  c->buffer->swap_buffers ();
1341    }
1342    else
1343    {
1344	/* in-place backward substitution */
1345	c->buffer->idx = c->buffer->len - 1;
1346	do
1347	{
1348	  if ((c->buffer->cur().mask & c->lookup_mask) &&
1349	      digest->may_have (c->buffer->cur().codepoint) &&
1350	      apply_once (c))
1351	    ret = true;
1352	  else
1353	    c->buffer->idx--;
1354
1355	}
1356	while ((int) c->buffer->idx >= 0);
1357    }
1358
1359    return ret;
1360  }
1361
1362  private:
1363  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1364						  unsigned int i)
1365  { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
1366  public:
1367
1368  inline bool serialize_single (hb_serialize_context_t *c,
1369				uint32_t lookup_props,
1370			        Supplier<GlyphID> &glyphs,
1371			        Supplier<GlyphID> &substitutes,
1372			        unsigned int num_glyphs)
1373  {
1374    TRACE_SERIALIZE ();
1375    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
1376    return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1377  }
1378
1379  inline bool serialize_multiple (hb_serialize_context_t *c,
1380				  uint32_t lookup_props,
1381				  Supplier<GlyphID> &glyphs,
1382				  Supplier<unsigned int> &substitute_len_list,
1383				  unsigned int num_glyphs,
1384				  Supplier<GlyphID> &substitute_glyphs_list)
1385  {
1386    TRACE_SERIALIZE ();
1387    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
1388    return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
1389									 substitute_glyphs_list));
1390  }
1391
1392  inline bool serialize_alternate (hb_serialize_context_t *c,
1393				   uint32_t lookup_props,
1394				   Supplier<GlyphID> &glyphs,
1395				   Supplier<unsigned int> &alternate_len_list,
1396				   unsigned int num_glyphs,
1397				   Supplier<GlyphID> &alternate_glyphs_list)
1398  {
1399    TRACE_SERIALIZE ();
1400    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
1401    return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
1402									  alternate_glyphs_list));
1403  }
1404
1405  inline bool serialize_ligature (hb_serialize_context_t *c,
1406				  uint32_t lookup_props,
1407				  Supplier<GlyphID> &first_glyphs,
1408				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1409				  unsigned int num_first_glyphs,
1410				  Supplier<GlyphID> &ligatures_list,
1411				  Supplier<unsigned int> &component_count_list,
1412				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1413  {
1414    TRACE_SERIALIZE ();
1415    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
1416    return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
1417									 ligatures_list, component_count_list, component_list));
1418  }
1419
1420  inline bool sanitize (hb_sanitize_context_t *c)
1421  {
1422    TRACE_SANITIZE ();
1423    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1424    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
1425    if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
1426
1427    if (unlikely (get_type () == SubstLookupSubTable::Extension))
1428    {
1429      /* The spec says all subtables of an Extension lookup should
1430       * have the same type.  This is specially important if one has
1431       * a reverse type!
1432       *
1433       * We just check that they are all either forward, or reverse. */
1434      unsigned int type = get_subtable (0).u.extension.get_type ();
1435      unsigned int count = get_subtable_count ();
1436      for (unsigned int i = 1; i < count; i++)
1437        if (get_subtable (i).u.extension.get_type () != type)
1438	  return TRACE_RETURN (false);
1439    }
1440    return TRACE_RETURN (true);
1441  }
1442};
1443
1444typedef OffsetListOf<SubstLookup> SubstLookupList;
1445
1446/*
1447 * GSUB -- The Glyph Substitution Table
1448 */
1449
1450struct GSUB : GSUBGPOS
1451{
1452  static const hb_tag_t Tag	= HB_OT_TAG_GSUB;
1453
1454  inline const SubstLookup& get_lookup (unsigned int i) const
1455  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
1456
1457  template <typename set_t>
1458  inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
1459  { get_lookup (lookup_index).add_coverage (glyphs); }
1460
1461  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1462  static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
1463
1464  inline void closure_lookup (hb_closure_context_t *c,
1465			      unsigned int          lookup_index) const
1466  { return get_lookup (lookup_index).closure (c); }
1467
1468  inline bool sanitize (hb_sanitize_context_t *c) {
1469    TRACE_SANITIZE ();
1470    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1471    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1472    return TRACE_RETURN (list.sanitize (c, this));
1473  }
1474  public:
1475  DEFINE_SIZE_STATIC (10);
1476};
1477
1478
1479void
1480GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
1481{
1482  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
1483  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1484  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1485
1486  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
1487  unsigned int count = buffer->len;
1488  for (unsigned int i = 0; i < count; i++) {
1489    buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
1490    buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
1491  }
1492}
1493
1494void
1495GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
1496{
1497}
1498
1499
1500/* Out-of-class implementation for methods recursing */
1501
1502inline void ExtensionSubst::closure (hb_closure_context_t *c) const
1503{
1504  get_subtable ().closure (c, get_type ());
1505}
1506
1507inline const Coverage & ExtensionSubst::get_coverage (void) const
1508{
1509  return get_subtable ().get_coverage (get_type ());
1510}
1511
1512inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
1513{
1514  return get_subtable ().would_apply (c, get_type ());
1515}
1516
1517inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
1518{
1519  TRACE_APPLY ();
1520  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
1521}
1522
1523inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
1524{
1525  TRACE_SANITIZE ();
1526  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
1527  unsigned int offset = get_offset ();
1528  if (unlikely (!offset)) return TRACE_RETURN (true);
1529  return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
1530}
1531
1532inline bool ExtensionSubst::is_reverse (void) const
1533{
1534  unsigned int type = get_type ();
1535  if (unlikely (type == SubstLookupSubTable::Extension))
1536    return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
1537  return SubstLookup::lookup_type_is_reverse (type);
1538}
1539
1540static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
1541{
1542  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1543  const SubstLookup &l = gsub.get_lookup (lookup_index);
1544
1545  if (unlikely (c->nesting_level_left == 0))
1546    return;
1547
1548  c->nesting_level_left--;
1549  l.closure (c);
1550  c->nesting_level_left++;
1551}
1552
1553static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1554{
1555  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1556  const SubstLookup &l = gsub.get_lookup (lookup_index);
1557
1558  if (unlikely (c->nesting_level_left == 0))
1559    return false;
1560
1561  hb_apply_context_t new_c (*c);
1562  new_c.nesting_level_left--;
1563  new_c.set_lookup (l);
1564  return l.apply_once (&new_c);
1565}
1566
1567
1568} // namespace OT
1569
1570
1571#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
1572