hb-ot-layout-common.hh 54.8 KB
Newer Older
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3
 * Copyright © 2010,2012  Google, Inc.
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
27 28
 */

29 30
#ifndef HB_OT_LAYOUT_COMMON_HH
#define HB_OT_LAYOUT_COMMON_HH
31

32 33 34 35
#include "hb.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
#include "hb-set.hh"
36 37


38 39 40 41 42 43
#ifndef HB_MAX_NESTING_LEVEL
#define HB_MAX_NESTING_LEVEL	6
#endif
#ifndef HB_MAX_CONTEXT_LENGTH
#define HB_MAX_CONTEXT_LENGTH	64
#endif
44 45 46 47
#ifndef HB_CLOSURE_MAX_STAGES
/*
 * The maximum number of times a lookup can be applied during shaping.
 * Used to limit the number of iterations of the closure algorithm.
48 49
 * This must be larger than the number of times add_pause() is
 * called in a collect_features call of any shaper.
50
 */
51
#define HB_CLOSURE_MAX_STAGES	32
52
#endif
53 54


55 56 57
namespace OT {


B
Minor  
Behdad Esfahbod 已提交
58
#define NOT_COVERED		((unsigned int) -1)
B
Behdad Esfahbod 已提交
59

B
Behdad Esfahbod 已提交
60

B
Behdad Esfahbod 已提交
61

62 63 64 65 66 67
/*
 *
 * OpenType Layout Common Table Formats
 *
 */

68

69 70 71 72 73
/*
 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
 */

template <typename Type>
B
Behdad Esfahbod 已提交
74 75
struct Record
{
76
  inline int cmp (hb_tag_t a) const {
77
    return tag.cmp (a);
B
Behdad Esfahbod 已提交
78 79
  }

80 81
  struct sanitize_closure_t {
    hb_tag_t tag;
B
Behdad Esfahbod 已提交
82
    const void *list_base;
83
  };
B
Behdad Esfahbod 已提交
84 85
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
86
    TRACE_SANITIZE (this);
87
    const sanitize_closure_t closure = {tag, base};
B
Behdad Esfahbod 已提交
88
    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
B
Behdad Esfahbod 已提交
89 90
  }

91 92 93 94
  Tag		tag;		/* 4-byte Tag identifier */
  OffsetTo<Type>
		offset;		/* Offset from beginning of object holding
				 * the Record */
B
Behdad Esfahbod 已提交
95 96
  public:
  DEFINE_SIZE_STATIC (6);
97 98 99
};

template <typename Type>
100 101 102 103 104 105
struct RecordArrayOf : SortedArrayOf<Record<Type> >
{
  inline const OffsetTo<Type>& get_offset (unsigned int i) const
  { return (*this)[i].offset; }
  inline OffsetTo<Type>& get_offset (unsigned int i)
  { return (*this)[i].offset; }
B
Behdad Esfahbod 已提交
106
  inline const Tag& get_tag (unsigned int i) const
107
  { return (*this)[i].tag; }
B
Behdad Esfahbod 已提交
108 109 110
  inline unsigned int get_tags (unsigned int start_offset,
				unsigned int *record_count /* IN/OUT */,
				hb_tag_t     *record_tags /* OUT */) const
111
  {
B
Behdad Esfahbod 已提交
112
    if (record_count) {
B
Behdad Esfahbod 已提交
113
      const Record<Type> *arr = this->sub_array (start_offset, record_count);
B
Behdad Esfahbod 已提交
114
      unsigned int count = *record_count;
B
Behdad Esfahbod 已提交
115
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
116
	record_tags[i] = arr[i].tag;
B
Behdad Esfahbod 已提交
117 118
    }
    return this->len;
119 120 121
  }
  inline bool find_index (hb_tag_t tag, unsigned int *index) const
  {
122 123
    /* If we want to allow non-sorted data, we can lsearch(). */
    int i = this->/*lsearch*/bsearch (tag);
B
Behdad Esfahbod 已提交
124
    if (i != -1) {
125 126
        if (index) *index = i;
        return true;
B
Behdad Esfahbod 已提交
127 128 129
    } else {
      if (index) *index = Index::NOT_FOUND_INDEX;
      return false;
130 131 132 133 134 135 136 137
    }
  }
};

template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
  inline const Type& operator [] (unsigned int i) const
138 139 140 141 142 143 144 145 146
  { return this+this->get_offset (i); }

  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    struct RecordListOf<Type> *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);
    unsigned int count = this->len;
    for (unsigned int i = 0; i < count; i++)
147
      out->get_offset (i).serialize_subset (c, (*this)[i], out);
148 149
    return_trace (true);
  }
B
Behdad Esfahbod 已提交
150

B
Behdad Esfahbod 已提交
151 152
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
153
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
154
    return_trace (RecordArrayOf<Type>::sanitize (c, this));
B
Behdad Esfahbod 已提交
155
  }
156 157 158
};


B
Behdad Esfahbod 已提交
159 160 161
struct RangeRecord
{
  inline int cmp (hb_codepoint_t g) const {
B
Minor  
Behdad Esfahbod 已提交
162
    return g < start ? -1 : g <= end ? 0 : +1 ;
B
Behdad Esfahbod 已提交
163 164
  }

B
Behdad Esfahbod 已提交
165 166
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
167
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
168
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
169 170
  }

171 172
  inline bool intersects (const hb_set_t *glyphs) const
  { return glyphs->intersects (start, end); }
173

174
  template <typename set_t>
B
Behdad Esfahbod 已提交
175
  inline bool add_coverage (set_t *glyphs) const {
176
    return glyphs->add_range (start, end);
177 178
  }

B
Behdad Esfahbod 已提交
179 180
  GlyphID	start;		/* First GlyphID in the range */
  GlyphID	end;		/* Last GlyphID in the range */
B
Behdad Esfahbod 已提交
181
  HBUINT16	value;		/* Value */
B
Behdad Esfahbod 已提交
182 183 184
  public:
  DEFINE_SIZE_STATIC (6);
};
185
DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
B
Behdad Esfahbod 已提交
186 187


B
Behdad Esfahbod 已提交
188
struct IndexArray : ArrayOf<Index>
189
{
B
Behdad Esfahbod 已提交
190 191 192
  inline unsigned int get_indexes (unsigned int start_offset,
				   unsigned int *_count /* IN/OUT */,
				   unsigned int *_indexes /* OUT */) const
193
  {
B
Behdad Esfahbod 已提交
194
    if (_count) {
B
Behdad Esfahbod 已提交
195
      const HBUINT16 *arr = this->sub_array (start_offset, _count);
B
Behdad Esfahbod 已提交
196
      unsigned int count = *_count;
B
Behdad Esfahbod 已提交
197
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
198
	_indexes[i] = arr[i];
B
Behdad Esfahbod 已提交
199 200
    }
    return this->len;
201
  }
202 203 204 205 206

  inline void add_indexes_to (hb_set_t* output /* OUT */) const
  {
    output->add_array (arrayZ, len);
  }
207 208 209
};


210 211 212 213 214
struct Script;
struct LangSys;
struct Feature;


B
Behdad Esfahbod 已提交
215 216
struct LangSys
{
217 218 219 220
  inline unsigned int get_feature_count (void) const
  { return featureIndex.len; }
  inline hb_tag_t get_feature_index (unsigned int i) const
  { return featureIndex[i]; }
B
Behdad Esfahbod 已提交
221 222 223 224
  inline unsigned int get_feature_indexes (unsigned int start_offset,
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */) const
  { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
225 226
  inline void add_feature_indexes_to (hb_set_t *feature_indexes) const
  { featureIndex.add_indexes_to (feature_indexes); }
227

228
  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
B
Behdad Esfahbod 已提交
229
  inline unsigned int get_required_feature_index (void) const
B
Behdad Esfahbod 已提交
230
  {
231
    if (reqFeatureIndex == 0xFFFFu)
B
Behdad Esfahbod 已提交
232
      return Index::NOT_FOUND_INDEX;
233 234 235
   return reqFeatureIndex;;
  }

236 237 238 239 240 241
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    return_trace (c->serializer->embed (*this));
  }

242
  inline bool sanitize (hb_sanitize_context_t *c,
B
Behdad Esfahbod 已提交
243
			const Record<LangSys>::sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
244
  {
B
Behdad Esfahbod 已提交
245
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
246
    return_trace (c->check_struct (this) && featureIndex.sanitize (c));
B
Behdad Esfahbod 已提交
247 248
  }

B
Behdad Esfahbod 已提交
249
  Offset16	lookupOrderZ;	/* = Null (reserved for an offset to a
250
				 * reordering table) */
B
Behdad Esfahbod 已提交
251
  HBUINT16	reqFeatureIndex;/* Index of a feature required for this
252
				 * language system--if no required features
253
				 * = 0xFFFFu */
254
  IndexArray	featureIndex;	/* Array of indices into the FeatureList */
B
Behdad Esfahbod 已提交
255
  public:
256
  DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
257
};
258
DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
259

B
Behdad Esfahbod 已提交
260 261
struct Script
{
262 263 264 265
  inline unsigned int get_lang_sys_count (void) const
  { return langSys.len; }
  inline const Tag& get_lang_sys_tag (unsigned int i) const
  { return langSys.get_tag (i); }
B
Behdad Esfahbod 已提交
266 267 268 269
  inline unsigned int get_lang_sys_tags (unsigned int start_offset,
					 unsigned int *lang_sys_count /* IN/OUT */,
					 hb_tag_t     *lang_sys_tags /* OUT */) const
  { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
B
Behdad Esfahbod 已提交
270 271
  inline const LangSys& get_lang_sys (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
272
    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
273 274
    return this+langSys[i].offset;
  }
275 276
  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
  { return langSys.find_index (tag, index); }
277

B
Behdad Esfahbod 已提交
278
  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
B
Behdad Esfahbod 已提交
279
  inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
280

281 282 283 284 285
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    struct Script *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);
286
    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
287 288
    unsigned int count = langSys.len;
    for (unsigned int i = 0; i < count; i++)
289
      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
290 291 292
    return_trace (true);
  }

293
  inline bool sanitize (hb_sanitize_context_t *c,
B
Behdad Esfahbod 已提交
294
			const Record<Script>::sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
295
  {
B
Behdad Esfahbod 已提交
296
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
297
    return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
B
Behdad Esfahbod 已提交
298 299
  }

300
  protected:
301 302 303
  OffsetTo<LangSys>
		defaultLangSys;	/* Offset to DefaultLangSys table--from
				 * beginning of Script table--may be Null */
B
Behdad Esfahbod 已提交
304
  RecordArrayOf<LangSys>
305 306
		langSys;	/* Array of LangSysRecords--listed
				 * alphabetically by LangSysTag */
307
  public:
308
  DEFINE_SIZE_ARRAY_SIZED (4, langSys);
309 310 311 312
};

typedef RecordListOf<Script> ScriptList;

313

314
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
315 316
struct FeatureParamsSize
{
B
Behdad Esfahbod 已提交
317 318
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
319
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
320
    if (unlikely (!c->check_struct (this))) return_trace (false);
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335

    /* This subtable has some "history", if you will.  Some earlier versions of
     * Adobe tools calculated the offset of the FeatureParams sutable from the
     * beginning of the FeatureList table!  Now, that is dealt with in the
     * Feature implementation.  But we still need to be able to tell junk from
     * real data.  Note: We don't check that the nameID actually exists.
     *
     * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
     *
     * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
     * coming out soon, and that the makeotf program will build a font with a
     * 'size' feature that is correct by the specification.
     *
     * The specification for this feature tag is in the "OpenType Layout Tag
     * Registry". You can see a copy of this at:
336
     * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
337 338 339 340 341 342
     *
     * Here is one set of rules to determine if the 'size' feature is built
     * correctly, or as by the older versions of MakeOTF. You may be able to do
     * better.
     *
     * Assume that the offset to the size feature is according to specification,
B
Bruce Mitchener 已提交
343
     * and make the following value checks. If it fails, assume the size
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
     * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
     * If this fails, reject the 'size' feature. The older makeOTF's calculated the
     * offset from the beginning of the FeatureList table, rather than from the
     * beginning of the 'size' Feature table.
     *
     * If "design size" == 0:
     *     fails check
     *
     * Else if ("subfamily identifier" == 0 and
     *     "range start" == 0 and
     *     "range end" == 0 and
     *     "range start" == 0 and
     *     "menu name ID" == 0)
     *     passes check: this is the format used when there is a design size
     * specified, but there is no recommended size range.
     *
     * Else if ("design size" <  "range start" or
     *     "design size" >   "range end" or
     *     "range end" <= "range start" or
     *     "menu name ID"  < 256 or
     *     "menu name ID"  > 32767 or
     *     menu name ID is not a name ID which is actually in the name table)
     *     fails test
     * Else
     *     passes test.
     */

    if (!designSize)
B
Behdad Esfahbod 已提交
372
      return_trace (false);
373 374 375 376
    else if (subfamilyID == 0 &&
	     subfamilyNameID == 0 &&
	     rangeStart == 0 &&
	     rangeEnd == 0)
B
Behdad Esfahbod 已提交
377
      return_trace (true);
378 379 380 381
    else if (designSize < rangeStart ||
	     designSize > rangeEnd ||
	     subfamilyNameID < 256 ||
	     subfamilyNameID > 32767)
B
Behdad Esfahbod 已提交
382
      return_trace (false);
383
    else
B
Behdad Esfahbod 已提交
384
      return_trace (true);
385 386
  }

B
Behdad Esfahbod 已提交
387
  HBUINT16	designSize;	/* Represents the design size in 720/inch
388 389 390 391
				 * units (decipoints).  The design size entry
				 * must be non-zero.  When there is a design
				 * size but no recommended size range, the
				 * rest of the array will consist of zeros. */
B
Behdad Esfahbod 已提交
392
  HBUINT16	subfamilyID;	/* Has no independent meaning, but serves
393 394 395 396 397 398 399 400 401
				 * as an identifier that associates fonts
				 * in a subfamily. All fonts which share a
				 * Preferred or Font Family name and which
				 * differ only by size range shall have the
				 * same subfamily value, and no fonts which
				 * differ in weight or style shall have the
				 * same subfamily value. If this value is
				 * zero, the remaining fields in the array
				 * will be ignored. */
B
Behdad Esfahbod 已提交
402
  HBUINT16	subfamilyNameID;/* If the preceding value is non-zero, this
403 404 405 406 407 408 409 410 411 412 413 414 415
				 * value must be set in the range 256 - 32767
				 * (inclusive). It records the value of a
				 * field in the name table, which must
				 * contain English-language strings encoded
				 * in Windows Unicode and Macintosh Roman,
				 * and may contain additional strings
				 * localized to other scripts and languages.
				 * Each of these strings is the name an
				 * application should use, in combination
				 * with the family name, to represent the
				 * subfamily in a menu.  Applications will
				 * choose the appropriate version based on
				 * their selection criteria. */
B
Behdad Esfahbod 已提交
416
  HBUINT16	rangeStart;	/* Large end of the recommended usage range
417 418
				 * (inclusive), stored in 720/inch units
				 * (decipoints). */
B
Behdad Esfahbod 已提交
419
  HBUINT16	rangeEnd;	/* Small end of the recommended usage range
420 421
				   (exclusive), stored in 720/inch units
				 * (decipoints). */
422 423 424 425
  public:
  DEFINE_SIZE_STATIC (10);
};

