Upgrade to latest harfbuzz
[framework/uifw/harfbuzz.git] / src / hb-ot-layout-gsubgpos-private.hh
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_GSUBGPOS_PRIVATE_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
31
32 #include "hb-buffer-private.hh"
33 #include "hb-ot-layout-gdef-table.hh"
34
35
36
37 /* unique ligature id */
38 /* component number in the ligature (0 = base) */
39 static inline void
40 set_lig_props (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp)
41 {
42   info.lig_props() = (lig_id << 4) | (lig_comp & 0x0F);
43 }
44 static inline unsigned int
45 get_lig_id (hb_glyph_info_t &info)
46 {
47   return info.lig_props() >> 4;
48 }
49 static inline unsigned int
50 get_lig_comp (hb_glyph_info_t &info)
51 {
52   return info.lig_props() & 0x0F;
53 }
54
55 static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
56   uint8_t lig_id = buffer->next_serial () & 0x0F;
57   if (unlikely (!lig_id))
58     lig_id = allocate_lig_id (buffer); /* in case of overflow */
59   return lig_id;
60 }
61
62
63
64 #ifndef HB_DEBUG_CLOSURE
65 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
66 #endif
67
68 #define TRACE_CLOSURE() \
69         hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
70
71
72 /* TODO Add TRACE_RETURN annotation for would_apply */
73
74
75 struct hb_closure_context_t
76 {
77   hb_face_t *face;
78   hb_set_t *glyphs;
79   unsigned int nesting_level_left;
80   unsigned int debug_depth;
81
82
83   hb_closure_context_t (hb_face_t *face_,
84                         hb_set_t *glyphs_,
85                         unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
86                           face (face_), glyphs (glyphs_),
87                           nesting_level_left (nesting_level_left_),
88                           debug_depth (0) {}
89 };
90
91
92
93 #ifndef HB_DEBUG_APPLY
94 #define HB_DEBUG_APPLY (HB_DEBUG+0)
95 #endif
96
97 #define TRACE_APPLY() \
98         hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->cur().codepoint);
99
100
101
102 struct hb_apply_context_t
103 {
104   hb_font_t *font;
105   hb_face_t *face;
106   hb_buffer_t *buffer;
107   hb_direction_t direction;
108   hb_mask_t lookup_mask;
109   unsigned int nesting_level_left;
110   unsigned int lookup_props;
111   unsigned int property; /* propety of first glyph */
112   unsigned int debug_depth;
113
114
115   hb_apply_context_t (hb_font_t *font_,
116                       hb_face_t *face_,
117                       hb_buffer_t *buffer_,
118                       hb_mask_t lookup_mask_) :
119                         font (font_), face (face_), buffer (buffer_),
120                         direction (buffer_->props.direction),
121                         lookup_mask (lookup_mask_),
122                         nesting_level_left (MAX_NESTING_LEVEL),
123                         lookup_props (0), property (0), debug_depth (0) {}
124
125   void set_lookup (const Lookup &l) {
126     lookup_props = l.get_props ();
127   }
128
129   struct mark_skipping_forward_iterator_t
130   {
131     inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
132                                              unsigned int start_index_,
133                                              unsigned int num_items_,
134                                              bool context_match = false)
135     {
136       c = c_;
137       idx = start_index_;
138       num_items = num_items_;
139       mask = context_match ? -1 : c->lookup_mask;
140       syllable = context_match ? 0 : c->buffer->cur().syllable ();
141       end = c->buffer->len;
142     }
143     inline bool has_no_chance (void) const
144     {
145       return unlikely (num_items && idx + num_items >= end);
146     }
147     inline bool next (unsigned int *property_out,
148                       unsigned int lookup_props)
149     {
150       assert (num_items > 0);
151       do
152       {
153         if (has_no_chance ())
154           return false;
155         idx++;
156       } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out));
157       num_items--;
158       return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
159     }
160     inline bool next (unsigned int *property_out = NULL)
161     {
162       return next (property_out, c->lookup_props);
163     }
164
165     unsigned int idx;
166     private:
167     hb_apply_context_t *c;
168     unsigned int num_items;
169     hb_mask_t mask;
170     uint8_t syllable;
171     unsigned int end;
172   };
173
174   struct mark_skipping_backward_iterator_t
175   {
176     inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
177                                               unsigned int start_index_,
178                                               unsigned int num_items_,
179                                               hb_mask_t mask_ = 0,
180                                               bool match_syllable_ = true)
181     {
182       c = c_;
183       idx = start_index_;
184       num_items = num_items_;
185       mask = mask_ ? mask_ : c->lookup_mask;
186       syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
187     }
188     inline bool has_no_chance (void) const
189     {
190       return unlikely (idx < num_items);
191     }
192     inline bool prev (unsigned int *property_out,
193                       unsigned int lookup_props)
194     {
195       assert (num_items > 0);
196       do
197       {
198         if (has_no_chance ())
199           return false;
200         idx--;
201       } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out));
202       num_items--;
203       return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
204     }
205     inline bool prev (unsigned int *property_out = NULL)
206     {
207       return prev (property_out, c->lookup_props);
208     }
209
210     unsigned int idx;
211     private:
212     hb_apply_context_t *c;
213     unsigned int num_items;
214     hb_mask_t mask;
215     uint8_t syllable;
216   };
217
218   inline bool should_mark_skip_current_glyph (void) const
219   {
220     return _hb_ot_layout_skip_mark (face, &buffer->cur(), lookup_props, NULL);
221   }
222
223
224
225   inline void replace_glyph (hb_codepoint_t glyph_index,
226                              unsigned int klass = 0) const
227   {
228     buffer->cur().props_cache() = klass; /*XXX if has gdef? */
229     buffer->replace_glyph (glyph_index);
230   }
231   inline void replace_glyphs_be16 (unsigned int num_in,
232                                    unsigned int num_out,
233                                    const uint16_t *glyph_data_be,
234                                    unsigned int klass = 0) const
235   {
236     buffer->cur().props_cache() = klass; /* XXX if has gdef? */
237     buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be);
238   }
239 };
240
241
242
243 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
244 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
245 typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
246 typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
247
248 struct ContextClosureFuncs
249 {
250   intersects_func_t intersects;
251   closure_lookup_func_t closure;
252 };
253 struct ContextApplyFuncs
254 {
255   match_func_t match;
256   apply_lookup_func_t apply;
257 };
258
259 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
260 {
261   return glyphs->has (value);
262 }
263 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
264 {
265   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
266   return class_def.intersects_class (glyphs, value);
267 }
268 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
269 {
270   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
271   return (data+coverage).intersects (glyphs);
272 }
273
274 static inline bool intersects_array (hb_closure_context_t *c,
275                                      unsigned int count,
276                                      const USHORT values[],
277                                      intersects_func_t intersects_func,
278                                      const void *intersects_data)
279 {
280   for (unsigned int i = 0; i < count; i++)
281     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
282       return false;
283   return true;
284 }
285
286
287 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
288 {
289   return glyph_id == value;
290 }
291
292 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
293 {
294   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
295   return class_def.get_class (glyph_id) == value;
296 }
297
298 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
299 {
300   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
301   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
302 }
303
304
305 static inline bool match_input (hb_apply_context_t *c,
306                                 unsigned int count, /* Including the first glyph (not matched) */
307                                 const USHORT input[], /* Array of input values--start with second glyph */
308                                 match_func_t match_func,
309                                 const void *match_data,
310                                 unsigned int *end_offset = NULL)
311 {
312   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
313   if (skippy_iter.has_no_chance ())
314     return false;
315
316   for (unsigned int i = 1; i < count; i++)
317   {
318     if (!skippy_iter.next ())
319       return false;
320
321     if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data)))
322       return false;
323   }
324
325   if (end_offset)
326     *end_offset = skippy_iter.idx - c->buffer->idx + 1;
327
328   return true;
329 }
330
331 static inline bool match_backtrack (hb_apply_context_t *c,
332                                     unsigned int count,
333                                     const USHORT backtrack[],
334                                     match_func_t match_func,
335                                     const void *match_data)
336 {
337   hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
338   if (skippy_iter.has_no_chance ())
339     return false;
340
341   for (unsigned int i = 0; i < count; i++)
342   {
343     if (!skippy_iter.prev ())
344       return false;
345
346     if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
347       return false;
348   }
349
350   return true;
351 }
352
353 static inline bool match_lookahead (hb_apply_context_t *c,
354                                     unsigned int count,
355                                     const USHORT lookahead[],
356                                     match_func_t match_func,
357                                     const void *match_data,
358                                     unsigned int offset)
359 {
360   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
361   if (skippy_iter.has_no_chance ())
362     return false;
363
364   for (unsigned int i = 0; i < count; i++)
365   {
366     if (!skippy_iter.next ())
367       return false;
368
369     if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
370       return false;
371   }
372
373   return true;
374 }
375
376
377
378 struct LookupRecord
379 {
380   inline bool sanitize (hb_sanitize_context_t *c) {
381     TRACE_SANITIZE ();
382     return TRACE_RETURN (c->check_struct (this));
383   }
384
385   USHORT        sequenceIndex;          /* Index into current glyph
386                                          * sequence--first glyph = 0 */
387   USHORT        lookupListIndex;        /* Lookup to apply to that
388                                          * position--zero--based */
389   public:
390   DEFINE_SIZE_STATIC (4);
391 };
392
393
394 static inline void closure_lookup (hb_closure_context_t *c,
395                                    unsigned int lookupCount,
396                                    const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
397                                    closure_lookup_func_t closure_func)
398 {
399   for (unsigned int i = 0; i < lookupCount; i++)
400     closure_func (c, lookupRecord->lookupListIndex);
401 }
402
403 static inline bool apply_lookup (hb_apply_context_t *c,
404                                  unsigned int count, /* Including the first glyph */
405                                  unsigned int lookupCount,
406                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
407                                  apply_lookup_func_t apply_func)
408 {
409   unsigned int end = c->buffer->len;
410   if (unlikely (count == 0 || c->buffer->idx + count > end))
411     return false;
412
413   /* TODO We don't support lookupRecord arrays that are not increasing:
414    *      Should be easy for in_place ones at least. */
415
416   /* Note: If sublookup is reverse, it will underflow after the first loop
417    * and we jump out of it.  Not entirely disastrous.  So we don't check
418    * for reverse lookup here.
419    */
420   for (unsigned int i = 0; i < count; /* NOP */)
421   {
422     if (unlikely (c->buffer->idx == end))
423       return true;
424     while (c->should_mark_skip_current_glyph ())
425     {
426       /* No lookup applied for this index */
427       c->buffer->next_glyph ();
428       if (unlikely (c->buffer->idx == end))
429         return true;
430     }
431
432     if (lookupCount && i == lookupRecord->sequenceIndex)
433     {
434       unsigned int old_pos = c->buffer->idx;
435
436       /* Apply a lookup */
437       bool done = apply_func (c, lookupRecord->lookupListIndex);
438
439       lookupRecord++;
440       lookupCount--;
441       /* Err, this is wrong if the lookup jumped over some glyphs */
442       i += c->buffer->idx - old_pos;
443       if (unlikely (c->buffer->idx == end))
444         return true;
445
446       if (!done)
447         goto not_applied;
448     }
449     else
450     {
451     not_applied:
452       /* No lookup applied for this index */
453       c->buffer->next_glyph ();
454       i++;
455     }
456   }
457
458   return true;
459 }
460
461
462
463 /* Contextual lookups */
464
465 struct ContextClosureLookupContext
466 {
467   ContextClosureFuncs funcs;
468   const void *intersects_data;
469 };
470
471 struct ContextApplyLookupContext
472 {
473   ContextApplyFuncs funcs;
474   const void *match_data;
475 };
476
477 static inline void context_closure_lookup (hb_closure_context_t *c,
478                                            unsigned int inputCount, /* Including the first glyph (not matched) */
479                                            const USHORT input[], /* Array of input values--start with second glyph */
480                                            unsigned int lookupCount,
481                                            const LookupRecord lookupRecord[],
482                                            ContextClosureLookupContext &lookup_context)
483 {
484   if (intersects_array (c,
485                         inputCount ? inputCount - 1 : 0, input,
486                         lookup_context.funcs.intersects, lookup_context.intersects_data))
487     closure_lookup (c,
488                     lookupCount, lookupRecord,
489                     lookup_context.funcs.closure);
490 }
491
492
493 static inline bool context_apply_lookup (hb_apply_context_t *c,
494                                          unsigned int inputCount, /* Including the first glyph (not matched) */
495                                          const USHORT input[], /* Array of input values--start with second glyph */
496                                          unsigned int lookupCount,
497                                          const LookupRecord lookupRecord[],
498                                          ContextApplyLookupContext &lookup_context)
499 {
500   return match_input (c,
501                       inputCount, input,
502                       lookup_context.funcs.match, lookup_context.match_data)
503       && apply_lookup (c,
504                        inputCount,
505                        lookupCount, lookupRecord,
506                        lookup_context.funcs.apply);
507 }
508
509 struct Rule
510 {
511   friend struct RuleSet;
512
513   private:
514
515   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
516   {
517     TRACE_CLOSURE ();
518     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
519     context_closure_lookup (c,
520                             inputCount, input,
521                             lookupCount, lookupRecord,
522                             lookup_context);
523   }
524
525   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
526   {
527     TRACE_APPLY ();
528     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
529     return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
530   }
531
532   public:
533   inline bool sanitize (hb_sanitize_context_t *c) {
534     TRACE_SANITIZE ();
535     return inputCount.sanitize (c)
536         && lookupCount.sanitize (c)
537         && c->check_range (input,
538                            input[0].static_size * inputCount
539                            + lookupRecordX[0].static_size * lookupCount);
540   }
541
542   private:
543   USHORT        inputCount;             /* Total number of glyphs in input
544                                          * glyph sequence--includes the first
545                                          * glyph */
546   USHORT        lookupCount;            /* Number of LookupRecords */
547   USHORT        input[VAR];             /* Array of match inputs--start with
548                                          * second glyph */
549   LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
550                                          * design order */
551   public:
552   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
553 };
554
555 struct RuleSet
556 {
557   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
558   {
559     TRACE_CLOSURE ();
560     unsigned int num_rules = rule.len;
561     for (unsigned int i = 0; i < num_rules; i++)
562       (this+rule[i]).closure (c, lookup_context);
563   }
564
565   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
566   {
567     TRACE_APPLY ();
568     unsigned int num_rules = rule.len;
569     for (unsigned int i = 0; i < num_rules; i++)
570     {
571       if ((this+rule[i]).apply (c, lookup_context))
572         return TRACE_RETURN (true);
573     }
574     return TRACE_RETURN (false);
575   }
576
577   inline bool sanitize (hb_sanitize_context_t *c) {
578     TRACE_SANITIZE ();
579     return TRACE_RETURN (rule.sanitize (c, this));
580   }
581
582   private:
583   OffsetArrayOf<Rule>
584                 rule;                   /* Array of Rule tables
585                                          * ordered by preference */
586   public:
587   DEFINE_SIZE_ARRAY (2, rule);
588 };
589
590
591 struct ContextFormat1
592 {
593   friend struct Context;
594
595   private:
596
597   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
598   {
599     TRACE_CLOSURE ();
600
601     const Coverage &cov = (this+coverage);
602
603     struct ContextClosureLookupContext lookup_context = {
604       {intersects_glyph, closure_func},
605       NULL
606     };
607
608     unsigned int count = ruleSet.len;
609     for (unsigned int i = 0; i < count; i++)
610       if (cov.intersects_coverage (c->glyphs, i)) {
611         const RuleSet &rule_set = this+ruleSet[i];
612         rule_set.closure (c, lookup_context);
613       }
614   }
615
616   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
617   {
618     TRACE_APPLY ();
619     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
620     if (likely (index == NOT_COVERED))
621       return TRACE_RETURN (false);
622
623     const RuleSet &rule_set = this+ruleSet[index];
624     struct ContextApplyLookupContext lookup_context = {
625       {match_glyph, apply_func},
626       NULL
627     };
628     return TRACE_RETURN (rule_set.apply (c, lookup_context));
629   }
630
631   inline bool sanitize (hb_sanitize_context_t *c) {
632     TRACE_SANITIZE ();
633     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
634   }
635
636   private:
637   USHORT        format;                 /* Format identifier--format = 1 */
638   OffsetTo<Coverage>
639                 coverage;               /* Offset to Coverage table--from
640                                          * beginning of table */
641   OffsetArrayOf<RuleSet>
642                 ruleSet;                /* Array of RuleSet tables
643                                          * ordered by Coverage Index */
644   public:
645   DEFINE_SIZE_ARRAY (6, ruleSet);
646 };
647
648
649 struct ContextFormat2
650 {
651   friend struct Context;
652
653   private:
654
655   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
656   {
657     TRACE_CLOSURE ();
658     if (!(this+coverage).intersects (c->glyphs))
659       return;
660
661     const ClassDef &class_def = this+classDef;
662
663     struct ContextClosureLookupContext lookup_context = {
664       {intersects_class, closure_func},
665       NULL
666     };
667
668     unsigned int count = ruleSet.len;
669     for (unsigned int i = 0; i < count; i++)
670       if (class_def.intersects_class (c->glyphs, i)) {
671         const RuleSet &rule_set = this+ruleSet[i];
672         rule_set.closure (c, lookup_context);
673       }
674   }
675
676   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
677   {
678     TRACE_APPLY ();
679     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
680     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
681
682     const ClassDef &class_def = this+classDef;
683     index = class_def (c->buffer->cur().codepoint);
684     const RuleSet &rule_set = this+ruleSet[index];
685     struct ContextApplyLookupContext lookup_context = {
686       {match_class, apply_func},
687       &class_def
688     };
689     return TRACE_RETURN (rule_set.apply (c, lookup_context));
690   }
691
692   inline bool sanitize (hb_sanitize_context_t *c) {
693     TRACE_SANITIZE ();
694     return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
695   }
696
697   private:
698   USHORT        format;                 /* Format identifier--format = 2 */
699   OffsetTo<Coverage>
700                 coverage;               /* Offset to Coverage table--from
701                                          * beginning of table */
702   OffsetTo<ClassDef>
703                 classDef;               /* Offset to glyph ClassDef table--from
704                                          * beginning of table */
705   OffsetArrayOf<RuleSet>
706                 ruleSet;                /* Array of RuleSet tables
707                                          * ordered by class */
708   public:
709   DEFINE_SIZE_ARRAY (8, ruleSet);
710 };
711
712
713 struct ContextFormat3
714 {
715   friend struct Context;
716
717   private:
718
719   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
720   {
721     TRACE_CLOSURE ();
722     if (!(this+coverage[0]).intersects (c->glyphs))
723       return;
724
725     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
726     struct ContextClosureLookupContext lookup_context = {
727       {intersects_coverage, closure_func},
728       this
729     };
730     context_closure_lookup (c,
731                             glyphCount, (const USHORT *) (coverage + 1),
732                             lookupCount, lookupRecord,
733                             lookup_context);
734   }
735
736   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
737   {
738     TRACE_APPLY ();
739     unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
740     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
741
742     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
743     struct ContextApplyLookupContext lookup_context = {
744       {match_coverage, apply_func},
745       this
746     };
747     return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
748   }
749
750   inline bool sanitize (hb_sanitize_context_t *c) {
751     TRACE_SANITIZE ();
752     if (!c->check_struct (this)) return TRACE_RETURN (false);
753     unsigned int count = glyphCount;
754     if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
755     for (unsigned int i = 0; i < count; i++)
756       if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
757     LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
758     return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
759   }
760
761   private:
762   USHORT        format;                 /* Format identifier--format = 3 */
763   USHORT        glyphCount;             /* Number of glyphs in the input glyph
764                                          * sequence */
765   USHORT        lookupCount;            /* Number of LookupRecords */
766   OffsetTo<Coverage>
767                 coverage[VAR];          /* Array of offsets to Coverage
768                                          * table in glyph sequence order */
769   LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
770                                          * design order */
771   public:
772   DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
773 };
774
775 struct Context
776 {
777   protected:
778
779   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
780   {
781     TRACE_CLOSURE ();
782     switch (u.format) {
783     case 1: u.format1.closure (c, closure_func); break;
784     case 2: u.format2.closure (c, closure_func); break;
785     case 3: u.format3.closure (c, closure_func); break;
786     default:                                     break;
787     }
788   }
789
790   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
791   {
792     TRACE_APPLY ();
793     switch (u.format) {
794     case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
795     case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
796     case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
797     default:return TRACE_RETURN (false);
798     }
799   }
800
801   inline bool sanitize (hb_sanitize_context_t *c) {
802     TRACE_SANITIZE ();
803     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
804     switch (u.format) {
805     case 1: return TRACE_RETURN (u.format1.sanitize (c));
806     case 2: return TRACE_RETURN (u.format2.sanitize (c));
807     case 3: return TRACE_RETURN (u.format3.sanitize (c));
808     default:return TRACE_RETURN (true);
809     }
810   }
811
812   private:
813   union {
814   USHORT                format;         /* Format identifier */
815   ContextFormat1        format1;
816   ContextFormat2        format2;
817   ContextFormat3        format3;
818   } u;
819 };
820
821
822 /* Chaining Contextual lookups */
823
824 struct ChainContextClosureLookupContext
825 {
826   ContextClosureFuncs funcs;
827   const void *intersects_data[3];
828 };
829
830 struct ChainContextApplyLookupContext
831 {
832   ContextApplyFuncs funcs;
833   const void *match_data[3];
834 };
835
836 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
837                                                  unsigned int backtrackCount,
838                                                  const USHORT backtrack[],
839                                                  unsigned int inputCount, /* Including the first glyph (not matched) */
840                                                  const USHORT input[], /* Array of input values--start with second glyph */
841                                                  unsigned int lookaheadCount,
842                                                  const USHORT lookahead[],
843                                                  unsigned int lookupCount,
844                                                  const LookupRecord lookupRecord[],
845                                                  ChainContextClosureLookupContext &lookup_context)
846 {
847   if (intersects_array (c,
848                         backtrackCount, backtrack,
849                         lookup_context.funcs.intersects, lookup_context.intersects_data[0])
850    && intersects_array (c,
851                         inputCount ? inputCount - 1 : 0, input,
852                         lookup_context.funcs.intersects, lookup_context.intersects_data[1])
853   && intersects_array (c,
854                        lookaheadCount, lookahead,
855                        lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
856     closure_lookup (c,
857                     lookupCount, lookupRecord,
858                     lookup_context.funcs.closure);
859 }
860
861 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
862                                                unsigned int backtrackCount,
863                                                const USHORT backtrack[],
864                                                unsigned int inputCount, /* Including the first glyph (not matched) */
865                                                const USHORT input[], /* Array of input values--start with second glyph */
866                                                unsigned int lookaheadCount,
867                                                const USHORT lookahead[],
868                                                unsigned int lookupCount,
869                                                const LookupRecord lookupRecord[],
870                                                ChainContextApplyLookupContext &lookup_context)
871 {
872   unsigned int lookahead_offset;
873   return match_backtrack (c,
874                           backtrackCount, backtrack,
875                           lookup_context.funcs.match, lookup_context.match_data[0])
876       && match_input (c,
877                       inputCount, input,
878                       lookup_context.funcs.match, lookup_context.match_data[1],
879                       &lookahead_offset)
880       && match_lookahead (c,
881                           lookaheadCount, lookahead,
882                           lookup_context.funcs.match, lookup_context.match_data[2],
883                           lookahead_offset)
884       && apply_lookup (c,
885                        inputCount,
886                        lookupCount, lookupRecord,
887                        lookup_context.funcs.apply);
888 }
889
890 struct ChainRule
891 {
892   friend struct ChainRuleSet;
893
894   private:
895
896   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
897   {
898     TRACE_CLOSURE ();
899     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
900     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
901     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
902     chain_context_closure_lookup (c,
903                                   backtrack.len, backtrack.array,
904                                   input.len, input.array,
905                                   lookahead.len, lookahead.array,
906                                   lookup.len, lookup.array,
907                                   lookup_context);
908   }
909
910   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
911   {
912     TRACE_APPLY ();
913     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
914     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
915     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
916     return TRACE_RETURN (chain_context_apply_lookup (c,
917                                                      backtrack.len, backtrack.array,
918                                                      input.len, input.array,
919                                                      lookahead.len, lookahead.array, lookup.len,
920                                                      lookup.array, lookup_context));
921   }
922
923   public:
924   inline bool sanitize (hb_sanitize_context_t *c) {
925     TRACE_SANITIZE ();
926     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
927     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
928     if (!input.sanitize (c)) return TRACE_RETURN (false);
929     ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
930     if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
931     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
932     return TRACE_RETURN (lookup.sanitize (c));
933   }
934
935   private:
936   ArrayOf<USHORT>
937                 backtrack;              /* Array of backtracking values
938                                          * (to be matched before the input
939                                          * sequence) */
940   HeadlessArrayOf<USHORT>
941                 inputX;                 /* Array of input values (start with
942                                          * second glyph) */
943   ArrayOf<USHORT>
944                 lookaheadX;             /* Array of lookahead values's (to be
945                                          * matched after the input sequence) */
946   ArrayOf<LookupRecord>
947                 lookupX;                /* Array of LookupRecords--in
948                                          * design order) */
949   public:
950   DEFINE_SIZE_MIN (8);
951 };
952
953 struct ChainRuleSet
954 {
955   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
956   {
957     TRACE_CLOSURE ();
958     unsigned int num_rules = rule.len;
959     for (unsigned int i = 0; i < num_rules; i++)
960       (this+rule[i]).closure (c, lookup_context);
961   }
962
963   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
964   {
965     TRACE_APPLY ();
966     unsigned int num_rules = rule.len;
967     for (unsigned int i = 0; i < num_rules; i++)
968       if ((this+rule[i]).apply (c, lookup_context))
969         return TRACE_RETURN (true);
970
971     return TRACE_RETURN (false);
972   }
973
974   inline bool sanitize (hb_sanitize_context_t *c) {
975     TRACE_SANITIZE ();
976     return TRACE_RETURN (rule.sanitize (c, this));
977   }
978
979   private:
980   OffsetArrayOf<ChainRule>
981                 rule;                   /* Array of ChainRule tables
982                                          * ordered by preference */
983   public:
984   DEFINE_SIZE_ARRAY (2, rule);
985 };
986
987 struct ChainContextFormat1
988 {
989   friend struct ChainContext;
990
991   private:
992
993   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
994   {
995     TRACE_CLOSURE ();
996     const Coverage &cov = (this+coverage);
997
998     struct ChainContextClosureLookupContext lookup_context = {
999       {intersects_glyph, closure_func},
1000       {NULL, NULL, NULL}
1001     };
1002
1003     unsigned int count = ruleSet.len;
1004     for (unsigned int i = 0; i < count; i++)
1005       if (cov.intersects_coverage (c->glyphs, i)) {
1006         const ChainRuleSet &rule_set = this+ruleSet[i];
1007         rule_set.closure (c, lookup_context);
1008       }
1009   }
1010
1011   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1012   {
1013     TRACE_APPLY ();
1014     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1015     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1016
1017     const ChainRuleSet &rule_set = this+ruleSet[index];
1018     struct ChainContextApplyLookupContext lookup_context = {
1019       {match_glyph, apply_func},
1020       {NULL, NULL, NULL}
1021     };
1022     return TRACE_RETURN (rule_set.apply (c, lookup_context));
1023   }
1024
1025   inline bool sanitize (hb_sanitize_context_t *c) {
1026     TRACE_SANITIZE ();
1027     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1028   }
1029
1030   private:
1031   USHORT        format;                 /* Format identifier--format = 1 */
1032   OffsetTo<Coverage>
1033                 coverage;               /* Offset to Coverage table--from
1034                                          * beginning of table */
1035   OffsetArrayOf<ChainRuleSet>
1036                 ruleSet;                /* Array of ChainRuleSet tables
1037                                          * ordered by Coverage Index */
1038   public:
1039   DEFINE_SIZE_ARRAY (6, ruleSet);
1040 };
1041
1042 struct ChainContextFormat2
1043 {
1044   friend struct ChainContext;
1045
1046   private:
1047
1048   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1049   {
1050     TRACE_CLOSURE ();
1051     if (!(this+coverage).intersects (c->glyphs))
1052       return;
1053
1054     const ClassDef &backtrack_class_def = this+backtrackClassDef;
1055     const ClassDef &input_class_def = this+inputClassDef;
1056     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1057
1058     struct ChainContextClosureLookupContext lookup_context = {
1059       {intersects_class, closure_func},
1060       {&backtrack_class_def,
1061        &input_class_def,
1062        &lookahead_class_def}
1063     };
1064
1065     unsigned int count = ruleSet.len;
1066     for (unsigned int i = 0; i < count; i++)
1067       if (input_class_def.intersects_class (c->glyphs, i)) {
1068         const ChainRuleSet &rule_set = this+ruleSet[i];
1069         rule_set.closure (c, lookup_context);
1070       }
1071   }
1072
1073   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1074   {
1075     TRACE_APPLY ();
1076     unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1077     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1078
1079     const ClassDef &backtrack_class_def = this+backtrackClassDef;
1080     const ClassDef &input_class_def = this+inputClassDef;
1081     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1082
1083     index = input_class_def (c->buffer->cur().codepoint);
1084     const ChainRuleSet &rule_set = this+ruleSet[index];
1085     struct ChainContextApplyLookupContext lookup_context = {
1086       {match_class, apply_func},
1087       {&backtrack_class_def,
1088        &input_class_def,
1089        &lookahead_class_def}
1090     };
1091     return TRACE_RETURN (rule_set.apply (c, lookup_context));
1092   }
1093
1094   inline bool sanitize (hb_sanitize_context_t *c) {
1095     TRACE_SANITIZE ();
1096     return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
1097                          inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
1098                          ruleSet.sanitize (c, this));
1099   }
1100
1101   private:
1102   USHORT        format;                 /* Format identifier--format = 2 */
1103   OffsetTo<Coverage>
1104                 coverage;               /* Offset to Coverage table--from
1105                                          * beginning of table */
1106   OffsetTo<ClassDef>
1107                 backtrackClassDef;      /* Offset to glyph ClassDef table
1108                                          * containing backtrack sequence
1109                                          * data--from beginning of table */
1110   OffsetTo<ClassDef>
1111                 inputClassDef;          /* Offset to glyph ClassDef
1112                                          * table containing input sequence
1113                                          * data--from beginning of table */
1114   OffsetTo<ClassDef>
1115                 lookaheadClassDef;      /* Offset to glyph ClassDef table
1116                                          * containing lookahead sequence
1117                                          * data--from beginning of table */
1118   OffsetArrayOf<ChainRuleSet>
1119                 ruleSet;                /* Array of ChainRuleSet tables
1120                                          * ordered by class */
1121   public:
1122   DEFINE_SIZE_ARRAY (12, ruleSet);
1123 };
1124
1125 struct ChainContextFormat3
1126 {
1127   friend struct ChainContext;
1128
1129   private:
1130
1131   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1132   {
1133     TRACE_CLOSURE ();
1134     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1135
1136     if (!(this+input[0]).intersects (c->glyphs))
1137       return;
1138
1139     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1140     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1141     struct ChainContextClosureLookupContext lookup_context = {
1142       {intersects_coverage, closure_func},
1143       {this, this, this}
1144     };
1145     chain_context_closure_lookup (c,
1146                                   backtrack.len, (const USHORT *) backtrack.array,
1147                                   input.len, (const USHORT *) input.array + 1,
1148                                   lookahead.len, (const USHORT *) lookahead.array,
1149                                   lookup.len, lookup.array,
1150                                   lookup_context);
1151   }
1152
1153   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1154   {
1155     TRACE_APPLY ();
1156     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1157
1158     unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
1159     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1160
1161     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1162     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1163     struct ChainContextApplyLookupContext lookup_context = {
1164       {match_coverage, apply_func},
1165       {this, this, this}
1166     };
1167     return TRACE_RETURN (chain_context_apply_lookup (c,
1168                                                      backtrack.len, (const USHORT *) backtrack.array,
1169                                                      input.len, (const USHORT *) input.array + 1,
1170                                                      lookahead.len, (const USHORT *) lookahead.array,
1171                                                      lookup.len, lookup.array, lookup_context));
1172   }
1173
1174   inline bool sanitize (hb_sanitize_context_t *c) {
1175     TRACE_SANITIZE ();
1176     if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
1177     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1178     if (!input.sanitize (c, this)) return TRACE_RETURN (false);
1179     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1180     if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
1181     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1182     return TRACE_RETURN (lookup.sanitize (c));
1183   }
1184
1185   private:
1186   USHORT        format;                 /* Format identifier--format = 3 */
1187   OffsetArrayOf<Coverage>
1188                 backtrack;              /* Array of coverage tables
1189                                          * in backtracking sequence, in  glyph
1190                                          * sequence order */
1191   OffsetArrayOf<Coverage>
1192                 inputX          ;       /* Array of coverage
1193                                          * tables in input sequence, in glyph
1194                                          * sequence order */
1195   OffsetArrayOf<Coverage>
1196                 lookaheadX;             /* Array of coverage tables
1197                                          * in lookahead sequence, in glyph
1198                                          * sequence order */
1199   ArrayOf<LookupRecord>
1200                 lookupX;                /* Array of LookupRecords--in
1201                                          * design order) */
1202   public:
1203   DEFINE_SIZE_MIN (10);
1204 };
1205
1206 struct ChainContext
1207 {
1208   protected:
1209
1210   inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1211   {
1212     TRACE_CLOSURE ();
1213     switch (u.format) {
1214     case 1: u.format1.closure (c, closure_func); break;
1215     case 2: u.format2.closure (c, closure_func); break;
1216     case 3: u.format3.closure (c, closure_func); break;
1217     default:                                     break;
1218     }
1219   }
1220
1221   inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
1222   {
1223     TRACE_APPLY ();
1224     switch (u.format) {
1225     case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
1226     case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
1227     case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
1228     default:return TRACE_RETURN (false);
1229     }
1230   }
1231
1232   inline bool sanitize (hb_sanitize_context_t *c) {
1233     TRACE_SANITIZE ();
1234     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1235     switch (u.format) {
1236     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1237     case 2: return TRACE_RETURN (u.format2.sanitize (c));
1238     case 3: return TRACE_RETURN (u.format3.sanitize (c));
1239     default:return TRACE_RETURN (true);
1240     }
1241   }
1242
1243   private:
1244   union {
1245   USHORT                format; /* Format identifier */
1246   ChainContextFormat1   format1;
1247   ChainContextFormat2   format2;
1248   ChainContextFormat3   format3;
1249   } u;
1250 };
1251
1252
1253 struct ExtensionFormat1
1254 {
1255   friend struct Extension;
1256
1257   protected:
1258   inline unsigned int get_type (void) const { return extensionLookupType; }
1259   inline unsigned int get_offset (void) const { return extensionOffset; }
1260
1261   inline bool sanitize (hb_sanitize_context_t *c) {
1262     TRACE_SANITIZE ();
1263     return TRACE_RETURN (c->check_struct (this));
1264   }
1265
1266   private:
1267   USHORT        format;                 /* Format identifier. Set to 1. */
1268   USHORT        extensionLookupType;    /* Lookup type of subtable referenced
1269                                          * by ExtensionOffset (i.e. the
1270                                          * extension subtable). */
1271   ULONG         extensionOffset;        /* Offset to the extension subtable,
1272                                          * of lookup type subtable. */
1273   public:
1274   DEFINE_SIZE_STATIC (8);
1275 };
1276
1277 struct Extension
1278 {
1279   inline unsigned int get_type (void) const
1280   {
1281     switch (u.format) {
1282     case 1: return u.format1.get_type ();
1283     default:return 0;
1284     }
1285   }
1286   inline unsigned int get_offset (void) const
1287   {
1288     switch (u.format) {
1289     case 1: return u.format1.get_offset ();
1290     default:return 0;
1291     }
1292   }
1293
1294   inline bool sanitize (hb_sanitize_context_t *c) {
1295     TRACE_SANITIZE ();
1296     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1297     switch (u.format) {
1298     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1299     default:return TRACE_RETURN (true);
1300     }
1301   }
1302
1303   private:
1304   union {
1305   USHORT                format;         /* Format identifier */
1306   ExtensionFormat1      format1;
1307   } u;
1308 };
1309
1310
1311 /*
1312  * GSUB/GPOS Common
1313  */
1314
1315 struct GSUBGPOS
1316 {
1317   static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
1318   static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
1319
1320   inline unsigned int get_script_count (void) const
1321   { return (this+scriptList).len; }
1322   inline const Tag& get_script_tag (unsigned int i) const
1323   { return (this+scriptList).get_tag (i); }
1324   inline unsigned int get_script_tags (unsigned int start_offset,
1325                                        unsigned int *script_count /* IN/OUT */,
1326                                        hb_tag_t     *script_tags /* OUT */) const
1327   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
1328   inline const Script& get_script (unsigned int i) const
1329   { return (this+scriptList)[i]; }
1330   inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
1331   { return (this+scriptList).find_index (tag, index); }
1332
1333   inline unsigned int get_feature_count (void) const
1334   { return (this+featureList).len; }
1335   inline const Tag& get_feature_tag (unsigned int i) const
1336   { return (this+featureList).get_tag (i); }
1337   inline unsigned int get_feature_tags (unsigned int start_offset,
1338                                         unsigned int *feature_count /* IN/OUT */,
1339                                         hb_tag_t     *feature_tags /* OUT */) const
1340   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
1341   inline const Feature& get_feature (unsigned int i) const
1342   { return (this+featureList)[i]; }
1343   inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
1344   { return (this+featureList).find_index (tag, index); }
1345
1346   inline unsigned int get_lookup_count (void) const
1347   { return (this+lookupList).len; }
1348   inline const Lookup& get_lookup (unsigned int i) const
1349   { return (this+lookupList)[i]; }
1350
1351   inline bool sanitize (hb_sanitize_context_t *c) {
1352     TRACE_SANITIZE ();
1353     return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
1354                          scriptList.sanitize (c, this) &&
1355                          featureList.sanitize (c, this) &&
1356                          lookupList.sanitize (c, this));
1357   }
1358
1359   protected:
1360   FixedVersion  version;        /* Version of the GSUB/GPOS table--initially set
1361                                  * to 0x00010000 */
1362   OffsetTo<ScriptList>
1363                 scriptList;     /* ScriptList table */
1364   OffsetTo<FeatureList>
1365                 featureList;    /* FeatureList table */
1366   OffsetTo<LookupList>
1367                 lookupList;     /* LookupList table */
1368   public:
1369   DEFINE_SIZE_STATIC (10);
1370 };
1371
1372
1373
1374 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */