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