426
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
427 428
struct FeatureParamsStylisticSet
{
B
Behdad Esfahbod 已提交
429 430
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
431 432 433
    TRACE_SANITIZE (this);
    /* Right now minorVersion is at zero.  Which means, any table supports
     * the uiNameID field. */
B
Behdad Esfahbod 已提交
434
    return_trace (c->check_struct (this));
435 436
  }

B
Behdad Esfahbod 已提交
437
  HBUINT16	version;	/* (set to 0): This corresponds to a “minor”
438 439 440 441
				 * version number. Additional data may be
				 * added to the end of this Feature Parameters
				 * table in the future. */

B
Behdad Esfahbod 已提交
442
  NameID	uiNameID;	/* The 'name' table name ID that specifies a
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
				 * string (or strings, for multiple languages)
				 * for a user-interface label for this
				 * feature.  The values of uiLabelNameId and
				 * sampleTextNameId are expected to be in the
				 * font-specific name ID range (256-32767),
				 * though that is not a requirement in this
				 * Feature Parameters specification. The
				 * user-interface label for the feature can
				 * be provided in multiple languages. An
				 * English string should be included as a
				 * fallback. The string should be kept to a
				 * minimal length to fit comfortably with
				 * different application interfaces. */
  public:
  DEFINE_SIZE_STATIC (4);
};

460
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
461 462
struct FeatureParamsCharacterVariants
{
B
Behdad Esfahbod 已提交
463 464
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
465
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
466 467
    return_trace (c->check_struct (this) &&
		  characters.sanitize (c));
468
  }
469

B
Behdad Esfahbod 已提交
470
  HBUINT16	format;			/* Format number is set to 0. */
B
Behdad Esfahbod 已提交
471
  NameID	featUILableNameID;	/* The ‘name’ table name ID that
472 473 474
					 * specifies a string (or strings,
					 * for multiple languages) for a
					 * user-interface label for this
B
Behdad Esfahbod 已提交
475
					 * feature. (May be nullptr.) */
B
Behdad Esfahbod 已提交
476
  NameID	featUITooltipTextNameID;/* The ‘name’ table name ID that
477 478 479 480
					 * specifies a string (or strings,
					 * for multiple languages) that an
					 * application can use for tooltip
					 * text for this feature. (May be
B
Behdad Esfahbod 已提交
481
					 * nullptr.) */
B
Behdad Esfahbod 已提交
482
  NameID	sampleTextNameID;	/* The ‘name’ table name ID that
483 484
					 * specifies sample text that
					 * illustrates the effect of this
B
Behdad Esfahbod 已提交
485
					 * feature. (May be nullptr.) */
B
Behdad Esfahbod 已提交
486
  HBUINT16	numNamedParameters;	/* Number of named parameters. (May
487
					 * be zero.) */
B
Behdad Esfahbod 已提交
488
  NameID	firstParamUILabelNameID;/* The first ‘name’ table name ID
489 490 491 492
					 * used to specify strings for
					 * user-interface labels for the
					 * feature parameters. (Must be zero
					 * if numParameters is zero.) */
493
  ArrayOf<HBUINT24>
494 495 496 497 498 499 500 501
		characters;		/* Array of the Unicode Scalar Value
					 * of the characters for which this
					 * feature provides glyph variants.
					 * (May be zero.) */
  public:
  DEFINE_SIZE_ARRAY (14, characters);
};

502 503
struct FeatureParams
{
B
Behdad Esfahbod 已提交
504 505
  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
  {
506
    TRACE_SANITIZE (this);
507
    if (tag == HB_TAG ('s','i','z','e'))
B
Behdad Esfahbod 已提交
508
      return_trace (u.size.sanitize (c));
509
    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
B
Behdad Esfahbod 已提交
510
      return_trace (u.stylisticSet.sanitize (c));
511
    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
B
Behdad Esfahbod 已提交
512 513
      return_trace (u.characterVariants.sanitize (c));
    return_trace (true);
514 515
  }

516 517 518 519 520 521 522 523
  inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
  {
    if (tag == HB_TAG ('s','i','z','e'))
      return u.size;
    return Null(FeatureParamsSize);
  }

  private:
524
  union {
525 526 527
  FeatureParamsSize			size;
  FeatureParamsStylisticSet		stylisticSet;
  FeatureParamsCharacterVariants	characterVariants;
528
  } u;
529
  DEFINE_SIZE_STATIC (17);
530
};
531

B
Behdad Esfahbod 已提交
532 533
struct Feature
{
534 535 536 537
  inline unsigned int get_lookup_count (void) const
  { return lookupIndex.len; }
  inline hb_tag_t get_lookup_index (unsigned int i) const
  { return lookupIndex[i]; }
B
Behdad Esfahbod 已提交
538 539 540 541
  inline unsigned int get_lookup_indexes (unsigned int start_index,
					  unsigned int *lookup_count /* IN/OUT */,
					  unsigned int *lookup_tags /* OUT */) const
  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
542

543 544 545
  inline const FeatureParams &get_feature_params (void) const
  { return this+featureParams; }

546 547 548 549 550 551 552 553 554
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    struct Feature *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);
    out->featureParams.set (0); /* TODO(subset) FeatureParams. */
    return_trace (true);
  }

555
  inline bool sanitize (hb_sanitize_context_t *c,
B
Behdad Esfahbod 已提交
556
			const Record<Feature>::sanitize_closure_t *closure = nullptr) const
B
Behdad Esfahbod 已提交
557
  {
B
Behdad Esfahbod 已提交
558
    TRACE_SANITIZE (this);
559
    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
B
Behdad Esfahbod 已提交
560
      return_trace (false);
561

562 563 564 565 566 567
    /* Some earlier versions of Adobe tools calculated the offset of the
     * FeatureParams subtable from the beginning of the FeatureList table!
     *
     * If sanitizing "failed" for the FeatureParams subtable, try it with the
     * alternative location.  We would know sanitize "failed" if old value
     * of the offset was non-zero, but it's zeroed now.
568 569 570
     *
     * Only do this for the 'size' feature, since at the time of the faulty
     * Adobe tools, only the 'size' feature had FeatureParams defined.
571 572
     */

B
Behdad Esfahbod 已提交
573
    OffsetTo<FeatureParams> orig_offset = featureParams;
574
    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
B
Behdad Esfahbod 已提交
575
      return_trace (false);
576

577
    if (likely (orig_offset.is_null ()))
B
Behdad Esfahbod 已提交
578
      return_trace (true);
579

580 581 582
    if (featureParams == 0 && closure &&
	closure->tag == HB_TAG ('s','i','z','e') &&
	closure->list_base && closure->list_base < this)
583
    {
584
      unsigned int new_offset_int = (unsigned int) orig_offset -
B
Behdad Esfahbod 已提交
585
				    (((char *) this) - ((char *) closure->list_base));
586

B
Behdad Esfahbod 已提交
587
      OffsetTo<FeatureParams> new_offset;
588
      /* Check that it did not overflow. */
589 590
      new_offset.set (new_offset_int);
      if (new_offset == new_offset_int &&
591
	  c->try_set (&featureParams, new_offset) &&
592
	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
B
Behdad Esfahbod 已提交
593
	return_trace (false);
594 595
    }

B
Behdad Esfahbod 已提交
596
    return_trace (true);
B
Behdad Esfahbod 已提交
597 598
  }

599 600
  OffsetTo<FeatureParams>
		 featureParams;	/* Offset to Feature Parameters table (if one
601 602 603
				 * has been defined for the feature), relative
				 * to the beginning of the Feature Table; = Null
				 * if not required */
604
  IndexArray	 lookupIndex;	/* Array of LookupList indices */
605
  public:
606
  DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
607 608 609 610 611
};

typedef RecordListOf<Feature> FeatureList;


B
Behdad Esfahbod 已提交
612
struct LookupFlag : HBUINT16
B
Behdad Esfahbod 已提交
613
{
B
Behdad Esfahbod 已提交
614
  enum Flags {
B
Behdad Esfahbod 已提交
615 616 617 618
    RightToLeft		= 0x0001u,
    IgnoreBaseGlyphs	= 0x0002u,
    IgnoreLigatures	= 0x0004u,
    IgnoreMarks		= 0x0008u,
B
Behdad Esfahbod 已提交
619
    IgnoreFlags		= 0x000Eu,
620 621
    UseMarkFilteringSet	= 0x0010u,
    Reserved		= 0x00E0u,
622
    MarkAttachmentType	= 0xFF00u
B
Behdad Esfahbod 已提交
623
  };
624 625
  public:
  DEFINE_SIZE_STATIC (2);
626 627
};

B
Behdad Esfahbod 已提交
628 629
} /* namespace OT */
/* This has to be outside the namespace. */
C
Chun-wei Fan 已提交
630
HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
B
Behdad Esfahbod 已提交
631 632
namespace OT {

B
Behdad Esfahbod 已提交
633 634 635
struct Lookup
{
  inline unsigned int get_subtable_count (void) const { return subTable.len; }
636

B
Behdad Esfahbod 已提交
637 638 639
  template <typename TSubTable>
  inline const TSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
640

B
Behdad Esfahbod 已提交
641 642 643 644 645 646
  template <typename TSubTable>
  inline const OffsetArrayOf<TSubTable>& get_subtables (void) const
  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
  template <typename TSubTable>
  inline OffsetArrayOf<TSubTable>& get_subtables (void)
  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
647

648 649 650 651 652 653 654 655
  inline unsigned int get_size (void) const
  {
    const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable);
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
      return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this;
    return (const char *) &markFilteringSet - (const char *) this;
  }

656
  inline unsigned int get_type (void) const { return lookupType; }
657 658 659 660 661

  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
   * higher 16-bit is mark-filtering-set if the lookup uses one.
   * Not to be confused with glyph_props which is very similar. */
  inline uint32_t get_props (void) const
662 663
  {
    unsigned int flag = lookupFlag;
664
    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
665
    {
B
Behdad Esfahbod 已提交
666
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
667
      flag += (markFilteringSet << 16);
668 669 670
    }
    return flag;
  }
671

B
Behdad Esfahbod 已提交
672
  template <typename TSubTable, typename context_t>
673 674 675 676 677 678
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    unsigned int lookup_type = get_type ();
    TRACE_DISPATCH (this, lookup_type);
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
679
      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
680
      if (c->stop_sublookup_iteration (r))
B
Behdad Esfahbod 已提交
681
        return_trace (r);
682
    }
B
Behdad Esfahbod 已提交
683
    return_trace (c->default_return_value ());
684 685
  }

686 687 688 689 690
  inline bool serialize (hb_serialize_context_t *c,
			 unsigned int lookup_type,
			 uint32_t lookup_props,
			 unsigned int num_subtables)
  {
B
Behdad Esfahbod 已提交
691
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
692
    if (unlikely (!c->extend_min (*this))) return_trace (false);
693
    lookupType.set (lookup_type);
694
    lookupFlag.set (lookup_props & 0xFFFFu);
B
Behdad Esfahbod 已提交
695
    if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
696
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
697
    {
698
      if (unlikely (!c->extend (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
699
      HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
700 701
      markFilteringSet.set (lookup_props >> 16);
    }
B
Behdad Esfahbod 已提交
702
    return_trace (true);
703 704
  }

705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
  template <typename TSubTable>
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    struct Lookup *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);

    /* Subset the actual subtables. */
    /* TODO Drop empty ones, either by calling intersects() beforehand,
     * or just dropping null offsets after. */
    const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
    OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
    unsigned int count = subTable.len;
    for (unsigned int i = 0; i < count; i++)
    {
      struct Wrapper
      {
        inline Wrapper (const TSubTable &subtable_,
			unsigned int lookup_type_) :
			  subtable (subtable_),
			  lookup_type (lookup_type_) {}

	inline bool subset (hb_subset_context_t *c) const
	{ return subtable.dispatch (c, lookup_type); }

	private:
	const TSubTable &subtable;
	unsigned int lookup_type;
      } wrapper (this+subtables[i], get_type ());

      out_subtables[i].serialize_subset (c, wrapper, out);
    }

    return_trace (true);
  }

B
Behdad Esfahbod 已提交
741
  template <typename TSubTable>
B
Behdad Esfahbod 已提交
742 743
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
744
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
745
    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
746
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
747
    {
B
Behdad Esfahbod 已提交
748
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
749
      if (!markFilteringSet.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
750
    }
B
Behdad Esfahbod 已提交
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766

    if (unlikely (!dispatch<TSubTable> (c))) return_trace (false);

    if (unlikely (get_type () == TSubTable::Extension))
    {
      /* The spec says all subtables of an Extension lookup should
       * have the same type, which shall not be the Extension type
       * itself (but we already checked for that).
       * This is specially important if one has a reverse type! */
      unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
      unsigned int count = get_subtable_count ();
      for (unsigned int i = 1; i < count; i++)
        if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
	  return_trace (false);
    }
    return_trace (true);
B
Behdad Esfahbod 已提交
767
    return_trace (true);
B
Behdad Esfahbod 已提交
768 769
  }

770
  private:
B
Behdad Esfahbod 已提交
771 772
  HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
  HBUINT16	lookupFlag;		/* Lookup qualifiers */
B
Behdad Esfahbod 已提交
773
  ArrayOf<Offset16>
774
		subTable;		/* Array of SubTables */
B
Behdad Esfahbod 已提交
775
  HBUINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
776 777
					 * structure. This field is only present if bit
					 * UseMarkFilteringSet of lookup flags is set. */
B
Behdad Esfahbod 已提交
778
  public:
779
  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
780 781 782 783 784 785 786 787 788
};

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
789 790
struct CoverageFormat1
{
791 792 793
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
794 795
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
796
    int i = glyphArray.bsearch (glyph_id);
797
    static_assert ((((unsigned int) -1) == NOT_COVERED), "");
B
Minor  
Behdad Esfahbod 已提交
798
    return i;
799 800
  }

801
  inline bool serialize (hb_serialize_context_t *c,
802
			 Supplier<GlyphID> &glyphs,
803
			 unsigned int num_glyphs)
804
  {
B
Behdad Esfahbod 已提交
805
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
806
    if (unlikely (!c->extend_min (*this))) return_trace (false);
807
    glyphArray.len.set (num_glyphs);
B
Behdad Esfahbod 已提交
808
    if (unlikely (!c->extend (glyphArray))) return_trace (false);
809
    for (unsigned int i = 0; i < num_glyphs; i++)
810
      glyphArray[i] = glyphs[i];
811
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
812
    return_trace (true);
813 814
  }

B
Behdad Esfahbod 已提交
815 816
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
817
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
818
    return_trace (glyphArray.sanitize (c));
B
Behdad Esfahbod 已提交
819 820
  }

821 822 823 824 825 826 827 828
  inline bool intersects (const hb_set_t *glyphs) const
  {
    /* TODO Speed up, using hb_set_next() and bsearch()? */
    unsigned int count = glyphArray.len;
    for (unsigned int i = 0; i < count; i++)
      if (glyphs->has (glyphArray[i]))
        return true;
    return false;
829
  }
830 831
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  { return glyphs->has (glyphArray[index]); }
832

833
  template <typename set_t>
B
Behdad Esfahbod 已提交
834
  inline bool add_coverage (set_t *glyphs) const {
835
    return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
836 837
  }

B
Behdad Esfahbod 已提交
838 839
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
840
  struct Iter {
B
Behdad Esfahbod 已提交
841
    inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
842
    inline void fini (void) {};
B
Behdad Esfahbod 已提交
843 844
    inline bool more (void) { return i < c->glyphArray.len; }
    inline void next (void) { i++; }
845 846
    inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
    inline unsigned int get_coverage (void) { return i; }
B
Behdad Esfahbod 已提交
847 848 849 850 851

    private:
    const struct CoverageFormat1 *c;
    unsigned int i;
  };
B
Behdad Esfahbod 已提交
852
  private:
B
Behdad Esfahbod 已提交
853

854
  protected:
B
Behdad Esfahbod 已提交
855
  HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
856
  SortedArrayOf<GlyphID>
857
		glyphArray;	/* Array of GlyphIDs--in numerical order */
858
  public:
859
  DEFINE_SIZE_ARRAY (4, glyphArray);
860 861
};

B
Behdad Esfahbod 已提交
862 863
struct CoverageFormat2
{
864 865 866
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
867 868
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
869
    int i = rangeRecord.bsearch (glyph_id);
B
Behdad Esfahbod 已提交
870 871 872
    if (i != -1) {
      const RangeRecord &range = rangeRecord[i];
      return (unsigned int) range.value + (glyph_id - range.start);
873 874 875 876
    }
    return NOT_COVERED;
  }

877
  inline bool serialize (hb_serialize_context_t *c,
878
			 Supplier<GlyphID> &glyphs,
879
			 unsigned int num_glyphs)
880
  {
B
Behdad Esfahbod 已提交
881
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
882
    if (unlikely (!c->extend_min (*this))) return_trace (false);
883

884 885 886 887 888
    if (unlikely (!num_glyphs))
    {
      rangeRecord.len.set (0);
      return_trace (true);
    }
889

890 891 892 893
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
894
    rangeRecord.len.set (num_ranges);
B
Behdad Esfahbod 已提交
895
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
896

897
    unsigned int range = 0;
898
    rangeRecord[range].start = glyphs[0];
899
    rangeRecord[range].value.set (0);
900 901 902
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i]) {
	range++;
903 904 905
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value.set (i);
        rangeRecord[range].end = glyphs[i];
906
      } else {
907
        rangeRecord[range].end = glyphs[i];
908
      }
909
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
910
    return_trace (true);
911 912
  }

B
Behdad Esfahbod 已提交
913 914
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
915
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
916
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
917 918
  }

919 920 921 922 923 924 925 926 927 928 929
  inline bool intersects (const hb_set_t *glyphs) const
  {
    /* TODO Speed up, using hb_set_next() and bsearch()? */
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  {
930 931 932 933 934
    unsigned int i;
    unsigned int count = rangeRecord.len;
    for (i = 0; i < count; i++) {
      const RangeRecord &range = rangeRecord[i];
      if (range.value <= index &&
B
Behdad Esfahbod 已提交
935
	  index < (unsigned int) range.value + (range.end - range.start) &&
936 937 938 939 940 941 942 943
	  range.intersects (glyphs))
        return true;
      else if (index < range.value)
        return false;
    }
    return false;
  }

944
  template <typename set_t>
B
Behdad Esfahbod 已提交
945
  inline bool add_coverage (set_t *glyphs) const {
946 947
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
948
      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
949
        return false;
B
Behdad Esfahbod 已提交
950
    return true;
951 952
  }

B
Behdad Esfahbod 已提交
953 954
  public:
  /* Older compilers need this to be public. */
955 956 957 958
  struct Iter
  {
    inline void init (const CoverageFormat2 &c_)
    {
B
Behdad Esfahbod 已提交
959 960 961
      c = &c_;
      coverage = 0;
      i = 0;
962 963 964 965 966 967
      j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
      if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
      {
        /* Broken table. Skip. */
        i = c->rangeRecord.len;
      }
B
Behdad Esfahbod 已提交
968
    }
969
    inline void fini (void) {};
B
Behdad Esfahbod 已提交
970
    inline bool more (void) { return i < c->rangeRecord.len; }
971 972 973 974
    inline void next (void)
    {
      if (j >= c->rangeRecord[i].end)
      {
B
Behdad Esfahbod 已提交
975
        i++;
B
Behdad Esfahbod 已提交
976
	if (more ())
977
	{
978
	  hb_codepoint_t old = j;
B
Behdad Esfahbod 已提交
979
	  j = c->rangeRecord[i].start;
980 981 982 983 984 985
	  if (unlikely (j <= old))
	  {
	    /* Broken table. Skip. Important to avoid DoS. */
	   i = c->rangeRecord.len;
	   return;
	  }
986 987
	  coverage = c->rangeRecord[i].value;
	}
B
Behdad Esfahbod 已提交
988
	return;
B
Behdad Esfahbod 已提交
989
      }
990
      coverage++;
B
Behdad Esfahbod 已提交
991 992
      j++;
    }
993 994
    inline hb_codepoint_t get_glyph (void) { return j; }
    inline unsigned int get_coverage (void) { return coverage; }
B
Behdad Esfahbod 已提交
995 996 997

    private:
    const struct CoverageFormat2 *c;
998 999
    unsigned int i, coverage;
    hb_codepoint_t j;
B
Behdad Esfahbod 已提交
1000
  };
B
Behdad Esfahbod 已提交
1001
  private:
B
Behdad Esfahbod 已提交
1002

1003
  protected:
B
Behdad Esfahbod 已提交
1004
  HBUINT16	coverageFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1005
  SortedArrayOf<RangeRecord>
1006 1007 1008
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID. rangeCount entries
				 * long */
1009
  public:
1010
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1011 1012
};

B
Behdad Esfahbod 已提交
1013 1014
struct Coverage
{
B
Behdad Esfahbod 已提交
1015
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1016
  {
1017
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1018 1019
    case 1: return u.format1.get_coverage (glyph_id);
    case 2: return u.format2.get_coverage (glyph_id);
1020 1021 1022 1023
    default:return NOT_COVERED;
    }
  }

1024
  inline bool serialize (hb_serialize_context_t *c,
1025
			 Supplier<GlyphID> &glyphs,
1026
			 unsigned int num_glyphs)
1027
  {
B
Behdad Esfahbod 已提交
1028
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1029
    if (unlikely (!c->extend_min (*this))) return_trace (false);
1030 1031 1032 1033
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
1034
    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
1035 1036
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1037 1038 1039
    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
    case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
    default:return_trace (false);
1040 1041 1042
    }
  }

B
Behdad Esfahbod 已提交
1043 1044
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1045
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1046
    if (!u.format.sanitize (c)) return_trace (false);
1047 1048
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1049 1050 1051
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1052 1053
    }
  }
1054

