Home | History | Annotate | Download | only in src
      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 namespace OT {
     38 
     39 
     40 #define NOT_COVERED		((unsigned int) -1)
     41 #define MAX_NESTING_LEVEL	8
     42 #define MAX_CONTEXT_LENGTH	64
     43 
     44 
     45 
     46 /*
     47  *
     48  * OpenType Layout Common Table Formats
     49  *
     50  */
     51 
     52 
     53 /*
     54  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
     55  */
     56 
     57 template <typename Type>
     58 struct Record
     59 {
     60   inline int cmp (hb_tag_t a) const {
     61     return tag.cmp (a);
     62   }
     63 
     64   struct sanitize_closure_t {
     65     hb_tag_t tag;
     66     void *list_base;
     67   };
     68   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
     69     TRACE_SANITIZE (this);
     70     const sanitize_closure_t closure = {tag, base};
     71     return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
     72   }
     73 
     74   Tag		tag;		/* 4-byte Tag identifier */
     75   OffsetTo<Type>
     76 		offset;		/* Offset from beginning of object holding
     77 				 * the Record */
     78   public:
     79   DEFINE_SIZE_STATIC (6);
     80 };
     81 
     82 template <typename Type>
     83 struct RecordArrayOf : SortedArrayOf<Record<Type> > {
     84   inline const Tag& get_tag (unsigned int i) const
     85   {
     86     /* We cheat slightly and don't define separate Null objects
     87      * for Record types.  Instead, we return the correct Null(Tag)
     88      * here. */
     89     if (unlikely (i >= this->len)) return Null(Tag);
     90     return (*this)[i].tag;
     91   }
     92   inline unsigned int get_tags (unsigned int start_offset,
     93 				unsigned int *record_count /* IN/OUT */,
     94 				hb_tag_t     *record_tags /* OUT */) const
     95   {
     96     if (record_count) {
     97       const Record<Type> *arr = this->sub_array (start_offset, record_count);
     98       unsigned int count = *record_count;
     99       for (unsigned int i = 0; i < count; i++)
    100 	record_tags[i] = arr[i].tag;
    101     }
    102     return this->len;
    103   }
    104   inline bool find_index (hb_tag_t tag, unsigned int *index) const
    105   {
    106     int i = this->search (tag);
    107     if (i != -1) {
    108         if (index) *index = i;
    109         return true;
    110     } else {
    111       if (index) *index = Index::NOT_FOUND_INDEX;
    112       return false;
    113     }
    114   }
    115 };
    116 
    117 template <typename Type>
    118 struct RecordListOf : RecordArrayOf<Type>
    119 {
    120   inline const Type& operator [] (unsigned int i) const
    121   { return this+RecordArrayOf<Type>::operator [](i).offset; }
    122 
    123   inline bool sanitize (hb_sanitize_context_t *c) {
    124     TRACE_SANITIZE (this);
    125     return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
    126   }
    127 };
    128 
    129 
    130 struct RangeRecord
    131 {
    132   inline int cmp (hb_codepoint_t g) const {
    133     return g < start ? -1 : g <= end ? 0 : +1 ;
    134   }
    135 
    136   inline bool sanitize (hb_sanitize_context_t *c) {
    137     TRACE_SANITIZE (this);
    138     return TRACE_RETURN (c->check_struct (this));
    139   }
    140 
    141   inline bool intersects (const hb_set_t *glyphs) const {
    142     return glyphs->intersects (start, end);
    143   }
    144 
    145   template <typename set_t>
    146   inline void add_coverage (set_t *glyphs) const {
    147     glyphs->add_range (start, end);
    148   }
    149 
    150   GlyphID	start;		/* First GlyphID in the range */
    151   GlyphID	end;		/* Last GlyphID in the range */
    152   USHORT	value;		/* Value */
    153   public:
    154   DEFINE_SIZE_STATIC (6);
    155 };
    156 DEFINE_NULL_DATA (RangeRecord, "\000\001");
    157 
    158 
    159 struct IndexArray : ArrayOf<Index>
    160 {
    161   inline unsigned int get_indexes (unsigned int start_offset,
    162 				   unsigned int *_count /* IN/OUT */,
    163 				   unsigned int *_indexes /* OUT */) const
    164   {
    165     if (_count) {
    166       const USHORT *arr = this->sub_array (start_offset, _count);
    167       unsigned int count = *_count;
    168       for (unsigned int i = 0; i < count; i++)
    169 	_indexes[i] = arr[i];
    170     }
    171     return this->len;
    172   }
    173 };
    174 
    175 
    176 struct Script;
    177 struct LangSys;
    178 struct Feature;
    179 
    180 
    181 struct LangSys
    182 {
    183   inline unsigned int get_feature_count (void) const
    184   { return featureIndex.len; }
    185   inline hb_tag_t get_feature_index (unsigned int i) const
    186   { return featureIndex[i]; }
    187   inline unsigned int get_feature_indexes (unsigned int start_offset,
    188 					   unsigned int *feature_count /* IN/OUT */,
    189 					   unsigned int *feature_indexes /* OUT */) const
    190   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
    191 
    192   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
    193   inline unsigned int get_required_feature_index (void) const
    194   {
    195     if (reqFeatureIndex == 0xffff)
    196       return Index::NOT_FOUND_INDEX;
    197    return reqFeatureIndex;;
    198   }
    199 
    200   inline bool sanitize (hb_sanitize_context_t *c,
    201 			const Record<LangSys>::sanitize_closure_t * = NULL) {
    202     TRACE_SANITIZE (this);
    203     return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
    204   }
    205 
    206   Offset	lookupOrder;	/* = Null (reserved for an offset to a
    207 				 * reordering table) */
    208   USHORT	reqFeatureIndex;/* Index of a feature required for this
    209 				 * language system--if no required features
    210 				 * = 0xFFFF */
    211   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
    212   public:
    213   DEFINE_SIZE_ARRAY (6, featureIndex);
    214 };
    215 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
    216 
    217 
    218 struct Script
    219 {
    220   inline unsigned int get_lang_sys_count (void) const
    221   { return langSys.len; }
    222   inline const Tag& get_lang_sys_tag (unsigned int i) const
    223   { return langSys.get_tag (i); }
    224   inline unsigned int get_lang_sys_tags (unsigned int start_offset,
    225 					 unsigned int *lang_sys_count /* IN/OUT */,
    226 					 hb_tag_t     *lang_sys_tags /* OUT */) const
    227   { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
    228   inline const LangSys& get_lang_sys (unsigned int i) const
    229   {
    230     if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
    231     return this+langSys[i].offset;
    232   }
    233   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
    234   { return langSys.find_index (tag, index); }
    235 
    236   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
    237   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
    238 
    239   inline bool sanitize (hb_sanitize_context_t *c,
    240 			const Record<Script>::sanitize_closure_t * = NULL) {
    241     TRACE_SANITIZE (this);
    242     return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
    243   }
    244 
    245   protected:
    246   OffsetTo<LangSys>
    247 		defaultLangSys;	/* Offset to DefaultLangSys table--from
    248 				 * beginning of Script table--may be Null */
    249   RecordArrayOf<LangSys>
    250 		langSys;	/* Array of LangSysRecords--listed
    251 				 * alphabetically by LangSysTag */
    252   public:
    253   DEFINE_SIZE_ARRAY (4, langSys);
    254 };
    255 
    256 typedef RecordListOf<Script> ScriptList;
    257 
    258 
    259 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
    260 struct FeatureParamsSize
    261 {
    262   inline bool sanitize (hb_sanitize_context_t *c) {
    263     TRACE_SANITIZE (this);
    264     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
    265 
    266     /* This subtable has some "history", if you will.  Some earlier versions of
    267      * Adobe tools calculated the offset of the FeatureParams sutable from the
    268      * beginning of the FeatureList table!  Now, that is dealt with in the
    269      * Feature implementation.  But we still need to be able to tell junk from
    270      * real data.  Note: We don't check that the nameID actually exists.
    271      *
    272      * Read Roberts wrote on 9/15/06 on opentype-list (at) indx.co.uk :
    273      *
    274      * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
    275      * coming out soon, and that the makeotf program will build a font with a
    276      * 'size' feature that is correct by the specification.
    277      *
    278      * The specification for this feature tag is in the "OpenType Layout Tag
    279      * Registry". You can see a copy of this at:
    280      * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
    281      *
    282      * Here is one set of rules to determine if the 'size' feature is built
    283      * correctly, or as by the older versions of MakeOTF. You may be able to do
    284      * better.
    285      *
    286      * Assume that the offset to the size feature is according to specification,
    287      * and make the following value checks. If it fails, assume the the size
    288      * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
    289      * If this fails, reject the 'size' feature. The older makeOTF's calculated the
    290      * offset from the beginning of the FeatureList table, rather than from the
    291      * beginning of the 'size' Feature table.
    292      *
    293      * If "design size" == 0:
    294      *     fails check
    295      *
    296      * Else if ("subfamily identifier" == 0 and
    297      *     "range start" == 0 and
    298      *     "range end" == 0 and
    299      *     "range start" == 0 and
    300      *     "menu name ID" == 0)
    301      *     passes check: this is the format used when there is a design size
    302      * specified, but there is no recommended size range.
    303      *
    304      * Else if ("design size" <  "range start" or
    305      *     "design size" >   "range end" or
    306      *     "range end" <= "range start" or
    307      *     "menu name ID"  < 256 or
    308      *     "menu name ID"  > 32767 or
    309      *     menu name ID is not a name ID which is actually in the name table)
    310      *     fails test
    311      * Else
    312      *     passes test.
    313      */
    314 
    315     if (!designSize)
    316       return TRACE_RETURN (false);
    317     else if (subfamilyID == 0 &&
    318 	     subfamilyNameID == 0 &&
    319 	     rangeStart == 0 &&
    320 	     rangeEnd == 0)
    321       return TRACE_RETURN (true);
    322     else if (designSize < rangeStart ||
    323 	     designSize > rangeEnd ||
    324 	     subfamilyNameID < 256 ||
    325 	     subfamilyNameID > 32767)
    326       return TRACE_RETURN (false);
    327     else
    328       return TRACE_RETURN (true);
    329   }
    330 
    331   USHORT	designSize;	/* Represents the design size in 720/inch
    332 				 * units (decipoints).  The design size entry
    333 				 * must be non-zero.  When there is a design
    334 				 * size but no recommended size range, the
    335 				 * rest of the array will consist of zeros. */
    336   USHORT	subfamilyID;	/* Has no independent meaning, but serves
    337 				 * as an identifier that associates fonts
    338 				 * in a subfamily. All fonts which share a
    339 				 * Preferred or Font Family name and which
    340 				 * differ only by size range shall have the
    341 				 * same subfamily value, and no fonts which
    342 				 * differ in weight or style shall have the
    343 				 * same subfamily value. If this value is
    344 				 * zero, the remaining fields in the array
    345 				 * will be ignored. */
    346   USHORT	subfamilyNameID;/* If the preceding value is non-zero, this
    347 				 * value must be set in the range 256 - 32767
    348 				 * (inclusive). It records the value of a
    349 				 * field in the name table, which must
    350 				 * contain English-language strings encoded
    351 				 * in Windows Unicode and Macintosh Roman,
    352 				 * and may contain additional strings
    353 				 * localized to other scripts and languages.
    354 				 * Each of these strings is the name an
    355 				 * application should use, in combination
    356 				 * with the family name, to represent the
    357 				 * subfamily in a menu.  Applications will
    358 				 * choose the appropriate version based on
    359 				 * their selection criteria. */
    360   USHORT	rangeStart;	/* Large end of the recommended usage range
    361 				 * (inclusive), stored in 720/inch units
    362 				 * (decipoints). */
    363   USHORT	rangeEnd;	/* Small end of the recommended usage range
    364 				   (exclusive), stored in 720/inch units
    365 				 * (decipoints). */
    366   public:
    367   DEFINE_SIZE_STATIC (10);
    368 };
    369 
    370 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
    371 struct FeatureParamsStylisticSet
    372 {
    373   inline bool sanitize (hb_sanitize_context_t *c) {
    374     TRACE_SANITIZE (this);
    375     /* Right now minorVersion is at zero.  Which means, any table supports
    376      * the uiNameID field. */
    377     return TRACE_RETURN (c->check_struct (this));
    378   }
    379 
    380   USHORT	version;	/* (set to 0): This corresponds to a minor
    381 				 * version number. Additional data may be
    382 				 * added to the end of this Feature Parameters
    383 				 * table in the future. */
    384 
    385   USHORT	uiNameID;	/* The 'name' table name ID that specifies a
    386 				 * string (or strings, for multiple languages)
    387 				 * for a user-interface label for this
    388 				 * feature.  The values of uiLabelNameId and
    389 				 * sampleTextNameId are expected to be in the
    390 				 * font-specific name ID range (256-32767),
    391 				 * though that is not a requirement in this
    392 				 * Feature Parameters specification. The
    393 				 * user-interface label for the feature can
    394 				 * be provided in multiple languages. An
    395 				 * English string should be included as a
    396 				 * fallback. The string should be kept to a
    397 				 * minimal length to fit comfortably with
    398 				 * different application interfaces. */
    399   public:
    400   DEFINE_SIZE_STATIC (4);
    401 };
    402 
    403 /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
    404 struct FeatureParamsCharacterVariants
    405 {
    406   inline bool sanitize (hb_sanitize_context_t *c) {
    407     TRACE_SANITIZE (this);
    408     return TRACE_RETURN (c->check_struct (this) &&
    409 			 characters.sanitize (c));
    410   }
    411 
    412   USHORT	format;			/* Format number is set to 0. */
    413   USHORT	featUILableNameID;	/* The name table name ID that
    414 					 * specifies a string (or strings,
    415 					 * for multiple languages) for a
    416 					 * user-interface label for this
    417 					 * feature. (May be NULL.) */
    418   USHORT	featUITooltipTextNameID;/* The name table name ID that
    419 					 * specifies a string (or strings,
    420 					 * for multiple languages) that an
    421 					 * application can use for tooltip
    422 					 * text for this feature. (May be
    423 					 * NULL.) */
    424   USHORT	sampleTextNameID;	/* The name table name ID that
    425 					 * specifies sample text that
    426 					 * illustrates the effect of this
    427 					 * feature. (May be NULL.) */
    428   USHORT	numNamedParameters;	/* Number of named parameters. (May
    429 					 * be zero.) */
    430   USHORT	firstParamUILabelNameID;/* The first name table name ID
    431 					 * used to specify strings for
    432 					 * user-interface labels for the
    433 					 * feature parameters. (Must be zero
    434 					 * if numParameters is zero.) */
    435   ArrayOf<UINT24>
    436 		characters;		/* Array of the Unicode Scalar Value
    437 					 * of the characters for which this
    438 					 * feature provides glyph variants.
    439 					 * (May be zero.) */
    440   public:
    441   DEFINE_SIZE_ARRAY (14, characters);
    442 };
    443 
    444 struct FeatureParams
    445 {
    446   inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
    447     TRACE_SANITIZE (this);
    448     if (tag == HB_TAG ('s','i','z','e'))
    449       return TRACE_RETURN (u.size.sanitize (c));
    450     if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */
    451       return TRACE_RETURN (u.stylisticSet.sanitize (c));
    452     if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */
    453       return TRACE_RETURN (u.characterVariants.sanitize (c));
    454     return TRACE_RETURN (true);
    455   }
    456 
    457   inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
    458   {
    459     if (tag == HB_TAG ('s','i','z','e'))
    460       return u.size;
    461     return Null(FeatureParamsSize);
    462   }
    463 
    464   private:
    465   union {
    466   FeatureParamsSize			size;
    467   FeatureParamsStylisticSet		stylisticSet;
    468   FeatureParamsCharacterVariants	characterVariants;
    469   } u;
    470   DEFINE_SIZE_STATIC (17);
    471 };
    472 
    473 struct Feature
    474 {
    475   inline unsigned int get_lookup_count (void) const
    476   { return lookupIndex.len; }
    477   inline hb_tag_t get_lookup_index (unsigned int i) const
    478   { return lookupIndex[i]; }
    479   inline unsigned int get_lookup_indexes (unsigned int start_index,
    480 					  unsigned int *lookup_count /* IN/OUT */,
    481 					  unsigned int *lookup_tags /* OUT */) const
    482   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
    483 
    484   inline const FeatureParams &get_feature_params (void) const
    485   { return this+featureParams; }
    486 
    487   inline bool sanitize (hb_sanitize_context_t *c,
    488 			const Record<Feature>::sanitize_closure_t *closure) {
    489     TRACE_SANITIZE (this);
    490     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
    491       return TRACE_RETURN (false);
    492 
    493     /* Some earlier versions of Adobe tools calculated the offset of the
    494      * FeatureParams subtable from the beginning of the FeatureList table!
    495      *
    496      * If sanitizing "failed" for the FeatureParams subtable, try it with the
    497      * alternative location.  We would know sanitize "failed" if old value
    498      * of the offset was non-zero, but it's zeroed now.
    499      *
    500      * Only do this for the 'size' feature, since at the time of the faulty
    501      * Adobe tools, only the 'size' feature had FeatureParams defined.
    502      */
    503 
    504     Offset orig_offset = featureParams;
    505     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
    506       return TRACE_RETURN (false);
    507 
    508     if (likely (!orig_offset))
    509       return TRACE_RETURN (true);
    510 
    511     if (featureParams == 0 && closure &&
    512 	closure->tag == HB_TAG ('s','i','z','e') &&
    513 	closure->list_base && closure->list_base < this)
    514     {
    515       unsigned int new_offset_int = (unsigned int) orig_offset -
    516 				    ((char *) this - (char *) closure->list_base);
    517 
    518       Offset new_offset;
    519       /* Check that it did not overflow. */
    520       new_offset.set (new_offset_int);
    521       if (new_offset == new_offset_int &&
    522 	  featureParams.try_set (c, new_offset) &&
    523 	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
    524 	return TRACE_RETURN (false);
    525     }
    526 
    527     return TRACE_RETURN (true);
    528   }
    529 
    530   OffsetTo<FeatureParams>
    531 		 featureParams;	/* Offset to Feature Parameters table (if one
    532 				 * has been defined for the feature), relative
    533 				 * to the beginning of the Feature Table; = Null
    534 				 * if not required */
    535   IndexArray	 lookupIndex;	/* Array of LookupList indices */
    536   public:
    537   DEFINE_SIZE_ARRAY (4, lookupIndex);
    538 };
    539 
    540 typedef RecordListOf<Feature> FeatureList;
    541 
    542 
    543 struct LookupFlag : USHORT
    544 {
    545   enum Flags {
    546     RightToLeft		= 0x0001u,
    547     IgnoreBaseGlyphs	= 0x0002u,
    548     IgnoreLigatures	= 0x0004u,
    549     IgnoreMarks		= 0x0008u,
    550     IgnoreFlags		= 0x000Eu,
    551     UseMarkFilteringSet	= 0x0010u,
    552     Reserved		= 0x00E0u,
    553     MarkAttachmentType	= 0xFF00u
    554   };
    555   public:
    556   DEFINE_SIZE_STATIC (2);
    557 };
    558 
    559 struct Lookup
    560 {
    561   inline unsigned int get_subtable_count (void) const { return subTable.len; }
    562 
    563   inline unsigned int get_type (void) const { return lookupType; }
    564 
    565   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
    566    * higher 16-bit is mark-filtering-set if the lookup uses one.
    567    * Not to be confused with glyph_props which is very similar. */
    568   inline uint32_t get_props (void) const
    569   {
    570     unsigned int flag = lookupFlag;
    571     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
    572     {
    573       const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
    574       flag += (markFilteringSet << 16);
    575     }
    576     return flag;
    577   }
    578 
    579   inline bool serialize (hb_serialize_context_t *c,
    580 			 unsigned int lookup_type,
    581 			 uint32_t lookup_props,
    582 			 unsigned int num_subtables)
    583   {
    584     TRACE_SERIALIZE (this);
    585     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    586     lookupType.set (lookup_type);
    587     lookupFlag.set (lookup_props & 0xFFFF);
    588     if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
    589     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
    590     {
    591       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
    592       markFilteringSet.set (lookup_props >> 16);
    593     }
    594     return TRACE_RETURN (true);
    595   }
    596 
    597   inline bool sanitize (hb_sanitize_context_t *c) {
    598     TRACE_SANITIZE (this);
    599     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
    600     if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
    601     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
    602     {
    603       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
    604       if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
    605     }
    606     return TRACE_RETURN (true);
    607   }
    608 
    609   USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
    610   USHORT	lookupFlag;		/* Lookup qualifiers */
    611   ArrayOf<Offset>
    612 		subTable;		/* Array of SubTables */
    613   USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
    614 					 * structure. This field is only present if bit
    615 					 * UseMarkFilteringSet of lookup flags is set. */
    616   public:
    617   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
    618 };
    619 
    620 typedef OffsetListOf<Lookup> LookupList;
    621 
    622 
    623 /*
    624  * Coverage Table
    625  */
    626 
    627 struct CoverageFormat1
    628 {
    629   friend struct Coverage;
    630 
    631   private:
    632   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
    633   {
    634     int i = glyphArray.search (glyph_id);
    635     ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
    636     return i;
    637   }
    638 
    639   inline bool serialize (hb_serialize_context_t *c,
    640 			 Supplier<GlyphID> &glyphs,
    641 			 unsigned int num_glyphs)
    642   {
    643     TRACE_SERIALIZE (this);
    644     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    645     glyphArray.len.set (num_glyphs);
    646     if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
    647     for (unsigned int i = 0; i < num_glyphs; i++)
    648       glyphArray[i] = glyphs[i];
    649     glyphs.advance (num_glyphs);
    650     return TRACE_RETURN (true);
    651   }
    652 
    653   inline bool sanitize (hb_sanitize_context_t *c) {
    654     TRACE_SANITIZE (this);
    655     return TRACE_RETURN (glyphArray.sanitize (c));
    656   }
    657 
    658   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
    659     return glyphs->has (glyphArray[index]);
    660   }
    661 
    662   template <typename set_t>
    663   inline void add_coverage (set_t *glyphs) const {
    664     unsigned int count = glyphArray.len;
    665     for (unsigned int i = 0; i < count; i++)
    666       glyphs->add (glyphArray[i]);
    667   }
    668 
    669   public:
    670   /* Older compilers need this to be public. */
    671   struct Iter {
    672     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
    673     inline bool more (void) { return i < c->glyphArray.len; }
    674     inline void next (void) { i++; }
    675     inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
    676     inline uint16_t get_coverage (void) { return i; }
    677 
    678     private:
    679     const struct CoverageFormat1 *c;
    680     unsigned int i;
    681   };
    682   private:
    683 
    684   protected:
    685   USHORT	coverageFormat;	/* Format identifier--format = 1 */
    686   SortedArrayOf<GlyphID>
    687 		glyphArray;	/* Array of GlyphIDs--in numerical order */
    688   public:
    689   DEFINE_SIZE_ARRAY (4, glyphArray);
    690 };
    691 
    692 struct CoverageFormat2
    693 {
    694   friend struct Coverage;
    695 
    696   private:
    697   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
    698   {
    699     int i = rangeRecord.search (glyph_id);
    700     if (i != -1) {
    701       const RangeRecord &range = rangeRecord[i];
    702       return (unsigned int) range.value + (glyph_id - range.start);
    703     }
    704     return NOT_COVERED;
    705   }
    706 
    707   inline bool serialize (hb_serialize_context_t *c,
    708 			 Supplier<GlyphID> &glyphs,
    709 			 unsigned int num_glyphs)
    710   {
    711     TRACE_SERIALIZE (this);
    712     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    713 
    714     if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
    715 
    716     unsigned int num_ranges = 1;
    717     for (unsigned int i = 1; i < num_glyphs; i++)
    718       if (glyphs[i - 1] + 1 != glyphs[i])
    719         num_ranges++;
    720     rangeRecord.len.set (num_ranges);
    721     if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
    722 
    723     unsigned int range = 0;
    724     rangeRecord[range].start = glyphs[0];
    725     rangeRecord[range].value.set (0);
    726     for (unsigned int i = 1; i < num_glyphs; i++)
    727       if (glyphs[i - 1] + 1 != glyphs[i]) {
    728 	range++;
    729 	rangeRecord[range].start = glyphs[i];
    730 	rangeRecord[range].value.set (i);
    731         rangeRecord[range].end = glyphs[i];
    732       } else {
    733         rangeRecord[range].end = glyphs[i];
    734       }
    735     glyphs.advance (num_glyphs);
    736     return TRACE_RETURN (true);
    737   }
    738 
    739   inline bool sanitize (hb_sanitize_context_t *c) {
    740     TRACE_SANITIZE (this);
    741     return TRACE_RETURN (rangeRecord.sanitize (c));
    742   }
    743 
    744   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
    745     unsigned int i;
    746     unsigned int count = rangeRecord.len;
    747     for (i = 0; i < count; i++) {
    748       const RangeRecord &range = rangeRecord[i];
    749       if (range.value <= index &&
    750 	  index < (unsigned int) range.value + (range.end - range.start) &&
    751 	  range.intersects (glyphs))
    752         return true;
    753       else if (index < range.value)
    754         return false;
    755     }
    756     return false;
    757   }
    758 
    759   template <typename set_t>
    760   inline void add_coverage (set_t *glyphs) const {
    761     unsigned int count = rangeRecord.len;
    762     for (unsigned int i = 0; i < count; i++)
    763       rangeRecord[i].add_coverage (glyphs);
    764   }
    765 
    766   public:
    767   /* Older compilers need this to be public. */
    768   struct Iter {
    769     inline void init (const CoverageFormat2 &c_) {
    770       c = &c_;
    771       coverage = 0;
    772       i = 0;
    773       j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
    774     }
    775     inline bool more (void) { return i < c->rangeRecord.len; }
    776     inline void next (void) {
    777       coverage++;
    778       if (j == c->rangeRecord[i].end) {
    779         i++;
    780 	if (more ())
    781 	  j = c->rangeRecord[i].start;
    782 	return;
    783       }
    784       j++;
    785     }
    786     inline uint16_t get_glyph (void) { return j; }
    787     inline uint16_t get_coverage (void) { return coverage; }
    788 
    789     private:
    790     const struct CoverageFormat2 *c;
    791     unsigned int i, j, coverage;
    792   };
    793   private:
    794 
    795   protected:
    796   USHORT	coverageFormat;	/* Format identifier--format = 2 */
    797   SortedArrayOf<RangeRecord>
    798 		rangeRecord;	/* Array of glyph ranges--ordered by
    799 				 * Start GlyphID. rangeCount entries
    800 				 * long */
    801   public:
    802   DEFINE_SIZE_ARRAY (4, rangeRecord);
    803 };
    804 
    805 struct Coverage
    806 {
    807   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
    808   {
    809     switch (u.format) {
    810     case 1: return u.format1.get_coverage(glyph_id);
    811     case 2: return u.format2.get_coverage(glyph_id);
    812     default:return NOT_COVERED;
    813     }
    814   }
    815 
    816   inline bool serialize (hb_serialize_context_t *c,
    817 			 Supplier<GlyphID> &glyphs,
    818 			 unsigned int num_glyphs)
    819   {
    820     TRACE_SERIALIZE (this);
    821     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    822     unsigned int num_ranges = 1;
    823     for (unsigned int i = 1; i < num_glyphs; i++)
    824       if (glyphs[i - 1] + 1 != glyphs[i])
    825         num_ranges++;
    826     u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
    827     switch (u.format) {
    828     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
    829     case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
    830     default:return TRACE_RETURN (false);
    831     }
    832   }
    833 
    834   inline bool sanitize (hb_sanitize_context_t *c) {
    835     TRACE_SANITIZE (this);
    836     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
    837     switch (u.format) {
    838     case 1: return TRACE_RETURN (u.format1.sanitize (c));
    839     case 2: return TRACE_RETURN (u.format2.sanitize (c));
    840     default:return TRACE_RETURN (true);
    841     }
    842   }
    843 
    844   inline bool intersects (const hb_set_t *glyphs) const {
    845     /* TODO speed this up */
    846     Coverage::Iter iter;
    847     for (iter.init (*this); iter.more (); iter.next ()) {
    848       if (glyphs->has (iter.get_glyph ()))
    849         return true;
    850     }
    851     return false;
    852   }
    853 
    854   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
    855     switch (u.format) {
    856     case 1: return u.format1.intersects_coverage (glyphs, index);
    857     case 2: return u.format2.intersects_coverage (glyphs, index);
    858     default:return false;
    859     }
    860   }
    861 
    862   template <typename set_t>
    863   inline void add_coverage (set_t *glyphs) const {
    864     switch (u.format) {
    865     case 1: u.format1.add_coverage (glyphs); break;
    866     case 2: u.format2.add_coverage (glyphs); break;
    867     default:                                 break;
    868     }
    869   }
    870 
    871   struct Iter {
    872     Iter (void) : format (0) {};
    873     inline void init (const Coverage &c_) {
    874       format = c_.u.format;
    875       switch (format) {
    876       case 1: u.format1.init (c_.u.format1); return;
    877       case 2: u.format2.init (c_.u.format2); return;
    878       default:                               return;
    879       }
    880     }
    881     inline bool more (void) {
    882       switch (format) {
    883       case 1: return u.format1.more ();
    884       case 2: return u.format2.more ();
    885       default:return false;
    886       }
    887     }
    888     inline void next (void) {
    889       switch (format) {
    890       case 1: u.format1.next (); break;
    891       case 2: u.format2.next (); break;
    892       default:                   break;
    893       }
    894     }
    895     inline uint16_t get_glyph (void) {
    896       switch (format) {
    897       case 1: return u.format1.get_glyph ();
    898       case 2: return u.format2.get_glyph ();
    899       default:return 0;
    900       }
    901     }
    902     inline uint16_t get_coverage (void) {
    903       switch (format) {
    904       case 1: return u.format1.get_coverage ();
    905       case 2: return u.format2.get_coverage ();
    906       default:return -1;
    907       }
    908     }
    909 
    910     private:
    911     unsigned int format;
    912     union {
    913     CoverageFormat1::Iter	format1;
    914     CoverageFormat2::Iter	format2;
    915     } u;
    916   };
    917 
    918   protected:
    919   union {
    920   USHORT		format;		/* Format identifier */
    921   CoverageFormat1	format1;
    922   CoverageFormat2	format2;
    923   } u;
    924   public:
    925   DEFINE_SIZE_UNION (2, format);
    926 };
    927 
    928 
    929 /*
    930  * Class Definition Table
    931  */
    932 
    933 struct ClassDefFormat1
    934 {
    935   friend struct ClassDef;
    936 
    937   private:
    938   inline unsigned int get_class (hb_codepoint_t glyph_id) const
    939   {
    940     if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
    941       return classValue[glyph_id - startGlyph];
    942     return 0;
    943   }
    944 
    945   inline bool sanitize (hb_sanitize_context_t *c) {
    946     TRACE_SANITIZE (this);
    947     return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
    948   }
    949 
    950   template <typename set_t>
    951   inline void add_class (set_t *glyphs, unsigned int klass) const {
    952     unsigned int count = classValue.len;
    953     for (unsigned int i = 0; i < count; i++)
    954       if (classValue[i] == klass)
    955         glyphs->add (startGlyph + i);
    956   }
    957 
    958   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
    959     unsigned int count = classValue.len;
    960     if (klass == 0)
    961     {
    962       /* Match if there's any glyph that is not listed! */
    963       hb_codepoint_t g = -1;
    964       if (!hb_set_next (glyphs, &g))
    965         return false;
    966       if (g < startGlyph)
    967         return true;
    968       g = startGlyph + count - 1;
    969       if (hb_set_next (glyphs, &g))
    970         return true;
    971       /* Fall through. */
    972     }
    973     for (unsigned int i = 0; i < count; i++)
    974       if (classValue[i] == klass && glyphs->has (startGlyph + i))
    975         return true;
    976     return false;
    977   }
    978 
    979   protected:
    980   USHORT	classFormat;		/* Format identifier--format = 1 */
    981   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
    982   ArrayOf<USHORT>
    983 		classValue;		/* Array of Class Values--one per GlyphID */
    984   public:
    985   DEFINE_SIZE_ARRAY (6, classValue);
    986 };
    987 
    988 struct ClassDefFormat2
    989 {
    990   friend struct ClassDef;
    991 
    992   private:
    993   inline unsigned int get_class (hb_codepoint_t glyph_id) const
    994   {
    995     int i = rangeRecord.search (glyph_id);
    996     if (i != -1)
    997       return rangeRecord[i].value;
    998     return 0;
    999   }
   1000 
   1001   inline bool sanitize (hb_sanitize_context_t *c) {
   1002     TRACE_SANITIZE (this);
   1003     return TRACE_RETURN (rangeRecord.sanitize (c));
   1004   }
   1005 
   1006   template <typename set_t>
   1007   inline void add_class (set_t *glyphs, unsigned int klass) const {
   1008     unsigned int count = rangeRecord.len;
   1009     for (unsigned int i = 0; i < count; i++)
   1010       if (rangeRecord[i].value == klass)
   1011         rangeRecord[i].add_coverage (glyphs);
   1012   }
   1013 
   1014   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
   1015     unsigned int count = rangeRecord.len;
   1016     if (klass == 0)
   1017     {
   1018       /* Match if there's any glyph that is not listed! */
   1019       hb_codepoint_t g = (hb_codepoint_t) -1;
   1020       for (unsigned int i = 0; i < count; i++)
   1021       {
   1022 	if (!hb_set_next (glyphs, &g))
   1023 	  break;
   1024 	if (g < rangeRecord[i].start)
   1025 	  return true;
   1026 	g = rangeRecord[i].end;
   1027       }
   1028       if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
   1029         return true;
   1030       /* Fall through. */
   1031     }
   1032     for (unsigned int i = 0; i < count; i++)
   1033       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
   1034         return true;
   1035     return false;
   1036   }
   1037 
   1038   protected:
   1039   USHORT	classFormat;	/* Format identifier--format = 2 */
   1040   SortedArrayOf<RangeRecord>
   1041 		rangeRecord;	/* Array of glyph ranges--ordered by
   1042 				 * Start GlyphID */
   1043   public:
   1044   DEFINE_SIZE_ARRAY (4, rangeRecord);
   1045 };
   1046 
   1047 struct ClassDef
   1048 {
   1049   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   1050   {
   1051     switch (u.format) {
   1052     case 1: return u.format1.get_class(glyph_id);
   1053     case 2: return u.format2.get_class(glyph_id);
   1054     default:return 0;
   1055     }
   1056   }
   1057 
   1058   inline bool sanitize (hb_sanitize_context_t *c) {
   1059     TRACE_SANITIZE (this);
   1060     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   1061     switch (u.format) {
   1062     case 1: return TRACE_RETURN (u.format1.sanitize (c));
   1063     case 2: return TRACE_RETURN (u.format2.sanitize (c));
   1064     default:return TRACE_RETURN (true);
   1065     }
   1066   }
   1067 
   1068   inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
   1069     switch (u.format) {
   1070     case 1: u.format1.add_class (glyphs, klass); return;
   1071     case 2: u.format2.add_class (glyphs, klass); return;
   1072     default:return;
   1073     }
   1074   }
   1075 
   1076   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
   1077     switch (u.format) {
   1078     case 1: return u.format1.intersects_class (glyphs, klass);
   1079     case 2: return u.format2.intersects_class (glyphs, klass);
   1080     default:return false;
   1081     }
   1082   }
   1083 
   1084   protected:
   1085   union {
   1086   USHORT		format;		/* Format identifier */
   1087   ClassDefFormat1	format1;
   1088   ClassDefFormat2	format2;
   1089   } u;
   1090   public:
   1091   DEFINE_SIZE_UNION (2, format);
   1092 };
   1093 
   1094 
   1095 /*
   1096  * Device Tables
   1097  */
   1098 
   1099 struct Device
   1100 {
   1101 
   1102   inline hb_position_t get_x_delta (hb_font_t *font) const
   1103   { return get_delta (font->x_ppem, font->x_scale); }
   1104 
   1105   inline hb_position_t get_y_delta (hb_font_t *font) const
   1106   { return get_delta (font->y_ppem, font->y_scale); }
   1107 
   1108   inline int get_delta (unsigned int ppem, int scale) const
   1109   {
   1110     if (!ppem) return 0;
   1111 
   1112     int pixels = get_delta_pixels (ppem);
   1113 
   1114     if (!pixels) return 0;
   1115 
   1116     return (int) (pixels * (int64_t) scale / ppem);
   1117   }
   1118 
   1119 
   1120   inline int get_delta_pixels (unsigned int ppem_size) const
   1121   {
   1122     unsigned int f = deltaFormat;
   1123     if (unlikely (f < 1 || f > 3))
   1124       return 0;
   1125 
   1126     if (ppem_size < startSize || ppem_size > endSize)
   1127       return 0;
   1128 
   1129     unsigned int s = ppem_size - startSize;
   1130 
   1131     unsigned int byte = deltaValue[s >> (4 - f)];
   1132     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
   1133     unsigned int mask = (0xFFFF >> (16 - (1 << f)));
   1134 
   1135     int delta = bits & mask;
   1136 
   1137     if ((unsigned int) delta >= ((mask + 1) >> 1))
   1138       delta -= mask + 1;
   1139 
   1140     return delta;
   1141   }
   1142 
   1143   inline unsigned int get_size (void) const
   1144   {
   1145     unsigned int f = deltaFormat;
   1146     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
   1147     return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
   1148   }
   1149 
   1150   inline bool sanitize (hb_sanitize_context_t *c) {
   1151     TRACE_SANITIZE (this);
   1152     return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
   1153   }
   1154 
   1155   protected:
   1156   USHORT	startSize;		/* Smallest size to correct--in ppem */
   1157   USHORT	endSize;		/* Largest size to correct--in ppem */
   1158   USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
   1159 					 * 1	Signed 2-bit value, 8 values per uint16
   1160 					 * 2	Signed 4-bit value, 4 values per uint16
   1161 					 * 3	Signed 8-bit value, 2 values per uint16
   1162 					 */
   1163   USHORT	deltaValue[VAR];	/* Array of compressed data */
   1164   public:
   1165   DEFINE_SIZE_ARRAY (6, deltaValue);
   1166 };
   1167 
   1168 
   1169 } /* namespace OT */
   1170 
   1171 
   1172 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
   1173