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