1055 1056
  inline bool intersects (const hb_set_t *glyphs) const
  {
1057 1058 1059 1060 1061 1062
    switch (u.format)
    {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
1063
  }
1064 1065 1066 1067
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  {
    switch (u.format)
    {
1068 1069 1070 1071
    case 1: return u.format1.intersects_coverage (glyphs, index);
    case 2: return u.format2.intersects_coverage (glyphs, index);
    default:return false;
    }
B
Behdad Esfahbod 已提交
1072 1073
  }

B
Behdad Esfahbod 已提交
1074 1075
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
1076
  template <typename set_t>
1077 1078 1079 1080
  inline bool add_coverage (set_t *glyphs) const
  {
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1081 1082
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1083
    default:return false;
1084 1085 1086
    }
  }

1087 1088
  struct Iter
  {
1089
    Iter (void) : format (0), u () {};
1090 1091
    inline void init (const Coverage &c_)
    {
B
Behdad Esfahbod 已提交
1092
      format = c_.u.format;
1093 1094
      switch (format)
      {
B
Minor  
Behdad Esfahbod 已提交
1095 1096
      case 1: u.format1.init (c_.u.format1); return;
      case 2: u.format2.init (c_.u.format2); return;
1097
      default:				     return;
B
Behdad Esfahbod 已提交
1098 1099
      }
    }
1100 1101 1102 1103 1104
    inline void fini (void) {}
    inline bool more (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1105 1106
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
1107
      default:return false;
B
Behdad Esfahbod 已提交
1108 1109
      }
    }
1110 1111 1112 1113
    inline void next (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1114 1115
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
1116
      default:			 break;
B
Behdad Esfahbod 已提交
1117 1118
      }
    }
1119 1120 1121 1122
    inline hb_codepoint_t get_glyph (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1123 1124
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
1125
      default:return 0;
B
Behdad Esfahbod 已提交
1126 1127
      }
    }
1128 1129 1130 1131
    inline unsigned int get_coverage (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1132 1133
      case 1: return u.format1.get_coverage ();
      case 2: return u.format2.get_coverage ();
B
Minor  
Behdad Esfahbod 已提交
1134
      default:return -1;
B
Behdad Esfahbod 已提交
1135 1136 1137 1138
      }
    }

    private:
B
Behdad Esfahbod 已提交
1139
    unsigned int format;
B
Behdad Esfahbod 已提交
1140
    union {
1141
    CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
B
Behdad Esfahbod 已提交
1142 1143 1144 1145
    CoverageFormat1::Iter	format1;
    } u;
  };

1146
  protected:
1147
  union {
B
Behdad Esfahbod 已提交
1148
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1149 1150
  CoverageFormat1	format1;
  CoverageFormat2	format2;
1151
  } u;
B
Behdad Esfahbod 已提交
1152
  public:
B
Behdad Esfahbod 已提交
1153
  DEFINE_SIZE_UNION (2, format);
1154 1155 1156 1157 1158 1159 1160
};


/*
 * Class Definition Table
 */

B
Behdad Esfahbod 已提交
1161 1162
struct ClassDefFormat1
{
1163 1164 1165
  friend struct ClassDef;

  private:
1166
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1167
  {
B
Minor  
Behdad Esfahbod 已提交
1168 1169 1170
    unsigned int i = (unsigned int) (glyph_id - startGlyph);
    if (unlikely (i < classValue.len))
      return classValue[i];
1171 1172 1173
    return 0;
  }

B
Behdad Esfahbod 已提交
1174 1175
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1176
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1177
    return_trace (c->check_struct (this) && classValue.sanitize (c));
B
Behdad Esfahbod 已提交
1178 1179
  }

1180
  template <typename set_t>
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
  inline bool add_coverage (set_t *glyphs) const {
    unsigned int start = 0;
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
    {
      if (classValue[i])
        continue;

      if (start != i)
	if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1191
	  return false;
1192 1193 1194 1195 1196

      start = i + 1;
    }
    if (start != count)
      if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1197
	return false;
1198 1199 1200 1201 1202 1203

    return true;
  }

  template <typename set_t>
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1204 1205
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1206
    {
1207
      if (classValue[i] == klass)
1208
        glyphs->add (startGlyph + i);
B
Behdad Esfahbod 已提交
1209 1210
    }
    return true;
1211 1212
  }

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
  inline bool intersects (const hb_set_t *glyphs) const
  {
    /* TODO Speed up, using hb_set_next()? */
    hb_codepoint_t start = startGlyph;
    hb_codepoint_t end = startGlyph + classValue.len;
    for (hb_codepoint_t iter = startGlyph - 1;
	 hb_set_next (glyphs, &iter) && iter < end;)
      if (classValue[iter - start])
        return true;
    return false;
  }
1224
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1225
    unsigned int count = classValue.len;
1226 1227 1228
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1229
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1230 1231 1232 1233 1234 1235 1236 1237 1238
      if (!hb_set_next (glyphs, &g))
        return false;
      if (g < startGlyph)
        return true;
      g = startGlyph + count - 1;
      if (hb_set_next (glyphs, &g))
        return true;
      /* Fall through. */
    }
1239 1240 1241 1242 1243 1244
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass && glyphs->has (startGlyph + i))
        return true;
    return false;
  }

1245
  protected:
B
Behdad Esfahbod 已提交
1246
  HBUINT16	classFormat;		/* Format identifier--format = 1 */
1247
  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
B
Behdad Esfahbod 已提交
1248
  ArrayOf<HBUINT16>
1249
		classValue;		/* Array of Class Values--one per GlyphID */
1250
  public:
1251
  DEFINE_SIZE_ARRAY (6, classValue);
1252 1253
};

B
Behdad Esfahbod 已提交
1254 1255
struct ClassDefFormat2
{
1256 1257 1258
  friend struct ClassDef;

  private:
1259
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1260
  {
1261
    int i = rangeRecord.bsearch (glyph_id);
B
Minor  
Behdad Esfahbod 已提交
1262
    if (unlikely (i != -1))
B
Behdad Esfahbod 已提交
1263
      return rangeRecord[i].value;
1264 1265 1266
    return 0;
  }

B
Behdad Esfahbod 已提交
1267 1268
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1269
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1270
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
1271 1272
  }

1273
  template <typename set_t>
1274 1275
  inline bool add_coverage (set_t *glyphs) const
  {
1276 1277 1278 1279
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value)
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1280
	  return false;
1281 1282 1283 1284
    return true;
  }

  template <typename set_t>
1285 1286
  inline bool add_class (set_t *glyphs, unsigned int klass) const
  {
1287 1288
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1289
    {
1290
      if (rangeRecord[i].value == klass)
B
Behdad Esfahbod 已提交
1291
        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1292
	  return false;
B
Behdad Esfahbod 已提交
1293 1294
    }
    return true;
1295 1296
  }

1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
  inline bool intersects (const hb_set_t *glyphs) const
  {
    /* TODO Speed up, using hb_set_next() and bsearch()? */
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
  {
1308
    unsigned int count = rangeRecord.len;
1309 1310 1311
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1312
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1313 1314 1315 1316 1317 1318 1319 1320
      for (unsigned int i = 0; i < count; i++)
      {
	if (!hb_set_next (glyphs, &g))
	  break;
	if (g < rangeRecord[i].start)
	  return true;
	g = rangeRecord[i].end;
      }
1321
      if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1322 1323 1324
        return true;
      /* Fall through. */
    }
1325 1326 1327 1328 1329 1330
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }

1331
  protected:
B
Behdad Esfahbod 已提交
1332
  HBUINT16	classFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1333
  SortedArrayOf<RangeRecord>
1334 1335
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID */
1336
  public:
1337
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1338 1339
};

