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