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