B
Behdad Esfahbod 已提交
1340 1341
struct ClassDef
{
1342
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1343
  {
1344
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1345 1346
    case 1: return u.format1.get_class (glyph_id);
    case 2: return u.format2.get_class (glyph_id);
1347 1348 1349 1350
    default:return 0;
    }
  }

B
Behdad Esfahbod 已提交
1351 1352
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1353
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1354
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
1355
    switch (u.format) {
B
Behdad Esfahbod 已提交
1356 1357 1358
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1359 1360
    }
  }
1361

1362 1363 1364 1365 1366 1367 1368
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
  template <typename set_t>
  inline bool add_coverage (set_t *glyphs) const {
    switch (u.format) {
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1369
    default:return false;
1370 1371 1372 1373 1374
    }
  }

  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
B
Behdad Esfahbod 已提交
1375
  template <typename set_t>
1376
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1377
    switch (u.format) {
1378 1379
    case 1: return u.format1.add_class (glyphs, klass);
    case 2: return u.format2.add_class (glyphs, klass);
B
Behdad Esfahbod 已提交
1380
    default:return false;
1381 1382 1383
    }
  }

1384 1385 1386 1387 1388 1389 1390
  inline bool intersects (const hb_set_t *glyphs) const {
    switch (u.format) {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
  }
1391
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1392 1393 1394 1395 1396 1397 1398
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1399
  protected:
1400
  union {
B
Behdad Esfahbod 已提交
1401
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1402 1403
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1404
  } u;
B
Behdad Esfahbod 已提交
1405
  public:
B
Behdad Esfahbod 已提交
1406
  DEFINE_SIZE_UNION (2, format);
1407 1408 1409
};


1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
/*
 * Item Variation Store
 */

struct VarRegionAxis
{
  inline float evaluate (int coord) const
  {
    int start = startCoord, peak = peakCoord, end = endCoord;

    /* TODO Move these to sanitize(). */
    if (unlikely (start > peak || peak > end))
      return 1.;
    if (unlikely (start < 0 && end > 0 && peak != 0))
      return 1.;

    if (peak == 0 || coord == peak)
      return 1.;

    if (coord <= start || end <= coord)
      return 0.;

    /* Interpolate */
    if (coord < peak)
      return float (coord - start) / (peak - start);
    else
      return float (end - coord) / (end - peak);
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
    /* TODO Handle invalid start/peak/end configs, so we don't
     * have to do that at runtime. */
  }

  public:
  F2DOT14	startCoord;
  F2DOT14	peakCoord;
  F2DOT14	endCoord;
  public:
  DEFINE_SIZE_STATIC (6);
};

struct VarRegionList
{
  inline float evaluate (unsigned int region_index,
			 int *coords, unsigned int coord_len) const
  {
    if (unlikely (region_index >= regionCount))
      return 0.;

1463
    const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1464 1465

    float v = 1.;
1466
    unsigned int count = axisCount;
1467 1468
    for (unsigned int i = 0; i < count; i++)
    {
1469 1470
      int coord = i < coord_len ? coords[i] : 0;
      float factor = axes[i].evaluate (coord);
1471
      if (factor == 0.f)
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
        return 0.;
      v *= factor;
    }
    return v;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
1482
		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1483 1484 1485
  }

  protected:
B
Behdad Esfahbod 已提交
1486 1487
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1488 1489
  UnsizedArrayOf<VarRegionAxis>
		axesZ;
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
  public:
  DEFINE_SIZE_ARRAY (4, axesZ);
};

struct VarData
{
  inline unsigned int get_row_size (void) const
  { return shortCount + regionIndices.len; }

  inline unsigned int get_size (void) const
  { return itemCount * get_row_size (); }

  inline float get_delta (unsigned int inner,
			  int *coords, unsigned int coord_count,
			  const VarRegionList &regions) const
  {
    if (unlikely (inner >= itemCount))
      return 0.;

   unsigned int count = regionIndices.len;
   unsigned int scount = shortCount;

B
Behdad Esfahbod 已提交
1512 1513
   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
   const HBUINT8 *row = bytes + inner * (scount + count);
1514 1515 1516 1517

   float delta = 0.;
   unsigned int i = 0;

B
Behdad Esfahbod 已提交
1518
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1519 1520
   for (; i < scount; i++)
   {
1521
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1522 1523
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1524
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1525 1526
   for (; i < count; i++)
   {
1527
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
     delta += scalar * *bcursor++;
   }

   return delta;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  regionIndices.sanitize(c) &&
		  shortCount <= regionIndices.len &&
B
Behdad Esfahbod 已提交
1540
		  c->check_array (&StructAfter<HBUINT8> (regionIndices),
1541 1542 1543 1544
				  get_row_size (), itemCount));
  }

  protected:
B
Behdad Esfahbod 已提交
1545 1546 1547
  HBUINT16		itemCount;
  HBUINT16		shortCount;
  ArrayOf<HBUINT16>	regionIndices;
1548
  HBUINT8		bytesX[VAR];
1549 1550 1551 1552
  public:
  DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
};

1553
struct VariationStore
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
{
  inline float get_delta (unsigned int outer, unsigned int inner,
			  int *coords, unsigned int coord_count) const
  {
    if (unlikely (outer >= dataSets.len))
      return 0.;

    return (this+dataSets[outer]).get_delta (inner,
					     coords, coord_count,
					     this+regions);
  }

1566 1567 1568 1569 1570 1571 1572 1573
  inline float get_delta (unsigned int index,
			  int *coords, unsigned int coord_count) const
  {
    unsigned int outer = index >> 16;
    unsigned int inner = index & 0xFFFF;
    return get_delta (outer, inner, coords, coord_count);
  }

1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  format == 1 &&
		  regions.sanitize (c, this) &&
		  dataSets.sanitize (c, this));
  }

  protected:
B
Behdad Esfahbod 已提交
1584
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1585
  LOffsetTo<VarRegionList>		regions;
B
Behdad Esfahbod 已提交
1586
  OffsetArrayOf<VarData, HBUINT32>	dataSets;
1587 1588 1589 1590
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

1591 1592 1593 1594 1595 1596 1597 1598 1599
/*
 * Feature Variations
 */

struct ConditionFormat1
{
  friend struct Condition;

  private:
1600
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
  {
    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  protected:
B
Behdad Esfahbod 已提交
1613 1614
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1615 1616 1617 1618 1619 1620 1621 1622
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1623
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
  {
    switch (u.format) {
    case 1: return u.format1.evaluate (coords, coord_len);
    default:return false;
    }
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (!u.format.sanitize (c)) return_trace (false);
    switch (u.format) {
    case 1: return_trace (u.format1.sanitize (c));
    default:return_trace (true);
    }
  }

  protected:
  union {
B
Behdad Esfahbod 已提交
1643
  HBUINT16		format;		/* Format identifier */
1644 1645 1646 1647 1648 1649 1650 1651
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct ConditionSet
{
1652
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1653 1654 1655
  {
    unsigned int count = conditions.len;
    for (unsigned int i = 0; i < count; i++)
1656
      if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
        return false;
    return true;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, this));
  }

  protected:
B
Behdad Esfahbod 已提交
1668
  OffsetArrayOf<Condition, HBUINT32> conditions;
1669 1670 1671 1672 1673 1674
  public:
  DEFINE_SIZE_ARRAY (2, conditions);
};

struct FeatureTableSubstitutionRecord
{
1675
  friend struct FeatureTableSubstitution;
1676

1677
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1678 1679
  {
    TRACE_SANITIZE (this);
1680
    return_trace (c->check_struct (this) && feature.sanitize (c, base));
1681 1682 1683
  }

