Update Copyright headers
[apps/home/video-player.git] / src / hb-ot-layout-gsubgpos-private.hh
1 /*
2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3  * Copyright © 2010  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_GSUBGPOS_PRIVATE_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
31
32 #include "hb-buffer-private.hh"
33 #include "hb-ot-layout-gdef-private.hh"
34
35 HB_BEGIN_DECLS
36
37
38 /* buffer var allocations */
39 #define lig_id() var2.u16[0] /* unique ligature id */
40 #define lig_comp() var2.u16[1] /* component number in the ligature (0 = base) */
41
42
43 #ifndef HB_DEBUG_APPLY
44 #define HB_DEBUG_APPLY (HB_DEBUG+0)
45 #endif
46
47 #define TRACE_APPLY() \
48         hb_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", HB_FUNC, this); \
49
50
51 HB_BEGIN_DECLS
52
53 struct hb_apply_context_t
54 {
55   unsigned int debug_depth;
56   hb_ot_layout_context_t *layout;
57   hb_buffer_t *buffer;
58   hb_mask_t lookup_mask;
59   unsigned int context_length;
60   unsigned int nesting_level_left;
61   unsigned int lookup_props;
62   unsigned int property; /* propety of first glyph */
63
64
65   inline void replace_glyph (hb_codepoint_t glyph_index) const
66   {
67     clear_property ();
68     buffer->replace_glyph (glyph_index);
69   }
70   inline void replace_glyphs_be16 (unsigned int num_in,
71                                    unsigned int num_out,
72                                    const uint16_t *glyph_data_be) const
73   {
74     clear_property ();
75     buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be);
76   }
77
78   inline void guess_glyph_class (unsigned int klass)
79   {
80     /* XXX if ! has gdef */
81     buffer->info[buffer->i].props_cache() = klass;
82   }
83
84   private:
85   inline void clear_property (void) const
86   {
87     /* XXX if has gdef */
88     buffer->info[buffer->i].props_cache() = 0;
89   }
90 };
91
92
93
94 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
95 typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
96
97 struct ContextFuncs
98 {
99   match_func_t match;
100   apply_lookup_func_t apply;
101 };
102
103
104 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
105 {
106   return glyph_id == value;
107 }
108
109 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
110 {
111   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
112   return class_def.get_class (glyph_id) == value;
113 }
114
115 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
116 {
117   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
118   return (data+coverage) (glyph_id) != NOT_COVERED;
119 }
120
121
122 static inline bool match_input (hb_apply_context_t *c,
123                                 unsigned int count, /* Including the first glyph (not matched) */
124                                 const USHORT input[], /* Array of input values--start with second glyph */
125                                 match_func_t match_func,
126                                 const void *match_data,
127                                 unsigned int *context_length_out)
128 {
129   unsigned int i, j;
130   unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
131   if (unlikely (c->buffer->i + count > end))
132     return false;
133
134   for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
135   {
136     while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
137     {
138       if (unlikely (j + count - i == end))
139         return false;
140       j++;
141     }
142
143     if (likely (!match_func (c->buffer->info[j].codepoint, input[i - 1], match_data)))
144       return false;
145   }
146
147   *context_length_out = j - c->buffer->i;
148
149   return true;
150 }
151
152 static inline bool match_backtrack (hb_apply_context_t *c,
153                                     unsigned int count,
154                                     const USHORT backtrack[],
155                                     match_func_t match_func,
156                                     const void *match_data)
157 {
158   if (unlikely (c->buffer->backtrack_len () < count))
159     return false;
160
161   for (unsigned int i = 0, j = c->buffer->backtrack_len () - 1; i < count; i++, j--)
162   {
163     while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->out_info[j], c->lookup_props, NULL))
164     {
165       if (unlikely (j + 1 == count - i))
166         return false;
167       j--;
168     }
169
170     if (likely (!match_func (c->buffer->out_info[j].codepoint, backtrack[i], match_data)))
171       return false;
172   }
173
174   return true;
175 }
176
177 static inline bool match_lookahead (hb_apply_context_t *c,
178                                     unsigned int count,
179                                     const USHORT lookahead[],
180                                     match_func_t match_func,
181                                     const void *match_data,
182                                     unsigned int offset)
183 {
184   unsigned int i, j;
185   unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
186   if (unlikely (c->buffer->i + offset + count > end))
187     return false;
188
189   for (i = 0, j = c->buffer->i + offset; i < count; i++, j++)
190   {
191     while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
192     {
193       if (unlikely (j + count - i == end))
194         return false;
195       j++;
196     }
197
198     if (likely (!match_func (c->buffer->info[j].codepoint, lookahead[i], match_data)))
199       return false;
200   }
201
202   return true;
203 }
204
205 HB_END_DECLS
206
207
208 struct LookupRecord
209 {
210   inline bool sanitize (hb_sanitize_context_t *c) {
211     TRACE_SANITIZE ();
212     return c->check_struct (this);
213   }
214
215   USHORT        sequenceIndex;          /* Index into current glyph
216                                          * sequence--first glyph = 0 */
217   USHORT        lookupListIndex;        /* Lookup to apply to that
218                                          * position--zero--based */
219   public:
220   DEFINE_SIZE_STATIC (4);
221 };
222
223
224 HB_BEGIN_DECLS
225
226 static inline bool apply_lookup (hb_apply_context_t *c,
227                                  unsigned int count, /* Including the first glyph */
228                                  unsigned int lookupCount,
229                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
230                                  apply_lookup_func_t apply_func)
231 {
232   unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
233   if (unlikely (count == 0 || c->buffer->i + count > end))
234     return false;
235
236   /* TODO We don't support lookupRecord arrays that are not increasing:
237    *      Should be easy for in_place ones at least. */
238
239   /* Note: If sublookup is reverse, it will underflow after the first loop
240    * and we jump out of it.  Not entirely disastrous.  So we don't check
241    * for reverse lookup here.
242    */
243   for (unsigned int i = 0; i < count; /* NOP */)
244   {
245     while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, NULL))
246     {
247       if (unlikely (c->buffer->i == end))
248         return true;
249       /* No lookup applied for this index */
250       c->buffer->next_glyph ();
251     }
252
253     if (lookupCount && i == lookupRecord->sequenceIndex)
254     {
255       unsigned int old_pos = c->buffer->i;
256
257       /* Apply a lookup */
258       bool done = apply_func (c, lookupRecord->lookupListIndex);
259
260       lookupRecord++;
261       lookupCount--;
262       /* Err, this is wrong if the lookup jumped over some glyphs */
263       i += c->buffer->i - old_pos;
264       if (unlikely (c->buffer->i == end))
265         return true;
266
267       if (!done)
268         goto not_applied;
269     }
270     else
271     {
272     not_applied:
273       /* No lookup applied for this index */
274       c->buffer->next_glyph ();
275       i++;
276     }
277   }
278
279   return true;
280 }
281
282 HB_END_DECLS
283
284
285 /* Contextual lookups */
286
287 struct ContextLookupContext
288 {
289   ContextFuncs funcs;
290   const void *match_data;
291 };
292
293 static inline bool context_lookup (hb_apply_context_t *c,
294                                    unsigned int inputCount, /* Including the first glyph (not matched) */
295                                    const USHORT input[], /* Array of input values--start with second glyph */
296                                    unsigned int lookupCount,
297                                    const LookupRecord lookupRecord[],
298                                    ContextLookupContext &lookup_context)
299 {
300   hb_apply_context_t new_context = *c;
301   return match_input (c,
302                       inputCount, input,
303                       lookup_context.funcs.match, lookup_context.match_data,
304                       &new_context.context_length)
305       && apply_lookup (&new_context,
306                        inputCount,
307                        lookupCount, lookupRecord,
308                        lookup_context.funcs.apply);
309 }
310
311 struct Rule
312 {
313   friend struct RuleSet;
314
315   private:
316   inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const
317   {
318     TRACE_APPLY ();
319     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
320     return context_lookup (c,
321                            inputCount, input,
322                            lookupCount, lookupRecord,
323                            lookup_context);
324   }
325
326   public:
327   inline bool sanitize (hb_sanitize_context_t *c) {
328     TRACE_SANITIZE ();
329     return inputCount.sanitize (c)
330         && lookupCount.sanitize (c)
331         && c->check_range (input,
332                                  input[0].static_size * inputCount
333                                  + lookupRecordX[0].static_size * lookupCount);
334   }
335
336   private:
337   USHORT        inputCount;             /* Total number of glyphs in input
338                                          * glyph sequence--includes the  first
339                                          * glyph */
340   USHORT        lookupCount;            /* Number of LookupRecords */
341   USHORT        input[VAR];             /* Array of match inputs--start with
342                                          * second glyph */
343   LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
344                                          * design order */
345   public:
346   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
347 };
348
349 struct RuleSet
350 {
351   inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const
352   {
353     TRACE_APPLY ();
354     unsigned int num_rules = rule.len;
355     for (unsigned int i = 0; i < num_rules; i++)
356     {
357       if ((this+rule[i]).apply (c, lookup_context))
358         return true;
359     }
360
361     return false;
362   }
363
364   inline bool sanitize (hb_sanitize_context_t *c) {
365     TRACE_SANITIZE ();
366     return rule.sanitize (c, this);
367   }
368
369   private:
370   OffsetArrayOf<Rule>
371                 rule;                   /* Array of Rule tables
372                                          * ordered by preference */
373   public:
374   DEFINE_SIZE_ARRAY (2, rule);
375 };
376
377
378 struct ContextFormat1
379 {
380   friend struct Context;
381
382   private:
383   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
384   {
385     TRACE_APPLY ();
386     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
387     if (likely (index == NOT_COVERED))
388       return false;
389
390     const RuleSet &rule_set = this+ruleSet[index];
391     struct ContextLookupContext lookup_context = {
392       {match_glyph, apply_func},
393       NULL
394     };
395     return rule_set.apply (c, lookup_context);
396   }
397
398   inline bool sanitize (hb_sanitize_context_t *c) {
399     TRACE_SANITIZE ();
400     return coverage.sanitize (c, this)
401         && ruleSet.sanitize (c, this);
402   }
403
404   private:
405   USHORT        format;                 /* Format identifier--format = 1 */
406   OffsetTo<Coverage>
407                 coverage;               /* Offset to Coverage table--from
408                                          * beginning of table */
409   OffsetArrayOf<RuleSet>
410                 ruleSet;                /* Array of RuleSet tables
411                                          * ordered by Coverage Index */
412   public:
413   DEFINE_SIZE_ARRAY (6, ruleSet);
414 };
415
416
417 struct ContextFormat2
418 {
419   friend struct Context;
420
421   private:
422   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
423   {
424     TRACE_APPLY ();
425     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
426     if (likely (index == NOT_COVERED))
427       return false;
428
429     const ClassDef &class_def = this+classDef;
430     index = class_def (c->buffer->info[c->buffer->i].codepoint);
431     const RuleSet &rule_set = this+ruleSet[index];
432     struct ContextLookupContext lookup_context = {
433       {match_class, apply_func},
434       &class_def
435     };
436     return rule_set.apply (c, lookup_context);
437   }
438
439   inline bool sanitize (hb_sanitize_context_t *c) {
440     TRACE_SANITIZE ();
441     return coverage.sanitize (c, this)
442         && classDef.sanitize (c, this)
443         && ruleSet.sanitize (c, this);
444   }
445
446   private:
447   USHORT        format;                 /* Format identifier--format = 2 */
448   OffsetTo<Coverage>
449                 coverage;               /* Offset to Coverage table--from
450                                          * beginning of table */
451   OffsetTo<ClassDef>
452                 classDef;               /* Offset to glyph ClassDef table--from
453                                          * beginning of table */
454   OffsetArrayOf<RuleSet>
455                 ruleSet;                /* Array of RuleSet tables
456                                          * ordered by class */
457   public:
458   DEFINE_SIZE_ARRAY (8, ruleSet);
459 };
460
461
462 struct ContextFormat3
463 {
464   friend struct Context;
465
466   private:
467   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
468   {
469     TRACE_APPLY ();
470     unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->i].codepoint);
471     if (likely (index == NOT_COVERED))
472       return false;
473
474     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
475     struct ContextLookupContext lookup_context = {
476       {match_coverage, apply_func},
477       this
478     };
479     return context_lookup (c,
480                            glyphCount, (const USHORT *) (coverage + 1),
481                            lookupCount, lookupRecord,
482                            lookup_context);
483   }
484
485   inline bool sanitize (hb_sanitize_context_t *c) {
486     TRACE_SANITIZE ();
487     if (!c->check_struct (this)) return false;
488     unsigned int count = glyphCount;
489     if (!c->check_array (coverage, coverage[0].static_size, count)) return false;
490     for (unsigned int i = 0; i < count; i++)
491       if (!coverage[i].sanitize (c, this)) return false;
492     LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
493     return c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount);
494   }
495
496   private:
497   USHORT        format;                 /* Format identifier--format = 3 */
498   USHORT        glyphCount;             /* Number of glyphs in the input glyph
499                                          * sequence */
500   USHORT        lookupCount;            /* Number of LookupRecords */
501   OffsetTo<Coverage>
502                 coverage[VAR];          /* Array of offsets to Coverage
503                                          * table in glyph sequence order */
504   LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
505                                          * design order */
506   public:
507   DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
508 };
509
510 struct Context
511 {
512   protected:
513   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
514   {
515     TRACE_APPLY ();
516     switch (u.format) {
517     case 1: return u.format1.apply (c, apply_func);
518     case 2: return u.format2.apply (c, apply_func);
519     case 3: return u.format3.apply (c, apply_func);
520     default:return false;
521     }
522   }
523
524   inline bool sanitize (hb_sanitize_context_t *c) {
525     TRACE_SANITIZE ();
526     if (!u.format.sanitize (c)) return false;
527     switch (u.format) {
528     case 1: return u.format1.sanitize (c);
529     case 2: return u.format2.sanitize (c);
530     case 3: return u.format3.sanitize (c);
531     default:return true;
532     }
533   }
534
535   private:
536   union {
537   USHORT                format;         /* Format identifier */
538   ContextFormat1        format1;
539   ContextFormat2        format2;
540   ContextFormat3        format3;
541   } u;
542 };
543
544
545 /* Chaining Contextual lookups */
546
547 struct ChainContextLookupContext
548 {
549   ContextFuncs funcs;
550   const void *match_data[3];
551 };
552
553 static inline bool chain_context_lookup (hb_apply_context_t *c,
554                                          unsigned int backtrackCount,
555                                          const USHORT backtrack[],
556                                          unsigned int inputCount, /* Including the first glyph (not matched) */
557                                          const USHORT input[], /* Array of input values--start with second glyph */
558                                          unsigned int lookaheadCount,
559                                          const USHORT lookahead[],
560                                          unsigned int lookupCount,
561                                          const LookupRecord lookupRecord[],
562                                          ChainContextLookupContext &lookup_context)
563 {
564   /* First guess */
565   if (unlikely (c->buffer->backtrack_len () < backtrackCount ||
566                 c->buffer->i + inputCount + lookaheadCount > c->buffer->len ||
567                 inputCount + lookaheadCount > c->context_length))
568     return false;
569
570   hb_apply_context_t new_context = *c;
571   return match_backtrack (c,
572                           backtrackCount, backtrack,
573                           lookup_context.funcs.match, lookup_context.match_data[0])
574       && match_input (c,
575                       inputCount, input,
576                       lookup_context.funcs.match, lookup_context.match_data[1],
577                       &new_context.context_length)
578       && match_lookahead (c,
579                           lookaheadCount, lookahead,
580                           lookup_context.funcs.match, lookup_context.match_data[2],
581                           new_context.context_length)
582       && apply_lookup (&new_context,
583                        inputCount,
584                        lookupCount, lookupRecord,
585                        lookup_context.funcs.apply);
586 }
587
588 struct ChainRule
589 {
590   friend struct ChainRuleSet;
591
592   private:
593   inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const
594   {
595     TRACE_APPLY ();
596     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
597     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
598     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
599     return chain_context_lookup (c,
600                                  backtrack.len, backtrack.array,
601                                  input.len, input.array,
602                                  lookahead.len, lookahead.array,
603                                  lookup.len, lookup.array,
604                                  lookup_context);
605   }
606
607   public:
608   inline bool sanitize (hb_sanitize_context_t *c) {
609     TRACE_SANITIZE ();
610     if (!backtrack.sanitize (c)) return false;
611     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
612     if (!input.sanitize (c)) return false;
613     ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
614     if (!lookahead.sanitize (c)) return false;
615     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
616     return lookup.sanitize (c);
617   }
618
619   private:
620   ArrayOf<USHORT>
621                 backtrack;              /* Array of backtracking values
622                                          * (to be matched before the input
623                                          * sequence) */
624   HeadlessArrayOf<USHORT>
625                 inputX;                 /* Array of input values (start with
626                                          * second glyph) */
627   ArrayOf<USHORT>
628                 lookaheadX;             /* Array of lookahead values's (to be
629                                          * matched after the input sequence) */
630   ArrayOf<LookupRecord>
631                 lookupX;                /* Array of LookupRecords--in
632                                          * design order) */
633   public:
634   DEFINE_SIZE_MIN (8);
635 };
636
637 struct ChainRuleSet
638 {
639   inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const
640   {
641     TRACE_APPLY ();
642     unsigned int num_rules = rule.len;
643     for (unsigned int i = 0; i < num_rules; i++)
644     {
645       if ((this+rule[i]).apply (c, lookup_context))
646         return true;
647     }
648
649     return false;
650   }
651
652   inline bool sanitize (hb_sanitize_context_t *c) {
653     TRACE_SANITIZE ();
654     return rule.sanitize (c, this);
655   }
656
657   private:
658   OffsetArrayOf<ChainRule>
659                 rule;                   /* Array of ChainRule tables
660                                          * ordered by preference */
661   public:
662   DEFINE_SIZE_ARRAY (2, rule);
663 };
664
665 struct ChainContextFormat1
666 {
667   friend struct ChainContext;
668
669   private:
670   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
671   {
672     TRACE_APPLY ();
673     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
674     if (likely (index == NOT_COVERED))
675       return false;
676
677     const ChainRuleSet &rule_set = this+ruleSet[index];
678     struct ChainContextLookupContext lookup_context = {
679       {match_glyph, apply_func},
680       {NULL, NULL, NULL}
681     };
682     return rule_set.apply (c, lookup_context);
683   }
684
685   inline bool sanitize (hb_sanitize_context_t *c) {
686     TRACE_SANITIZE ();
687     return coverage.sanitize (c, this)
688         && ruleSet.sanitize (c, this);
689   }
690
691   private:
692   USHORT        format;                 /* Format identifier--format = 1 */
693   OffsetTo<Coverage>
694                 coverage;               /* Offset to Coverage table--from
695                                          * beginning of table */
696   OffsetArrayOf<ChainRuleSet>
697                 ruleSet;                /* Array of ChainRuleSet tables
698                                          * ordered by Coverage Index */
699   public:
700   DEFINE_SIZE_ARRAY (6, ruleSet);
701 };
702
703 struct ChainContextFormat2
704 {
705   friend struct ChainContext;
706
707   private:
708   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
709   {
710     TRACE_APPLY ();
711     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
712     if (likely (index == NOT_COVERED))
713       return false;
714
715     const ClassDef &backtrack_class_def = this+backtrackClassDef;
716     const ClassDef &input_class_def = this+inputClassDef;
717     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
718
719     index = input_class_def (c->buffer->info[c->buffer->i].codepoint);
720     const ChainRuleSet &rule_set = this+ruleSet[index];
721     struct ChainContextLookupContext lookup_context = {
722       {match_class, apply_func},
723       {&backtrack_class_def,
724        &input_class_def,
725        &lookahead_class_def}
726     };
727     return rule_set.apply (c, lookup_context);
728   }
729
730   inline bool sanitize (hb_sanitize_context_t *c) {
731     TRACE_SANITIZE ();
732     return coverage.sanitize (c, this)
733         && backtrackClassDef.sanitize (c, this)
734         && inputClassDef.sanitize (c, this)
735         && lookaheadClassDef.sanitize (c, this)
736         && ruleSet.sanitize (c, this);
737   }
738
739   private:
740   USHORT        format;                 /* Format identifier--format = 2 */
741   OffsetTo<Coverage>
742                 coverage;               /* Offset to Coverage table--from
743                                          * beginning of table */
744   OffsetTo<ClassDef>
745                 backtrackClassDef;      /* Offset to glyph ClassDef table
746                                          * containing backtrack sequence
747                                          * data--from beginning of table */
748   OffsetTo<ClassDef>
749                 inputClassDef;          /* Offset to glyph ClassDef
750                                          * table containing input sequence
751                                          * data--from beginning of table */
752   OffsetTo<ClassDef>
753                 lookaheadClassDef;      /* Offset to glyph ClassDef table
754                                          * containing lookahead sequence
755                                          * data--from beginning of table */
756   OffsetArrayOf<ChainRuleSet>
757                 ruleSet;                /* Array of ChainRuleSet tables
758                                          * ordered by class */
759   public:
760   DEFINE_SIZE_ARRAY (12, ruleSet);
761 };
762
763 struct ChainContextFormat3
764 {
765   friend struct ChainContext;
766
767   private:
768
769   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
770   {
771     TRACE_APPLY ();
772     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
773
774     unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->i].codepoint);
775     if (likely (index == NOT_COVERED))
776       return false;
777
778     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
779     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
780     struct ChainContextLookupContext lookup_context = {
781       {match_coverage, apply_func},
782       {this, this, this}
783     };
784     return chain_context_lookup (c,
785                                  backtrack.len, (const USHORT *) backtrack.array,
786                                  input.len, (const USHORT *) input.array + 1,
787                                  lookahead.len, (const USHORT *) lookahead.array,
788                                  lookup.len, lookup.array,
789                                  lookup_context);
790   }
791
792   inline bool sanitize (hb_sanitize_context_t *c) {
793     TRACE_SANITIZE ();
794     if (!backtrack.sanitize (c, this)) return false;
795     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
796     if (!input.sanitize (c, this)) return false;
797     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
798     if (!lookahead.sanitize (c, this)) return false;
799     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
800     return lookup.sanitize (c);
801   }
802
803   private:
804   USHORT        format;                 /* Format identifier--format = 3 */
805   OffsetArrayOf<Coverage>
806                 backtrack;              /* Array of coverage tables
807                                          * in backtracking sequence, in  glyph
808                                          * sequence order */
809   OffsetArrayOf<Coverage>
810                 inputX          ;       /* Array of coverage
811                                          * tables in input sequence, in glyph
812                                          * sequence order */
813   OffsetArrayOf<Coverage>
814                 lookaheadX;             /* Array of coverage tables
815                                          * in lookahead sequence, in glyph
816                                          * sequence order */
817   ArrayOf<LookupRecord>
818                 lookupX;                /* Array of LookupRecords--in
819                                          * design order) */
820   public:
821   DEFINE_SIZE_MIN (10);
822 };
823
824 struct ChainContext
825 {
826   protected:
827   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
828   {
829     TRACE_APPLY ();
830     switch (u.format) {
831     case 1: return u.format1.apply (c, apply_func);
832     case 2: return u.format2.apply (c, apply_func);
833     case 3: return u.format3.apply (c, apply_func);
834     default:return false;
835     }
836   }
837
838   inline bool sanitize (hb_sanitize_context_t *c) {
839     TRACE_SANITIZE ();
840     if (!u.format.sanitize (c)) return false;
841     switch (u.format) {
842     case 1: return u.format1.sanitize (c);
843     case 2: return u.format2.sanitize (c);
844     case 3: return u.format3.sanitize (c);
845     default:return true;
846     }
847   }
848
849   private:
850   union {
851   USHORT                format; /* Format identifier */
852   ChainContextFormat1   format1;
853   ChainContextFormat2   format2;
854   ChainContextFormat3   format3;
855   } u;
856 };
857
858
859 struct ExtensionFormat1
860 {
861   friend struct Extension;
862
863   protected:
864   inline unsigned int get_type (void) const { return extensionLookupType; }
865   inline unsigned int get_offset (void) const { return extensionOffset; }
866
867   inline bool sanitize (hb_sanitize_context_t *c) {
868     TRACE_SANITIZE ();
869     return c->check_struct (this);
870   }
871
872   private:
873   USHORT        format;                 /* Format identifier. Set to 1. */
874   USHORT        extensionLookupType;    /* Lookup type of subtable referenced
875                                          * by ExtensionOffset (i.e. the
876                                          * extension subtable). */
877   ULONG         extensionOffset;        /* Offset to the extension subtable,
878                                          * of lookup type subtable. */
879   public:
880   DEFINE_SIZE_STATIC (8);
881 };
882
883 struct Extension
884 {
885   inline unsigned int get_type (void) const
886   {
887     switch (u.format) {
888     case 1: return u.format1.get_type ();
889     default:return 0;
890     }
891   }
892   inline unsigned int get_offset (void) const
893   {
894     switch (u.format) {
895     case 1: return u.format1.get_offset ();
896     default:return 0;
897     }
898   }
899
900   inline bool sanitize (hb_sanitize_context_t *c) {
901     TRACE_SANITIZE ();
902     if (!u.format.sanitize (c)) return false;
903     switch (u.format) {
904     case 1: return u.format1.sanitize (c);
905     default:return true;
906     }
907   }
908
909   private:
910   union {
911   USHORT                format;         /* Format identifier */
912   ExtensionFormat1      format1;
913   } u;
914 };
915
916
917 /*
918  * GSUB/GPOS Common
919  */
920
921 struct GSUBGPOS
922 {
923   static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
924   static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
925
926   inline unsigned int get_script_count (void) const
927   { return (this+scriptList).len; }
928   inline const Tag& get_script_tag (unsigned int i) const
929   { return (this+scriptList).get_tag (i); }
930   inline unsigned int get_script_tags (unsigned int start_offset,
931                                        unsigned int *script_count /* IN/OUT */,
932                                        hb_tag_t     *script_tags /* OUT */) const
933   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
934   inline const Script& get_script (unsigned int i) const
935   { return (this+scriptList)[i]; }
936   inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
937   { return (this+scriptList).find_index (tag, index); }
938
939   inline unsigned int get_feature_count (void) const
940   { return (this+featureList).len; }
941   inline const Tag& get_feature_tag (unsigned int i) const
942   { return (this+featureList).get_tag (i); }
943   inline unsigned int get_feature_tags (unsigned int start_offset,
944                                         unsigned int *feature_count /* IN/OUT */,
945                                         hb_tag_t     *feature_tags /* OUT */) const
946   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
947   inline const Feature& get_feature (unsigned int i) const
948   { return (this+featureList)[i]; }
949   inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
950   { return (this+featureList).find_index (tag, index); }
951
952   inline unsigned int get_lookup_count (void) const
953   { return (this+lookupList).len; }
954   inline const Lookup& get_lookup (unsigned int i) const
955   { return (this+lookupList)[i]; }
956
957   inline bool sanitize (hb_sanitize_context_t *c) {
958     TRACE_SANITIZE ();
959     return version.sanitize (c) && likely (version.major == 1)
960         && scriptList.sanitize (c, this)
961         && featureList.sanitize (c, this)
962         && lookupList.sanitize (c, this);
963   }
964
965   protected:
966   FixedVersion  version;        /* Version of the GSUB/GPOS table--initially set
967                                  * to 0x00010000 */
968   OffsetTo<ScriptList>
969                 scriptList;     /* ScriptList table */
970   OffsetTo<FeatureList>
971                 featureList;    /* FeatureList table */
972   OffsetTo<LookupList>
973                 lookupList;     /* LookupList table */
974   public:
975   DEFINE_SIZE_STATIC (10);
976 };
977
978
979 HB_END_DECLS
980
981 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */