763ea92f935ce55f9850e32438f03b5fc28c1199
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-common-private.hh
1 /*
2  * Copyright © 2007,2008,2009  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_COMMON_PRIVATE_HH
30 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
31
32 #include "hb-private.hh"
33 #include "hb-debug.hh"
34 #include "hb-ot-layout-private.hh"
35 #include "hb-open-type-private.hh"
36 #include "hb-set-private.hh"
37
38
39 #ifndef HB_MAX_NESTING_LEVEL
40 #define HB_MAX_NESTING_LEVEL    6
41 #endif
42 #ifndef HB_MAX_CONTEXT_LENGTH
43 #define HB_MAX_CONTEXT_LENGTH   64
44 #endif
45
46
47 namespace OT {
48
49
50 #define NOT_COVERED             ((unsigned int) -1)
51
52
53
54 /*
55  *
56  * OpenType Layout Common Table Formats
57  *
58  */
59
60
61 /*
62  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
63  */
64
65 template <typename Type>
66 struct Record
67 {
68   inline int cmp (hb_tag_t a) const {
69     return tag.cmp (a);
70   }
71
72   struct sanitize_closure_t {
73     hb_tag_t tag;
74     const void *list_base;
75   };
76   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
77   {
78     TRACE_SANITIZE (this);
79     const sanitize_closure_t closure = {tag, base};
80     return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
81   }
82
83   Tag           tag;            /* 4-byte Tag identifier */
84   OffsetTo<Type>
85                 offset;         /* Offset from beginning of object holding
86                                  * the Record */
87   public:
88   DEFINE_SIZE_STATIC (6);
89 };
90
91 template <typename Type>
92 struct RecordArrayOf : SortedArrayOf<Record<Type> > {
93   inline const Tag& get_tag (unsigned int i) const
94   {
95     /* We cheat slightly and don't define separate Null objects
96      * for Record types.  Instead, we return the correct Null(Tag)
97      * here. */
98     if (unlikely (i >= this->len)) return Null(Tag);
99     return (*this)[i].tag;
100   }
101   inline unsigned int get_tags (unsigned int start_offset,
102                                 unsigned int *record_count /* IN/OUT */,
103                                 hb_tag_t     *record_tags /* OUT */) const
104   {
105     if (record_count) {
106       const Record<Type> *arr = this->sub_array (start_offset, record_count);
107       unsigned int count = *record_count;
108       for (unsigned int i = 0; i < count; i++)
109         record_tags[i] = arr[i].tag;
110     }
111     return this->len;
112   }
113   inline bool find_index (hb_tag_t tag, unsigned int *index) const
114   {
115     /* If we want to allow non-sorted data, we can lsearch(). */
116     int i = this->/*lsearch*/bsearch (tag);
117     if (i != -1) {
118         if (index) *index = i;
119         return true;
120     } else {
121       if (index) *index = Index::NOT_FOUND_INDEX;
122       return false;
123     }
124   }
125 };
126
127 template <typename Type>
128 struct RecordListOf : RecordArrayOf<Type>
129 {
130   inline const Type& operator [] (unsigned int i) const
131   { return this+RecordArrayOf<Type>::operator [](i).offset; }
132
133   inline bool sanitize (hb_sanitize_context_t *c) const
134   {
135     TRACE_SANITIZE (this);
136     return_trace (RecordArrayOf<Type>::sanitize (c, this));
137   }
138 };
139
140
141 struct RangeRecord
142 {
143   inline int cmp (hb_codepoint_t g) const {
144     return g < start ? -1 : g <= end ? 0 : +1 ;
145   }
146
147   inline bool sanitize (hb_sanitize_context_t *c) const
148   {
149     TRACE_SANITIZE (this);
150     return_trace (c->check_struct (this));
151   }
152
153   inline bool intersects (const hb_set_t *glyphs) const {
154     return glyphs->intersects (start, end);
155   }
156
157   template <typename set_t>
158   inline bool add_coverage (set_t *glyphs) const {
159     return glyphs->add_range (start, end);
160   }
161
162   GlyphID       start;          /* First GlyphID in the range */
163   GlyphID       end;            /* Last GlyphID in the range */
164   HBUINT16      value;          /* Value */
165   public:
166   DEFINE_SIZE_STATIC (6);
167 };
168 DEFINE_NULL_DATA (OT, RangeRecord, "\000\001");
169
170
171 struct IndexArray : ArrayOf<Index>
172 {
173   inline unsigned int get_indexes (unsigned int start_offset,
174                                    unsigned int *_count /* IN/OUT */,
175                                    unsigned int *_indexes /* OUT */) const
176   {
177     if (_count) {
178       const HBUINT16 *arr = this->sub_array (start_offset, _count);
179       unsigned int count = *_count;
180       for (unsigned int i = 0; i < count; i++)
181         _indexes[i] = arr[i];
182     }
183     return this->len;
184   }
185 };
186
187
188 struct Script;
189 struct LangSys;
190 struct Feature;
191
192
193 struct LangSys
194 {
195   inline unsigned int get_feature_count (void) const
196   { return featureIndex.len; }
197   inline hb_tag_t get_feature_index (unsigned int i) const
198   { return featureIndex[i]; }
199   inline unsigned int get_feature_indexes (unsigned int start_offset,
200                                            unsigned int *feature_count /* IN/OUT */,
201                                            unsigned int *feature_indexes /* OUT */) const
202   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
203
204   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
205   inline unsigned int get_required_feature_index (void) const
206   {
207     if (reqFeatureIndex == 0xFFFFu)
208       return Index::NOT_FOUND_INDEX;
209    return reqFeatureIndex;;
210   }
211
212   inline bool sanitize (hb_sanitize_context_t *c,
213                         const Record<LangSys>::sanitize_closure_t * = nullptr) const
214   {
215     TRACE_SANITIZE (this);
216     return_trace (c->check_struct (this) && featureIndex.sanitize (c));
217   }
218
219   Offset16      lookupOrderZ;   /* = Null (reserved for an offset to a
220                                  * reordering table) */
221   HBUINT16      reqFeatureIndex;/* Index of a feature required for this
222                                  * language system--if no required features
223                                  * = 0xFFFFu */
224   IndexArray    featureIndex;   /* Array of indices into the FeatureList */
225   public:
226   DEFINE_SIZE_ARRAY (6, featureIndex);
227 };
228 DEFINE_NULL_DATA (OT, LangSys, "\0\0\xFF\xFF");
229
230
231 struct Script
232 {
233   inline unsigned int get_lang_sys_count (void) const
234   { return langSys.len; }
235   inline const Tag& get_lang_sys_tag (unsigned int i) const
236   { return langSys.get_tag (i); }
237   inline unsigned int get_lang_sys_tags (unsigned int start_offset,
238                                          unsigned int *lang_sys_count /* IN/OUT */,
239                                          hb_tag_t     *lang_sys_tags /* OUT */) const
240   { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
241   inline const LangSys& get_lang_sys (unsigned int i) const
242   {
243     if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
244     return this+langSys[i].offset;
245   }
246   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
247   { return langSys.find_index (tag, index); }
248
249   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
250   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
251
252   inline bool sanitize (hb_sanitize_context_t *c,
253                         const Record<Script>::sanitize_closure_t * = nullptr) const
254   {
255     TRACE_SANITIZE (this);
256     return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
257   }
258
259   protected:
260   OffsetTo<LangSys>
261                 defaultLangSys; /* Offset to DefaultLangSys table--from
262                                  * beginning of Script table--may be Null */
263   RecordArrayOf<LangSys>
264                 langSys;        /* Array of LangSysRecords--listed
265                                  * alphabetically by LangSysTag */
266   public:
267   DEFINE_SIZE_ARRAY (4, langSys);
268 };
269
270 typedef RecordListOf<Script> ScriptList;
271
272
273 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
274 struct FeatureParamsSize
275 {
276   inline bool sanitize (hb_sanitize_context_t *c) const
277   {
278     TRACE_SANITIZE (this);
279     if (unlikely (!c->check_struct (this))) return_trace (false);
280
281     /* This subtable has some "history", if you will.  Some earlier versions of
282      * Adobe tools calculated the offset of the FeatureParams sutable from the
283      * beginning of the FeatureList table!  Now, that is dealt with in the
284      * Feature implementation.  But we still need to be able to tell junk from
285      * real data.  Note: We don't check that the nameID actually exists.
286      *
287      * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
288      *
289      * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
290      * coming out soon, and that the makeotf program will build a font with a
291      * 'size' feature that is correct by the specification.
292      *
293      * The specification for this feature tag is in the "OpenType Layout Tag
294      * Registry". You can see a copy of this at:
295      * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
296      *
297      * Here is one set of rules to determine if the 'size' feature is built
298      * correctly, or as by the older versions of MakeOTF. You may be able to do
299      * better.
300      *
301      * Assume that the offset to the size feature is according to specification,
302      * and make the following value checks. If it fails, assume the size
303      * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
304      * If this fails, reject the 'size' feature. The older makeOTF's calculated the
305      * offset from the beginning of the FeatureList table, rather than from the
306      * beginning of the 'size' Feature table.
307      *
308      * If "design size" == 0:
309      *     fails check
310      *
311      * Else if ("subfamily identifier" == 0 and
312      *     "range start" == 0 and
313      *     "range end" == 0 and
314      *     "range start" == 0 and
315      *     "menu name ID" == 0)
316      *     passes check: this is the format used when there is a design size
317      * specified, but there is no recommended size range.
318      *
319      * Else if ("design size" <  "range start" or
320      *     "design size" >   "range end" or
321      *     "range end" <= "range start" or
322      *     "menu name ID"  < 256 or
323      *     "menu name ID"  > 32767 or
324      *     menu name ID is not a name ID which is actually in the name table)
325      *     fails test
326      * Else
327      *     passes test.
328      */
329
330     if (!designSize)
331       return_trace (false);
332     else if (subfamilyID == 0 &&
333              subfamilyNameID == 0 &&
334              rangeStart == 0 &&
335              rangeEnd == 0)
336       return_trace (true);
337     else if (designSize < rangeStart ||
338              designSize > rangeEnd ||
339              subfamilyNameID < 256 ||
340              subfamilyNameID > 32767)
341       return_trace (false);
342     else
343       return_trace (true);
344   }
345
346   HBUINT16      designSize;     /* Represents the design size in 720/inch
347                                  * units (decipoints).  The design size entry
348                                  * must be non-zero.  When there is a design
349                                  * size but no recommended size range, the
350                                  * rest of the array will consist of zeros. */
351   HBUINT16      subfamilyID;    /* Has no independent meaning, but serves
352                                  * as an identifier that associates fonts
353                                  * in a subfamily. All fonts which share a
354                                  * Preferred or Font Family name and which
355                                  * differ only by size range shall have the
356                                  * same subfamily value, and no fonts which
357                                  * differ in weight or style shall have the
358                                  * same subfamily value. If this value is
359                                  * zero, the remaining fields in the array
360                                  * will be ignored. */
361   HBUINT16      subfamilyNameID;/* If the preceding value is non-zero, this
362                                  * value must be set in the range 256 - 32767
363                                  * (inclusive). It records the value of a
364                                  * field in the name table, which must
365                                  * contain English-language strings encoded
366                                  * in Windows Unicode and Macintosh Roman,
367                                  * and may contain additional strings
368                                  * localized to other scripts and languages.
369                                  * Each of these strings is the name an
370                                  * application should use, in combination
371                                  * with the family name, to represent the
372                                  * subfamily in a menu.  Applications will
373                                  * choose the appropriate version based on
374                                  * their selection criteria. */
375   HBUINT16      rangeStart;     /* Large end of the recommended usage range
376                                  * (inclusive), stored in 720/inch units
377                                  * (decipoints). */
378   HBUINT16      rangeEnd;       /* Small end of the recommended usage range
379                                    (exclusive), stored in 720/inch units
380                                  * (decipoints). */
381   public:
382   DEFINE_SIZE_STATIC (10);
383 };
384
385 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
386 struct FeatureParamsStylisticSet
387 {
388   inline bool sanitize (hb_sanitize_context_t *c) const
389   {
390     TRACE_SANITIZE (this);
391     /* Right now minorVersion is at zero.  Which means, any table supports
392      * the uiNameID field. */
393     return_trace (c->check_struct (this));
394   }
395
396   HBUINT16      version;        /* (set to 0): This corresponds to a “minor”
397                                  * version number. Additional data may be
398                                  * added to the end of this Feature Parameters
399                                  * table in the future. */
400
401   NameID        uiNameID;       /* The 'name' table name ID that specifies a
402                                  * string (or strings, for multiple languages)
403                                  * for a user-interface label for this
404                                  * feature.  The values of uiLabelNameId and
405                                  * sampleTextNameId are expected to be in the
406                                  * font-specific name ID range (256-32767),
407                                  * though that is not a requirement in this
408                                  * Feature Parameters specification. The
409                                  * user-interface label for the feature can
410                                  * be provided in multiple languages. An
411                                  * English string should be included as a
412                                  * fallback. The string should be kept to a
413                                  * minimal length to fit comfortably with
414                                  * different application interfaces. */
415   public:
416   DEFINE_SIZE_STATIC (4);
417 };
418
419 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
420 struct FeatureParamsCharacterVariants
421 {
422   inline bool sanitize (hb_sanitize_context_t *c) const
423   {
424     TRACE_SANITIZE (this);
425     return_trace (c->check_struct (this) &&
426                   characters.sanitize (c));
427   }
428
429   HBUINT16      format;                 /* Format number is set to 0. */
430   NameID        featUILableNameID;      /* The ‘name’ table name ID that
431                                          * specifies a string (or strings,
432                                          * for multiple languages) for a
433                                          * user-interface label for this
434                                          * feature. (May be nullptr.) */
435   NameID        featUITooltipTextNameID;/* The ‘name’ table name ID that
436                                          * specifies a string (or strings,
437                                          * for multiple languages) that an
438                                          * application can use for tooltip
439                                          * text for this feature. (May be
440                                          * nullptr.) */
441   NameID        sampleTextNameID;       /* The ‘name’ table name ID that
442                                          * specifies sample text that
443                                          * illustrates the effect of this
444                                          * feature. (May be nullptr.) */
445   HBUINT16      numNamedParameters;     /* Number of named parameters. (May
446                                          * be zero.) */
447   NameID        firstParamUILabelNameID;/* The first ‘name’ table name ID
448                                          * used to specify strings for
449                                          * user-interface labels for the
450                                          * feature parameters. (Must be zero
451                                          * if numParameters is zero.) */
452   ArrayOf<HBUINT24>
453                 characters;             /* Array of the Unicode Scalar Value
454                                          * of the characters for which this
455                                          * feature provides glyph variants.
456                                          * (May be zero.) */
457   public:
458   DEFINE_SIZE_ARRAY (14, characters);
459 };
460
461 struct FeatureParams
462 {
463   inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
464   {
465     TRACE_SANITIZE (this);
466     if (tag == HB_TAG ('s','i','z','e'))
467       return_trace (u.size.sanitize (c));
468     if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
469       return_trace (u.stylisticSet.sanitize (c));
470     if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
471       return_trace (u.characterVariants.sanitize (c));
472     return_trace (true);
473   }
474
475   inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
476   {
477     if (tag == HB_TAG ('s','i','z','e'))
478       return u.size;
479     return Null(FeatureParamsSize);
480   }
481
482   private:
483   union {
484   FeatureParamsSize                     size;
485   FeatureParamsStylisticSet             stylisticSet;
486   FeatureParamsCharacterVariants        characterVariants;
487   } u;
488   DEFINE_SIZE_STATIC (17);
489 };
490
491 struct Feature
492 {
493   inline unsigned int get_lookup_count (void) const
494   { return lookupIndex.len; }
495   inline hb_tag_t get_lookup_index (unsigned int i) const
496   { return lookupIndex[i]; }
497   inline unsigned int get_lookup_indexes (unsigned int start_index,
498                                           unsigned int *lookup_count /* IN/OUT */,
499                                           unsigned int *lookup_tags /* OUT */) const
500   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
501
502   inline const FeatureParams &get_feature_params (void) const
503   { return this+featureParams; }
504
505   inline bool sanitize (hb_sanitize_context_t *c,
506                         const Record<Feature>::sanitize_closure_t *closure = nullptr) const
507   {
508     TRACE_SANITIZE (this);
509     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
510       return_trace (false);
511
512     /* Some earlier versions of Adobe tools calculated the offset of the
513      * FeatureParams subtable from the beginning of the FeatureList table!
514      *
515      * If sanitizing "failed" for the FeatureParams subtable, try it with the
516      * alternative location.  We would know sanitize "failed" if old value
517      * of the offset was non-zero, but it's zeroed now.
518      *
519      * Only do this for the 'size' feature, since at the time of the faulty
520      * Adobe tools, only the 'size' feature had FeatureParams defined.
521      */
522
523     OffsetTo<FeatureParams> orig_offset = featureParams;
524     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
525       return_trace (false);
526
527     if (likely (orig_offset.is_null ()))
528       return_trace (true);
529
530     if (featureParams == 0 && closure &&
531         closure->tag == HB_TAG ('s','i','z','e') &&
532         closure->list_base && closure->list_base < this)
533     {
534       unsigned int new_offset_int = (unsigned int) orig_offset -
535                                     (((char *) this) - ((char *) closure->list_base));
536
537       OffsetTo<FeatureParams> new_offset;
538       /* Check that it did not overflow. */
539       new_offset.set (new_offset_int);
540       if (new_offset == new_offset_int &&
541           c->try_set (&featureParams, new_offset) &&
542           !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
543         return_trace (false);
544
545       if (c->edit_count > 1)
546         c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
547     }
548
549     return_trace (true);
550   }
551
552   OffsetTo<FeatureParams>
553                  featureParams; /* Offset to Feature Parameters table (if one
554                                  * has been defined for the feature), relative
555                                  * to the beginning of the Feature Table; = Null
556                                  * if not required */
557   IndexArray     lookupIndex;   /* Array of LookupList indices */
558   public:
559   DEFINE_SIZE_ARRAY (4, lookupIndex);
560 };
561
562 typedef RecordListOf<Feature> FeatureList;
563
564
565 struct LookupFlag : HBUINT16
566 {
567   enum Flags {
568     RightToLeft         = 0x0001u,
569     IgnoreBaseGlyphs    = 0x0002u,
570     IgnoreLigatures     = 0x0004u,
571     IgnoreMarks         = 0x0008u,
572     IgnoreFlags         = 0x000Eu,
573     UseMarkFilteringSet = 0x0010u,
574     Reserved            = 0x00E0u,
575     MarkAttachmentType  = 0xFF00u
576   };
577   public:
578   DEFINE_SIZE_STATIC (2);
579 };
580
581 } /* namespace OT */
582 /* This has to be outside the namespace. */
583 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
584 namespace OT {
585
586 struct Lookup
587 {
588   inline unsigned int get_subtable_count (void) const { return subTable.len; }
589
590   template <typename SubTableType>
591   inline const SubTableType& get_subtable (unsigned int i) const
592   { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
593
594   template <typename SubTableType>
595   inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
596   { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
597   template <typename SubTableType>
598   inline OffsetArrayOf<SubTableType>& get_subtables (void)
599   { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
600
601   inline unsigned int get_type (void) const { return lookupType; }
602
603   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
604    * higher 16-bit is mark-filtering-set if the lookup uses one.
605    * Not to be confused with glyph_props which is very similar. */
606   inline uint32_t get_props (void) const
607   {
608     unsigned int flag = lookupFlag;
609     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
610     {
611       const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
612       flag += (markFilteringSet << 16);
613     }
614     return flag;
615   }
616
617   template <typename SubTableType, typename context_t>
618   inline typename context_t::return_t dispatch (context_t *c) const
619   {
620     unsigned int lookup_type = get_type ();
621     TRACE_DISPATCH (this, lookup_type);
622     unsigned int count = get_subtable_count ();
623     for (unsigned int i = 0; i < count; i++) {
624       typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
625       if (c->stop_sublookup_iteration (r))
626         return_trace (r);
627     }
628     return_trace (c->default_return_value ());
629   }
630
631   inline bool serialize (hb_serialize_context_t *c,
632                          unsigned int lookup_type,
633                          uint32_t lookup_props,
634                          unsigned int num_subtables)
635   {
636     TRACE_SERIALIZE (this);
637     if (unlikely (!c->extend_min (*this))) return_trace (false);
638     lookupType.set (lookup_type);
639     lookupFlag.set (lookup_props & 0xFFFFu);
640     if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
641     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
642     {
643       HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
644       markFilteringSet.set (lookup_props >> 16);
645     }
646     return_trace (true);
647   }
648
649   inline bool sanitize (hb_sanitize_context_t *c) const
650   {
651     TRACE_SANITIZE (this);
652     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
653     if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
654     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
655     {
656       const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
657       if (!markFilteringSet.sanitize (c)) return_trace (false);
658     }
659     return_trace (true);
660   }
661
662   private:
663   HBUINT16      lookupType;             /* Different enumerations for GSUB and GPOS */
664   HBUINT16      lookupFlag;             /* Lookup qualifiers */
665   ArrayOf<Offset16>
666                 subTable;               /* Array of SubTables */
667   HBUINT16      markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
668                                          * structure. This field is only present if bit
669                                          * UseMarkFilteringSet of lookup flags is set. */
670   public:
671   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
672 };
673
674 typedef OffsetListOf<Lookup> LookupList;
675
676
677 /*
678  * Coverage Table
679  */
680
681 struct CoverageFormat1
682 {
683   friend struct Coverage;
684
685   private:
686   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
687   {
688     int i = glyphArray.bsearch (glyph_id);
689     static_assert ((((unsigned int) -1) == NOT_COVERED), "");
690     return i;
691   }
692
693   inline bool serialize (hb_serialize_context_t *c,
694                          Supplier<GlyphID> &glyphs,
695                          unsigned int num_glyphs)
696   {
697     TRACE_SERIALIZE (this);
698     if (unlikely (!c->extend_min (*this))) return_trace (false);
699     glyphArray.len.set (num_glyphs);
700     if (unlikely (!c->extend (glyphArray))) return_trace (false);
701     for (unsigned int i = 0; i < num_glyphs; i++)
702       glyphArray[i] = glyphs[i];
703     glyphs += num_glyphs;
704     return_trace (true);
705   }
706
707   inline bool sanitize (hb_sanitize_context_t *c) const
708   {
709     TRACE_SANITIZE (this);
710     return_trace (glyphArray.sanitize (c));
711   }
712
713   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
714     return glyphs->has (glyphArray[index]);
715   }
716
717   template <typename set_t>
718   inline bool add_coverage (set_t *glyphs) const {
719     return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
720   }
721
722   public:
723   /* Older compilers need this to be public. */
724   struct Iter {
725     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
726     inline bool more (void) { return i < c->glyphArray.len; }
727     inline void next (void) { i++; }
728     inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
729     inline unsigned int get_coverage (void) { return i; }
730
731     private:
732     const struct CoverageFormat1 *c;
733     unsigned int i;
734   };
735   private:
736
737   protected:
738   HBUINT16      coverageFormat; /* Format identifier--format = 1 */
739   SortedArrayOf<GlyphID>
740                 glyphArray;     /* Array of GlyphIDs--in numerical order */
741   public:
742   DEFINE_SIZE_ARRAY (4, glyphArray);
743 };
744
745 struct CoverageFormat2
746 {
747   friend struct Coverage;
748
749   private:
750   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
751   {
752     int i = rangeRecord.bsearch (glyph_id);
753     if (i != -1) {
754       const RangeRecord &range = rangeRecord[i];
755       return (unsigned int) range.value + (glyph_id - range.start);
756     }
757     return NOT_COVERED;
758   }
759
760   inline bool serialize (hb_serialize_context_t *c,
761                          Supplier<GlyphID> &glyphs,
762                          unsigned int num_glyphs)
763   {
764     TRACE_SERIALIZE (this);
765     if (unlikely (!c->extend_min (*this))) return_trace (false);
766
767     if (unlikely (!num_glyphs))
768     {
769       rangeRecord.len.set (0);
770       return_trace (true);
771     }
772
773     unsigned int num_ranges = 1;
774     for (unsigned int i = 1; i < num_glyphs; i++)
775       if (glyphs[i - 1] + 1 != glyphs[i])
776         num_ranges++;
777     rangeRecord.len.set (num_ranges);
778     if (unlikely (!c->extend (rangeRecord))) return_trace (false);
779
780     unsigned int range = 0;
781     rangeRecord[range].start = glyphs[0];
782     rangeRecord[range].value.set (0);
783     for (unsigned int i = 1; i < num_glyphs; i++)
784       if (glyphs[i - 1] + 1 != glyphs[i]) {
785         range++;
786         rangeRecord[range].start = glyphs[i];
787         rangeRecord[range].value.set (i);
788         rangeRecord[range].end = glyphs[i];
789       } else {
790         rangeRecord[range].end = glyphs[i];
791       }
792     glyphs += num_glyphs;
793     return_trace (true);
794   }
795
796   inline bool sanitize (hb_sanitize_context_t *c) const
797   {
798     TRACE_SANITIZE (this);
799     return_trace (rangeRecord.sanitize (c));
800   }
801
802   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
803     unsigned int i;
804     unsigned int count = rangeRecord.len;
805     for (i = 0; i < count; i++) {
806       const RangeRecord &range = rangeRecord[i];
807       if (range.value <= index &&
808           index < (unsigned int) range.value + (range.end - range.start) &&
809           range.intersects (glyphs))
810         return true;
811       else if (index < range.value)
812         return false;
813     }
814     return false;
815   }
816
817   template <typename set_t>
818   inline bool add_coverage (set_t *glyphs) const {
819     unsigned int count = rangeRecord.len;
820     for (unsigned int i = 0; i < count; i++)
821       if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
822         return false;
823     return true;
824   }
825
826   public:
827   /* Older compilers need this to be public. */
828   struct Iter
829   {
830     inline void init (const CoverageFormat2 &c_)
831     {
832       c = &c_;
833       coverage = 0;
834       i = 0;
835       j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
836     }
837     inline bool more (void) { return i < c->rangeRecord.len; }
838     inline void next (void)
839     {
840       if (j >= c->rangeRecord[i].end)
841       {
842         i++;
843         if (more ())
844         {
845           j = c->rangeRecord[i].start;
846           coverage = c->rangeRecord[i].value;
847         }
848         return;
849       }
850       coverage++;
851       j++;
852     }
853     inline hb_codepoint_t get_glyph (void) { return j; }
854     inline unsigned int get_coverage (void) { return coverage; }
855
856     private:
857     const struct CoverageFormat2 *c;
858     unsigned int i, j, coverage;
859   };
860   private:
861
862   protected:
863   HBUINT16      coverageFormat; /* Format identifier--format = 2 */
864   SortedArrayOf<RangeRecord>
865                 rangeRecord;    /* Array of glyph ranges--ordered by
866                                  * Start GlyphID. rangeCount entries
867                                  * long */
868   public:
869   DEFINE_SIZE_ARRAY (4, rangeRecord);
870 };
871
872 struct Coverage
873 {
874   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
875   {
876     switch (u.format) {
877     case 1: return u.format1.get_coverage (glyph_id);
878     case 2: return u.format2.get_coverage (glyph_id);
879     default:return NOT_COVERED;
880     }
881   }
882
883   inline bool serialize (hb_serialize_context_t *c,
884                          Supplier<GlyphID> &glyphs,
885                          unsigned int num_glyphs)
886   {
887     TRACE_SERIALIZE (this);
888     if (unlikely (!c->extend_min (*this))) return_trace (false);
889     unsigned int num_ranges = 1;
890     for (unsigned int i = 1; i < num_glyphs; i++)
891       if (glyphs[i - 1] + 1 != glyphs[i])
892         num_ranges++;
893     u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
894     switch (u.format) {
895     case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
896     case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
897     default:return_trace (false);
898     }
899   }
900
901   inline bool sanitize (hb_sanitize_context_t *c) const
902   {
903     TRACE_SANITIZE (this);
904     if (!u.format.sanitize (c)) return_trace (false);
905     switch (u.format) {
906     case 1: return_trace (u.format1.sanitize (c));
907     case 2: return_trace (u.format2.sanitize (c));
908     default:return_trace (true);
909     }
910   }
911
912   inline bool intersects (const hb_set_t *glyphs) const {
913     /* TODO speed this up */
914     Coverage::Iter iter;
915     for (iter.init (*this); iter.more (); iter.next ()) {
916       if (glyphs->has (iter.get_glyph ()))
917         return true;
918     }
919     return false;
920   }
921
922   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
923     switch (u.format) {
924     case 1: return u.format1.intersects_coverage (glyphs, index);
925     case 2: return u.format2.intersects_coverage (glyphs, index);
926     default:return false;
927     }
928   }
929
930   /* Might return false if array looks unsorted.
931    * Used for faster rejection of corrupt data. */
932   template <typename set_t>
933   inline bool add_coverage (set_t *glyphs) const {
934     switch (u.format) {
935     case 1: return u.format1.add_coverage (glyphs);
936     case 2: return u.format2.add_coverage (glyphs);
937     default:return false;
938     }
939   }
940
941   struct Iter {
942     Iter (void) : format (0), u () {};
943     inline void init (const Coverage &c_) {
944       format = c_.u.format;
945       switch (format) {
946       case 1: u.format1.init (c_.u.format1); return;
947       case 2: u.format2.init (c_.u.format2); return;
948       default:                               return;
949       }
950     }
951     inline bool more (void) {
952       switch (format) {
953       case 1: return u.format1.more ();
954       case 2: return u.format2.more ();
955       default:return false;
956       }
957     }
958     inline void next (void) {
959       switch (format) {
960       case 1: u.format1.next (); break;
961       case 2: u.format2.next (); break;
962       default:                   break;
963       }
964     }
965     inline hb_codepoint_t get_glyph (void) {
966       switch (format) {
967       case 1: return u.format1.get_glyph ();
968       case 2: return u.format2.get_glyph ();
969       default:return 0;
970       }
971     }
972     inline unsigned int get_coverage (void) {
973       switch (format) {
974       case 1: return u.format1.get_coverage ();
975       case 2: return u.format2.get_coverage ();
976       default:return -1;
977       }
978     }
979
980     private:
981     unsigned int format;
982     union {
983     CoverageFormat2::Iter       format2; /* Put this one first since it's larger; helps shut up compiler. */
984     CoverageFormat1::Iter       format1;
985     } u;
986   };
987
988   protected:
989   union {
990   HBUINT16              format;         /* Format identifier */
991   CoverageFormat1       format1;
992   CoverageFormat2       format2;
993   } u;
994   public:
995   DEFINE_SIZE_UNION (2, format);
996 };
997
998
999 /*
1000  * Class Definition Table
1001  */
1002
1003 struct ClassDefFormat1
1004 {
1005   friend struct ClassDef;
1006
1007   private:
1008   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1009   {
1010     unsigned int i = (unsigned int) (glyph_id - startGlyph);
1011     if (unlikely (i < classValue.len))
1012       return classValue[i];
1013     return 0;
1014   }
1015
1016   inline bool sanitize (hb_sanitize_context_t *c) const
1017   {
1018     TRACE_SANITIZE (this);
1019     return_trace (c->check_struct (this) && classValue.sanitize (c));
1020   }
1021
1022   template <typename set_t>
1023   inline bool add_coverage (set_t *glyphs) const {
1024     unsigned int start = 0;
1025     unsigned int count = classValue.len;
1026     for (unsigned int i = 0; i < count; i++)
1027     {
1028       if (classValue[i])
1029         continue;
1030
1031       if (start != i)
1032         if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1033           return false;
1034
1035       start = i + 1;
1036     }
1037     if (start != count)
1038       if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1039         return false;
1040
1041     return true;
1042   }
1043
1044   template <typename set_t>
1045   inline bool add_class (set_t *glyphs, unsigned int klass) const {
1046     unsigned int count = classValue.len;
1047     for (unsigned int i = 0; i < count; i++)
1048     {
1049       if (classValue[i] == klass)
1050         glyphs->add (startGlyph + i);
1051     }
1052     return true;
1053   }
1054
1055   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1056     unsigned int count = classValue.len;
1057     if (klass == 0)
1058     {
1059       /* Match if there's any glyph that is not listed! */
1060       hb_codepoint_t g = HB_SET_VALUE_INVALID;
1061       if (!hb_set_next (glyphs, &g))
1062         return false;
1063       if (g < startGlyph)
1064         return true;
1065       g = startGlyph + count - 1;
1066       if (hb_set_next (glyphs, &g))
1067         return true;
1068       /* Fall through. */
1069     }
1070     for (unsigned int i = 0; i < count; i++)
1071       if (classValue[i] == klass && glyphs->has (startGlyph + i))
1072         return true;
1073     return false;
1074   }
1075
1076   protected:
1077   HBUINT16      classFormat;            /* Format identifier--format = 1 */
1078   GlyphID       startGlyph;             /* First GlyphID of the classValueArray */
1079   ArrayOf<HBUINT16>
1080                 classValue;             /* Array of Class Values--one per GlyphID */
1081   public:
1082   DEFINE_SIZE_ARRAY (6, classValue);
1083 };
1084
1085 struct ClassDefFormat2
1086 {
1087   friend struct ClassDef;
1088
1089   private:
1090   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1091   {
1092     int i = rangeRecord.bsearch (glyph_id);
1093     if (unlikely (i != -1))
1094       return rangeRecord[i].value;
1095     return 0;
1096   }
1097
1098   inline bool sanitize (hb_sanitize_context_t *c) const
1099   {
1100     TRACE_SANITIZE (this);
1101     return_trace (rangeRecord.sanitize (c));
1102   }
1103
1104   template <typename set_t>
1105   inline bool add_coverage (set_t *glyphs) const {
1106     unsigned int count = rangeRecord.len;
1107     for (unsigned int i = 0; i < count; i++)
1108       if (rangeRecord[i].value)
1109         if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1110           return false;
1111     return true;
1112   }
1113
1114   template <typename set_t>
1115   inline bool add_class (set_t *glyphs, unsigned int klass) const {
1116     unsigned int count = rangeRecord.len;
1117     for (unsigned int i = 0; i < count; i++)
1118     {
1119       if (rangeRecord[i].value == klass)
1120         if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1121           return false;
1122     }
1123     return true;
1124   }
1125
1126   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1127     unsigned int count = rangeRecord.len;
1128     if (klass == 0)
1129     {
1130       /* Match if there's any glyph that is not listed! */
1131       hb_codepoint_t g = HB_SET_VALUE_INVALID;
1132       for (unsigned int i = 0; i < count; i++)
1133       {
1134         if (!hb_set_next (glyphs, &g))
1135           break;
1136         if (g < rangeRecord[i].start)
1137           return true;
1138         g = rangeRecord[i].end;
1139       }
1140       if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1141         return true;
1142       /* Fall through. */
1143     }
1144     for (unsigned int i = 0; i < count; i++)
1145       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1146         return true;
1147     return false;
1148   }
1149
1150   protected:
1151   HBUINT16      classFormat;    /* Format identifier--format = 2 */
1152   SortedArrayOf<RangeRecord>
1153                 rangeRecord;    /* Array of glyph ranges--ordered by
1154                                  * Start GlyphID */
1155   public:
1156   DEFINE_SIZE_ARRAY (4, rangeRecord);
1157 };
1158
1159 struct ClassDef
1160 {
1161   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1162   {
1163     switch (u.format) {
1164     case 1: return u.format1.get_class (glyph_id);
1165     case 2: return u.format2.get_class (glyph_id);
1166     default:return 0;
1167     }
1168   }
1169
1170   inline bool sanitize (hb_sanitize_context_t *c) const
1171   {
1172     TRACE_SANITIZE (this);
1173     if (!u.format.sanitize (c)) return_trace (false);
1174     switch (u.format) {
1175     case 1: return_trace (u.format1.sanitize (c));
1176     case 2: return_trace (u.format2.sanitize (c));
1177     default:return_trace (true);
1178     }
1179   }
1180
1181   /* Might return false if array looks unsorted.
1182    * Used for faster rejection of corrupt data. */
1183   template <typename set_t>
1184   inline bool add_coverage (set_t *glyphs) const {
1185     switch (u.format) {
1186     case 1: return u.format1.add_coverage (glyphs);
1187     case 2: return u.format2.add_coverage (glyphs);
1188     default:return false;
1189     }
1190   }
1191
1192   /* Might return false if array looks unsorted.
1193    * Used for faster rejection of corrupt data. */
1194   template <typename set_t>
1195   inline bool add_class (set_t *glyphs, unsigned int klass) const {
1196     switch (u.format) {
1197     case 1: return u.format1.add_class (glyphs, klass);
1198     case 2: return u.format2.add_class (glyphs, klass);
1199     default:return false;
1200     }
1201   }
1202
1203   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1204     switch (u.format) {
1205     case 1: return u.format1.intersects_class (glyphs, klass);
1206     case 2: return u.format2.intersects_class (glyphs, klass);
1207     default:return false;
1208     }
1209   }
1210
1211   protected:
1212   union {
1213   HBUINT16              format;         /* Format identifier */
1214   ClassDefFormat1       format1;
1215   ClassDefFormat2       format2;
1216   } u;
1217   public:
1218   DEFINE_SIZE_UNION (2, format);
1219 };
1220
1221
1222 /*
1223  * Item Variation Store
1224  */
1225
1226 struct VarRegionAxis
1227 {
1228   inline float evaluate (int coord) const
1229   {
1230     int start = startCoord, peak = peakCoord, end = endCoord;
1231
1232     /* TODO Move these to sanitize(). */
1233     if (unlikely (start > peak || peak > end))
1234       return 1.;
1235     if (unlikely (start < 0 && end > 0 && peak != 0))
1236       return 1.;
1237
1238     if (peak == 0 || coord == peak)
1239       return 1.;
1240
1241     if (coord <= start || end <= coord)
1242       return 0.;
1243
1244     /* Interpolate */
1245     if (coord < peak)
1246       return float (coord - start) / (peak - start);
1247     else
1248       return float (end - coord) / (end - peak);
1249   }
1250
1251   inline bool sanitize (hb_sanitize_context_t *c) const
1252   {
1253     TRACE_SANITIZE (this);
1254     return_trace (c->check_struct (this));
1255     /* TODO Handle invalid start/peak/end configs, so we don't
1256      * have to do that at runtime. */
1257   }
1258
1259   public:
1260   F2DOT14       startCoord;
1261   F2DOT14       peakCoord;
1262   F2DOT14       endCoord;
1263   public:
1264   DEFINE_SIZE_STATIC (6);
1265 };
1266
1267 struct VarRegionList
1268 {
1269   inline float evaluate (unsigned int region_index,
1270                          int *coords, unsigned int coord_len) const
1271   {
1272     if (unlikely (region_index >= regionCount))
1273       return 0.;
1274
1275     const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1276
1277     float v = 1.;
1278     unsigned int count = axisCount;
1279     for (unsigned int i = 0; i < count; i++)
1280     {
1281       int coord = i < coord_len ? coords[i] : 0;
1282       float factor = axes[i].evaluate (coord);
1283       if (factor == 0.f)
1284         return 0.;
1285       v *= factor;
1286     }
1287     return v;
1288   }
1289
1290   inline bool sanitize (hb_sanitize_context_t *c) const
1291   {
1292     TRACE_SANITIZE (this);
1293     return_trace (c->check_struct (this) &&
1294                   axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1295   }
1296
1297   protected:
1298   HBUINT16      axisCount;
1299   HBUINT16      regionCount;
1300   UnsizedArrayOf<VarRegionAxis>
1301                 axesZ;
1302   public:
1303   DEFINE_SIZE_ARRAY (4, axesZ);
1304 };
1305
1306 struct VarData
1307 {
1308   inline unsigned int get_row_size (void) const
1309   { return shortCount + regionIndices.len; }
1310
1311   inline unsigned int get_size (void) const
1312   { return itemCount * get_row_size (); }
1313
1314   inline float get_delta (unsigned int inner,
1315                           int *coords, unsigned int coord_count,
1316                           const VarRegionList &regions) const
1317   {
1318     if (unlikely (inner >= itemCount))
1319       return 0.;
1320
1321    unsigned int count = regionIndices.len;
1322    unsigned int scount = shortCount;
1323
1324    const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
1325    const HBUINT8 *row = bytes + inner * (scount + count);
1326
1327    float delta = 0.;
1328    unsigned int i = 0;
1329
1330    const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1331    for (; i < scount; i++)
1332    {
1333      float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1334      delta += scalar * *scursor++;
1335    }
1336    const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1337    for (; i < count; i++)
1338    {
1339      float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1340      delta += scalar * *bcursor++;
1341    }
1342
1343    return delta;
1344   }
1345
1346   inline bool sanitize (hb_sanitize_context_t *c) const
1347   {
1348     TRACE_SANITIZE (this);
1349     return_trace (c->check_struct (this) &&
1350                   regionIndices.sanitize(c) &&
1351                   shortCount <= regionIndices.len &&
1352                   c->check_array (&StructAfter<HBUINT8> (regionIndices),
1353                                   get_row_size (), itemCount));
1354   }
1355
1356   protected:
1357   HBUINT16              itemCount;
1358   HBUINT16              shortCount;
1359   ArrayOf<HBUINT16>     regionIndices;
1360   HBUINT8               bytesX[VAR];
1361   public:
1362   DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
1363 };
1364
1365 struct VariationStore
1366 {
1367   inline float get_delta (unsigned int outer, unsigned int inner,
1368                           int *coords, unsigned int coord_count) const
1369   {
1370     if (unlikely (outer >= dataSets.len))
1371       return 0.;
1372
1373     return (this+dataSets[outer]).get_delta (inner,
1374                                              coords, coord_count,
1375                                              this+regions);
1376   }
1377
1378   inline float get_delta (unsigned int index,
1379                           int *coords, unsigned int coord_count) const
1380   {
1381     unsigned int outer = index >> 16;
1382     unsigned int inner = index & 0xFFFF;
1383     return get_delta (outer, inner, coords, coord_count);
1384   }
1385
1386   inline bool sanitize (hb_sanitize_context_t *c) const
1387   {
1388     TRACE_SANITIZE (this);
1389     return_trace (c->check_struct (this) &&
1390                   format == 1 &&
1391                   regions.sanitize (c, this) &&
1392                   dataSets.sanitize (c, this));
1393   }
1394
1395   protected:
1396   HBUINT16                              format;
1397   LOffsetTo<VarRegionList>              regions;
1398   OffsetArrayOf<VarData, HBUINT32>      dataSets;
1399   public:
1400   DEFINE_SIZE_ARRAY (8, dataSets);
1401 };
1402
1403 /*
1404  * Feature Variations
1405  */
1406
1407 struct ConditionFormat1
1408 {
1409   friend struct Condition;
1410
1411   private:
1412   inline bool evaluate (const int *coords, unsigned int coord_len) const
1413   {
1414     int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
1415     return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
1416   }
1417
1418   inline bool sanitize (hb_sanitize_context_t *c) const
1419   {
1420     TRACE_SANITIZE (this);
1421     return_trace (c->check_struct (this));
1422   }
1423
1424   protected:
1425   HBUINT16      format;         /* Format identifier--format = 1 */
1426   HBUINT16      axisIndex;
1427   F2DOT14       filterRangeMinValue;
1428   F2DOT14       filterRangeMaxValue;
1429   public:
1430   DEFINE_SIZE_STATIC (8);
1431 };
1432
1433 struct Condition
1434 {
1435   inline bool evaluate (const int *coords, unsigned int coord_len) const
1436   {
1437     switch (u.format) {
1438     case 1: return u.format1.evaluate (coords, coord_len);
1439     default:return false;
1440     }
1441   }
1442
1443   inline bool sanitize (hb_sanitize_context_t *c) const
1444   {
1445     TRACE_SANITIZE (this);
1446     if (!u.format.sanitize (c)) return_trace (false);
1447     switch (u.format) {
1448     case 1: return_trace (u.format1.sanitize (c));
1449     default:return_trace (true);
1450     }
1451   }
1452
1453   protected:
1454   union {
1455   HBUINT16              format;         /* Format identifier */
1456   ConditionFormat1      format1;
1457   } u;
1458   public:
1459   DEFINE_SIZE_UNION (2, format);
1460 };
1461
1462 struct ConditionSet
1463 {
1464   inline bool evaluate (const int *coords, unsigned int coord_len) const
1465   {
1466     unsigned int count = conditions.len;
1467     for (unsigned int i = 0; i < count; i++)
1468       if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
1469         return false;
1470     return true;
1471   }
1472
1473   inline bool sanitize (hb_sanitize_context_t *c) const
1474   {
1475     TRACE_SANITIZE (this);
1476     return_trace (conditions.sanitize (c, this));
1477   }
1478
1479   protected:
1480   OffsetArrayOf<Condition, HBUINT32> conditions;
1481   public:
1482   DEFINE_SIZE_ARRAY (2, conditions);
1483 };
1484
1485 struct FeatureTableSubstitutionRecord
1486 {
1487   friend struct FeatureTableSubstitution;
1488
1489   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1490   {
1491     TRACE_SANITIZE (this);
1492     return_trace (c->check_struct (this) && feature.sanitize (c, base));
1493   }
1494
1495   protected:
1496   HBUINT16              featureIndex;
1497   LOffsetTo<Feature>    feature;
1498   public:
1499   DEFINE_SIZE_STATIC (6);
1500 };
1501
1502 struct FeatureTableSubstitution
1503 {
1504   inline const Feature *find_substitute (unsigned int feature_index) const
1505   {
1506     unsigned int count = substitutions.len;
1507     for (unsigned int i = 0; i < count; i++)
1508     {
1509       const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1510       if (record.featureIndex == feature_index)
1511         return &(this+record.feature);
1512     }
1513     return nullptr;
1514   }
1515
1516   inline bool sanitize (hb_sanitize_context_t *c) const
1517   {
1518     TRACE_SANITIZE (this);
1519     return_trace (version.sanitize (c) &&
1520                   likely (version.major == 1) &&
1521                   substitutions.sanitize (c, this));
1522   }
1523
1524   protected:
1525   FixedVersion<>        version;        /* Version--0x00010000u */
1526   ArrayOf<FeatureTableSubstitutionRecord>
1527                         substitutions;
1528   public:
1529   DEFINE_SIZE_ARRAY (6, substitutions);
1530 };
1531
1532 struct FeatureVariationRecord
1533 {
1534   friend struct FeatureVariations;
1535
1536   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1537   {
1538     TRACE_SANITIZE (this);
1539     return_trace (conditions.sanitize (c, base) &&
1540                   substitutions.sanitize (c, base));
1541   }
1542
1543   protected:
1544   LOffsetTo<ConditionSet>
1545                         conditions;
1546   LOffsetTo<FeatureTableSubstitution>
1547                         substitutions;
1548   public:
1549   DEFINE_SIZE_STATIC (8);
1550 };
1551
1552 struct FeatureVariations
1553 {
1554   static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
1555
1556   inline bool find_index (const int *coords, unsigned int coord_len,
1557                           unsigned int *index) const
1558   {
1559     unsigned int count = varRecords.len;
1560     for (unsigned int i = 0; i < count; i++)
1561     {
1562       const FeatureVariationRecord &record = varRecords.arrayZ[i];
1563       if ((this+record.conditions).evaluate (coords, coord_len))
1564       {
1565         *index = i;
1566         return true;
1567       }
1568     }
1569     *index = NOT_FOUND_INDEX;
1570     return false;
1571   }
1572
1573   inline const Feature *find_substitute (unsigned int variations_index,
1574                                          unsigned int feature_index) const
1575   {
1576     const FeatureVariationRecord &record = varRecords[variations_index];
1577     return (this+record.substitutions).find_substitute (feature_index);
1578   }
1579
1580   inline bool sanitize (hb_sanitize_context_t *c) const
1581   {
1582     TRACE_SANITIZE (this);
1583     return_trace (version.sanitize (c) &&
1584                   likely (version.major == 1) &&
1585                   varRecords.sanitize (c, this));
1586   }
1587
1588   protected:
1589   FixedVersion<>        version;        /* Version--0x00010000u */
1590   LArrayOf<FeatureVariationRecord>
1591                         varRecords;
1592   public:
1593   DEFINE_SIZE_ARRAY (8, varRecords);
1594 };
1595
1596
1597 /*
1598  * Device Tables
1599  */
1600
1601 struct HintingDevice
1602 {
1603   friend struct Device;
1604
1605   private:
1606
1607   inline hb_position_t get_x_delta (hb_font_t *font) const
1608   { return get_delta (font->x_ppem, font->x_scale); }
1609
1610   inline hb_position_t get_y_delta (hb_font_t *font) const
1611   { return get_delta (font->y_ppem, font->y_scale); }
1612
1613   inline unsigned int get_size (void) const
1614   {
1615     unsigned int f = deltaFormat;
1616     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size;
1617     return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
1618   }
1619
1620   inline bool sanitize (hb_sanitize_context_t *c) const
1621   {
1622     TRACE_SANITIZE (this);
1623     return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
1624   }
1625
1626   private:
1627
1628   inline int get_delta (unsigned int ppem, int scale) const
1629   {
1630     if (!ppem) return 0;
1631
1632     int pixels = get_delta_pixels (ppem);
1633
1634     if (!pixels) return 0;
1635
1636     return (int) (pixels * (int64_t) scale / ppem);
1637   }
1638   inline int get_delta_pixels (unsigned int ppem_size) const
1639   {
1640     unsigned int f = deltaFormat;
1641     if (unlikely (f < 1 || f > 3))
1642       return 0;
1643
1644     if (ppem_size < startSize || ppem_size > endSize)
1645       return 0;
1646
1647     unsigned int s = ppem_size - startSize;
1648
1649     unsigned int byte = deltaValue[s >> (4 - f)];
1650     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1651     unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1652
1653     int delta = bits & mask;
1654
1655     if ((unsigned int) delta >= ((mask + 1) >> 1))
1656       delta -= mask + 1;
1657
1658     return delta;
1659   }
1660
1661   protected:
1662   HBUINT16      startSize;              /* Smallest size to correct--in ppem */
1663   HBUINT16      endSize;                /* Largest size to correct--in ppem */
1664   HBUINT16      deltaFormat;            /* Format of DeltaValue array data: 1, 2, or 3
1665                                          * 1    Signed 2-bit value, 8 values per uint16
1666                                          * 2    Signed 4-bit value, 4 values per uint16
1667                                          * 3    Signed 8-bit value, 2 values per uint16
1668                                          */
1669   HBUINT16      deltaValue[VAR];        /* Array of compressed data */
1670   public:
1671   DEFINE_SIZE_ARRAY (6, deltaValue);
1672 };
1673
1674 struct VariationDevice
1675 {
1676   friend struct Device;
1677
1678   private:
1679
1680   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1681   { return font->em_scalef_x (get_delta (font, store)); }
1682
1683   inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1684   { return font->em_scalef_y (get_delta (font, store)); }
1685
1686   inline bool sanitize (hb_sanitize_context_t *c) const
1687   {
1688     TRACE_SANITIZE (this);
1689     return_trace (c->check_struct (this));
1690   }
1691
1692   private:
1693
1694   inline float get_delta (hb_font_t *font, const VariationStore &store) const
1695   {
1696     return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1697   }
1698
1699   protected:
1700   HBUINT16      outerIndex;
1701   HBUINT16      innerIndex;
1702   HBUINT16      deltaFormat;    /* Format identifier for this table: 0x0x8000 */
1703   public:
1704   DEFINE_SIZE_STATIC (6);
1705 };
1706
1707 struct DeviceHeader
1708 {
1709   protected:
1710   HBUINT16              reserved1;
1711   HBUINT16              reserved2;
1712   public:
1713   HBUINT16              format;         /* Format identifier */
1714   public:
1715   DEFINE_SIZE_STATIC (6);
1716 };
1717
1718 struct Device
1719 {
1720   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1721   {
1722     switch (u.b.format)
1723     {
1724     case 1: case 2: case 3:
1725       return u.hinting.get_x_delta (font);
1726     case 0x8000:
1727       return u.variation.get_x_delta (font, store);
1728     default:
1729       return 0;
1730     }
1731   }
1732   inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1733   {
1734     switch (u.b.format)
1735     {
1736     case 1: case 2: case 3:
1737       return u.hinting.get_y_delta (font);
1738     case 0x8000:
1739       return u.variation.get_y_delta (font, store);
1740     default:
1741       return 0;
1742     }
1743   }
1744
1745   inline bool sanitize (hb_sanitize_context_t *c) const
1746   {
1747     TRACE_SANITIZE (this);
1748     if (!u.b.format.sanitize (c)) return_trace (false);
1749     switch (u.b.format) {
1750     case 1: case 2: case 3:
1751       return_trace (u.hinting.sanitize (c));
1752     case 0x8000:
1753       return_trace (u.variation.sanitize (c));
1754     default:
1755       return_trace (true);
1756     }
1757   }
1758
1759   protected:
1760   union {
1761   DeviceHeader          b;
1762   HintingDevice         hinting;
1763   VariationDevice       variation;
1764   } u;
1765   public:
1766   DEFINE_SIZE_UNION (6, b);
1767 };
1768
1769
1770 } /* namespace OT */
1771
1772
1773 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */