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