LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-layout-common-private.hh (source / functions) Hit Total Coverage
Test: output.info Lines: 227 584 38.9 %
Date: 2017-07-14 16:53:18 Functions: 83 143 58.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13