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