  protected:
B
Behdad Esfahbod 已提交
1684
  HBUINT16		featureIndex;
B
Behdad Esfahbod 已提交
1685
  LOffsetTo<Feature>	feature;
1686 1687 1688 1689 1690 1691
  public:
  DEFINE_SIZE_STATIC (6);
};

struct FeatureTableSubstitution
{
1692 1693 1694 1695 1696
  inline const Feature *find_substitute (unsigned int feature_index) const
  {
    unsigned int count = substitutions.len;
    for (unsigned int i = 0; i < count; i++)
    {
1697
      const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1698 1699
      if (record.featureIndex == feature_index)
	return &(this+record.feature);
1700
    }
B
Behdad Esfahbod 已提交
1701
    return nullptr;
1702 1703
  }

1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  substitutions.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
1714
  ArrayOf<FeatureTableSubstitutionRecord>
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
			substitutions;
  public:
  DEFINE_SIZE_ARRAY (6, substitutions);
};

struct FeatureVariationRecord
{
  friend struct FeatureVariations;

  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, base) &&
		  substitutions.sanitize (c, base));
  }

  protected:
B
Behdad Esfahbod 已提交
1732
  LOffsetTo<ConditionSet>
1733
			conditions;
B
Behdad Esfahbod 已提交
1734
  LOffsetTo<FeatureTableSubstitution>
1735 1736 1737 1738 1739 1740 1741
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct FeatureVariations
{
1742 1743
  static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;

1744 1745
  inline bool find_index (const int *coords, unsigned int coord_len,
			  unsigned int *index) const
1746 1747 1748 1749
  {
    unsigned int count = varRecords.len;
    for (unsigned int i = 0; i < count; i++)
    {
1750
      const FeatureVariationRecord &record = varRecords.arrayZ[i];
1751
      if ((this+record.conditions).evaluate (coords, coord_len))
1752 1753 1754 1755
      {
	*index = i;
	return true;
      }
1756
    }
1757
    *index = NOT_FOUND_INDEX;
1758
    return false;
1759 1760
  }

1761 1762 1763 1764 1765 1766 1767
  inline const Feature *find_substitute (unsigned int variations_index,
					 unsigned int feature_index) const
  {
    const FeatureVariationRecord &record = varRecords[variations_index];
    return (this+record.substitutions).find_substitute (feature_index);
  }

1768 1769 1770 1771 1772 1773
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    return_trace (c->serializer->embed (*this));
  }

1774 1775 1776 1777 1778 1779 1780 1781 1782 1783
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  varRecords.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
B
Behdad Esfahbod 已提交
1784
  LArrayOf<FeatureVariationRecord>
1785 1786
			varRecords;
  public:
1787
  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
1788 1789
};

1790

1791 1792 1793 1794
/*
 * Device Tables
 */

1795
struct HintingDevice
B
Behdad Esfahbod 已提交
1796
{
1797 1798 1799
  friend struct Device;

  private:
B
Behdad Esfahbod 已提交
1800

1801 1802
  inline hb_position_t get_x_delta (hb_font_t *font) const
  { return get_delta (font->x_ppem, font->x_scale); }
B
Behdad Esfahbod 已提交
1803

1804 1805
  inline hb_position_t get_y_delta (hb_font_t *font) const
  { return get_delta (font->y_ppem, font->y_scale); }
B
Behdad Esfahbod 已提交
1806

B
Minor  
Behdad Esfahbod 已提交
1807 1808 1809
  inline unsigned int get_size (void) const
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
1810 1811
    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size;
    return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
B
Minor  
Behdad Esfahbod 已提交
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
  }

  private:

1822
  inline int get_delta (unsigned int ppem, int scale) const
1823 1824 1825 1826 1827 1828 1829
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

B
Behdad Esfahbod 已提交
1830
    return (int) (pixels * (int64_t) scale / ppem);
1831 1832
  }
  inline int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
1833
  {
1834
    unsigned int f = deltaFormat;
1835
    if (unlikely (f < 1 || f > 3))
1836
      return 0;
1837

1838 1839
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
1840

1841
    unsigned int s = ppem_size - startSize;
1842

1843
    unsigned int byte = deltaValue[s >> (4 - f)];
B
Behdad Esfahbod 已提交
1844
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1845
    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1846 1847 1848

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
1849
    if ((unsigned int) delta >= ((mask + 1) >> 1))
1850 1851 1852 1853 1854
      delta -= mask + 1;

    return delta;
  }

1855
  protected:
B
Behdad Esfahbod 已提交
1856 1857 1858
  HBUINT16	startSize;		/* Smallest size to correct--in ppem */
  HBUINT16	endSize;		/* Largest size to correct--in ppem */
  HBUINT16	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
1859 1860 1861 1862
					 * 1	Signed 2-bit value, 8 values per uint16
					 * 2	Signed 4-bit value, 4 values per uint16
					 * 3	Signed 8-bit value, 2 values per uint16
					 */
B
Behdad Esfahbod 已提交
1863
  HBUINT16	deltaValue[VAR];	/* Array of compressed data */
B
Behdad Esfahbod 已提交
1864
  public:
1865
  DEFINE_SIZE_ARRAY (6, deltaValue);
1866 1867
};

1868 1869
struct VariationDevice
{
1870 1871 1872
  friend struct Device;

  private:
1873

1874
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1875
  { return font->em_scalef_x (get_delta (font, store)); }
1876

1877
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1878
  { return font->em_scalef_y (get_delta (font, store)); }
1879 1880 1881 1882

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
1883
    return_trace (c->check_struct (this));
1884 1885 1886 1887
  }

  private:

1888
  inline float get_delta (hb_font_t *font, const VariationStore &store) const
1889
  {
1890
    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1891 1892 1893
  }

  protected:
B
Behdad Esfahbod 已提交
1894 1895 1896
  HBUINT16	outerIndex;
  HBUINT16	innerIndex;
  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
1897
  public:
1898
  DEFINE_SIZE_STATIC (6);
1899 1900
};

1901 1902 1903
struct DeviceHeader
{
  protected:
B
Behdad Esfahbod 已提交
1904 1905
  HBUINT16		reserved1;
  HBUINT16		reserved2;
1906
  public:
B
Behdad Esfahbod 已提交
1907
  HBUINT16		format;		/* Format identifier */
1908 1909 1910 1911
  public:
  DEFINE_SIZE_STATIC (6);
};

1912 1913
struct Device
{
1914
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1915 1916 1917 1918 1919
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
1920
    case 0x8000:
1921
      return u.variation.get_x_delta (font, store);
1922 1923 1924 1925
    default:
      return 0;
    }
  }
1926
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1927 1928 1929 1930
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
1931
      return u.hinting.get_y_delta (font);
1932
    case 0x8000:
1933
      return u.variation.get_y_delta (font, store);
1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945
    default:
      return 0;
    }
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (!u.b.format.sanitize (c)) return_trace (false);
    switch (u.b.format) {
    case 1: case 2: case 3:
      return_trace (u.hinting.sanitize (c));
1946
    case 0x8000:
1947 1948 1949 1950 1951 1952 1953 1954
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

  protected:
  union {
1955
  DeviceHeader		b;
1956 1957 1958 1959 1960 1961 1962
  HintingDevice		hinting;
  VariationDevice	variation;
  } u;
  public:
  DEFINE_SIZE_UNION (6, b);
};

1963

B
Behdad Esfahbod 已提交
1964
} /* namespace OT */
1965

B
Behdad Esfahbod 已提交
1966

1967
#endif /* HB_OT_LAYOUT_COMMON_HH */