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