hb-ot-layout-common.hh 55.5 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
/*
 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
 */

73 74 75 76 77
struct Record_sanitize_closure_t {
  hb_tag_t tag;
  const void *list_base;
};

78
template <typename Type>
B
Behdad Esfahbod 已提交
79 80
struct Record
{
81
  inline int cmp (hb_tag_t a) const {
82
    return tag.cmp (a);
B
Behdad Esfahbod 已提交
83 84
  }

B
Behdad Esfahbod 已提交
85 86
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
87
    TRACE_SANITIZE (this);
88
    const Record_sanitize_closure_t closure = {tag, base};
B
Behdad Esfahbod 已提交
89
    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
B
Behdad Esfahbod 已提交
90 91
  }

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

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

template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
  inline const Type& operator [] (unsigned int i) const
139 140 141 142 143 144 145 146 147
  { 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++)
148
      out->get_offset (i).serialize_subset (c, (*this)[i], out);
149 150
    return_trace (true);
  }
B
Behdad Esfahbod 已提交
151

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


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

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

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

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

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


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

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


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


B
Behdad Esfahbod 已提交
216 217
struct LangSys
{
218 219 220 221
  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 已提交
222 223 224 225
  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); }
226 227
  inline void add_feature_indexes_to (hb_set_t *feature_indexes) const
  { featureIndex.add_indexes_to (feature_indexes); }
228

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

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

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

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

B
Behdad Esfahbod 已提交
261 262
struct Script
{
263 264 265 266
  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 已提交
267 268 269 270
  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 已提交
271 272
  inline const LangSys& get_lang_sys (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
273
    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
274 275
    return this+langSys[i].offset;
  }
276 277
  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
  { return langSys.find_index (tag, index); }
278

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

282 283 284 285 286
  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);
287
    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
288 289
    unsigned int count = langSys.len;
    for (unsigned int i = 0; i < count; i++)
290
      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
291 292 293
    return_trace (true);
  }

294
  inline bool sanitize (hb_sanitize_context_t *c,
295
			const Record_sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
296
  {
B
Behdad Esfahbod 已提交
297
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
298
    return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
B
Behdad Esfahbod 已提交
299 300
  }

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

typedef RecordListOf<Script> ScriptList;

314

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

    /* 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:
337
     * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
338 339 340 341 342 343
     *
     * 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 已提交
344
     * and make the following value checks. If it fails, assume the size
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 372
     * 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 已提交
373
      return_trace (false);
374 375 376 377
    else if (subfamilyID == 0 &&
	     subfamilyNameID == 0 &&
	     rangeStart == 0 &&
	     rangeEnd == 0)
B
Behdad Esfahbod 已提交
378
      return_trace (true);
379 380 381 382
    else if (designSize < rangeStart ||
	     designSize > rangeEnd ||
	     subfamilyNameID < 256 ||
	     subfamilyNameID > 32767)
B
Behdad Esfahbod 已提交
383
      return_trace (false);
384
    else
B
Behdad Esfahbod 已提交
385
      return_trace (true);
386 387
  }

B
Behdad Esfahbod 已提交
388
  HBUINT16	designSize;	/* Represents the design size in 720/inch
389 390 391 392
				 * 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 已提交
393
  HBUINT16	subfamilyID;	/* Has no independent meaning, but serves
394 395 396 397 398 399 400 401 402
				 * 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 已提交
403
  NameID	subfamilyNameID;/* If the preceding value is non-zero, this
404 405 406 407 408 409 410 411 412 413 414 415 416
				 * 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 已提交
417
  HBUINT16	rangeStart;	/* Large end of the recommended usage range
418 419
				 * (inclusive), stored in 720/inch units
				 * (decipoints). */
B
Behdad Esfahbod 已提交
420
  HBUINT16	rangeEnd;	/* Small end of the recommended usage range
421 422
				   (exclusive), stored in 720/inch units
				 * (decipoints). */
423 424 425 426
  public:
  DEFINE_SIZE_STATIC (10);
};

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

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

B
Behdad Esfahbod 已提交
443
  NameID	uiNameID;	/* The 'name' table name ID that specifies a
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
				 * 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);
};

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

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

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

524 525 526 527 528 529 530 531 532 533 534 535 536 537
  inline const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
  {
    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
      return u.stylisticSet;
    return Null(FeatureParamsStylisticSet);
  }

  inline const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
  {
    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
      return u.characterVariants;
    return Null(FeatureParamsCharacterVariants);
  }

538
  private:
539
  union {
540 541 542
  FeatureParamsSize			size;
  FeatureParamsStylisticSet		stylisticSet;
  FeatureParamsCharacterVariants	characterVariants;
543
  } u;
544
  public:
545
  DEFINE_SIZE_STATIC (17);
546
};
547

B
Behdad Esfahbod 已提交
548 549
struct Feature
{
550 551 552 553
  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 已提交
554 555 556 557
  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); }
558 559
  inline void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
  { lookupIndex.add_indexes_to (lookup_indexes); }
560

561 562 563
  inline const FeatureParams &get_feature_params (void) const
  { return this+featureParams; }

564 565 566 567 568 569 570 571 572
  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);
  }

573
  inline bool sanitize (hb_sanitize_context_t *c,
574
			const Record_sanitize_closure_t *closure = nullptr) const
B
Behdad Esfahbod 已提交
575
  {
B
Behdad Esfahbod 已提交
576
    TRACE_SANITIZE (this);
577
    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
B
Behdad Esfahbod 已提交
578
      return_trace (false);
579

580 581 582 583 584 585
    /* 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.
586 587 588
     *
     * Only do this for the 'size' feature, since at the time of the faulty
     * Adobe tools, only the 'size' feature had FeatureParams defined.
589 590
     */

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

595
    if (likely (orig_offset.is_null ()))
B
Behdad Esfahbod 已提交
596
      return_trace (true);
597

598 599 600
    if (featureParams == 0 && closure &&
	closure->tag == HB_TAG ('s','i','z','e') &&
	closure->list_base && closure->list_base < this)
601
    {
602
      unsigned int new_offset_int = (unsigned int) orig_offset -
B
Behdad Esfahbod 已提交
603
				    (((char *) this) - ((char *) closure->list_base));
604

B
Behdad Esfahbod 已提交
605
      OffsetTo<FeatureParams> new_offset;
606
      /* Check that it did not overflow. */
607 608
      new_offset.set (new_offset_int);
      if (new_offset == new_offset_int &&
609
	  c->try_set (&featureParams, new_offset) &&
610
	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
B
Behdad Esfahbod 已提交
611
	return_trace (false);
612 613
    }

B
Behdad Esfahbod 已提交
614
    return_trace (true);
B
Behdad Esfahbod 已提交
615 616
  }

617 618
  OffsetTo<FeatureParams>
		 featureParams;	/* Offset to Feature Parameters table (if one
619 620 621
				 * has been defined for the feature), relative
				 * to the beginning of the Feature Table; = Null
				 * if not required */
622
  IndexArray	 lookupIndex;	/* Array of LookupList indices */
623
  public:
624
  DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
625 626 627 628 629
};

typedef RecordListOf<Feature> FeatureList;


B
Behdad Esfahbod 已提交
630
struct LookupFlag : HBUINT16
B
Behdad Esfahbod 已提交
631
{
B
Behdad Esfahbod 已提交
632
  enum Flags {
B
Behdad Esfahbod 已提交
633 634 635 636
    RightToLeft		= 0x0001u,
    IgnoreBaseGlyphs	= 0x0002u,
    IgnoreLigatures	= 0x0004u,
    IgnoreMarks		= 0x0008u,
B
Behdad Esfahbod 已提交
637
    IgnoreFlags		= 0x000Eu,
638 639
    UseMarkFilteringSet	= 0x0010u,
    Reserved		= 0x00E0u,
640
    MarkAttachmentType	= 0xFF00u
B
Behdad Esfahbod 已提交
641
  };
642 643
  public:
  DEFINE_SIZE_STATIC (2);
644 645
};

B
Behdad Esfahbod 已提交
646 647
} /* namespace OT */
/* This has to be outside the namespace. */
C
Chun-wei Fan 已提交
648
HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
B
Behdad Esfahbod 已提交
649 650
namespace OT {

B
Behdad Esfahbod 已提交
651 652 653
struct Lookup
{
  inline unsigned int get_subtable_count (void) const { return subTable.len; }
654

B
Behdad Esfahbod 已提交
655 656 657
  template <typename TSubTable>
  inline const TSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
658

B
Behdad Esfahbod 已提交
659 660 661 662 663 664
  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); }
665

666 667 668 669 670 671 672 673
  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;
  }

674
  inline unsigned int get_type (void) const { return lookupType; }
675 676 677 678 679

  /* 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
680 681
  {
    unsigned int flag = lookupFlag;
682
    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
683
    {
B
Behdad Esfahbod 已提交
684
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
685
      flag += (markFilteringSet << 16);
686 687 688
    }
    return flag;
  }
689

B
Behdad Esfahbod 已提交
690
  template <typename TSubTable, typename context_t>
691 692 693 694 695 696
  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 已提交
697
      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
698
      if (c->stop_sublookup_iteration (r))
B
Behdad Esfahbod 已提交
699
        return_trace (r);
700
    }
B
Behdad Esfahbod 已提交
701
    return_trace (c->default_return_value ());
702 703
  }

704 705 706 707 708
  inline bool serialize (hb_serialize_context_t *c,
			 unsigned int lookup_type,
			 uint32_t lookup_props,
			 unsigned int num_subtables)
  {
B
Behdad Esfahbod 已提交
709
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
710
    if (unlikely (!c->extend_min (*this))) return_trace (false);
711
    lookupType.set (lookup_type);
712
    lookupFlag.set (lookup_props & 0xFFFFu);
B
Behdad Esfahbod 已提交
713
    if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
714
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
715
    {
716
      if (unlikely (!c->extend (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
717
      HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
718 719
      markFilteringSet.set (lookup_props >> 16);
    }
B
Behdad Esfahbod 已提交
720
    return_trace (true);
721 722
  }

B
Bruce Mitchener 已提交
723
  /* Older compilers need this to NOT be locally defined in a function. */
B
Behdad Esfahbod 已提交
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
  template <typename TSubTable>
  struct SubTableSubsetWrapper
  {
    inline SubTableSubsetWrapper (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;
  };

740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
  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++)
    {
B
Behdad Esfahbod 已提交
755
      SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
756 757 758 759 760 761 762

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

    return_trace (true);
  }

B
Behdad Esfahbod 已提交
763
  template <typename TSubTable>
B
Behdad Esfahbod 已提交
764 765
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
766
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
767
    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
768
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
769
    {
B
Behdad Esfahbod 已提交
770
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
771
      if (!markFilteringSet.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
772
    }
B
Behdad Esfahbod 已提交
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788

    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 已提交
789
    return_trace (true);
B
Behdad Esfahbod 已提交
790 791
  }

792
  private:
B
Behdad Esfahbod 已提交
793 794
  HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
  HBUINT16	lookupFlag;		/* Lookup qualifiers */
B
Behdad Esfahbod 已提交
795
  ArrayOf<Offset16>
796
		subTable;		/* Array of SubTables */
B
Behdad Esfahbod 已提交
797
  HBUINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
798 799
					 * structure. This field is only present if bit
					 * UseMarkFilteringSet of lookup flags is set. */
B
Behdad Esfahbod 已提交
800
  public:
801
  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
802 803 804 805 806 807 808 809 810
};

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
811 812
struct CoverageFormat1
{
813 814 815
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
816 817
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
818
    int i = glyphArray.bsearch (glyph_id);
819
    static_assert ((((unsigned int) -1) == NOT_COVERED), "");
B
Minor  
Behdad Esfahbod 已提交
820
    return i;
821 822
  }

823
  inline bool serialize (hb_serialize_context_t *c,
824
			 Supplier<GlyphID> &glyphs,
825
			 unsigned int num_glyphs)
826
  {
B
Behdad Esfahbod 已提交
827
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
828
    if (unlikely (!c->extend_min (*this))) return_trace (false);
829
    glyphArray.len.set (num_glyphs);
B
Behdad Esfahbod 已提交
830
    if (unlikely (!c->extend (glyphArray))) return_trace (false);
831
    for (unsigned int i = 0; i < num_glyphs; i++)
832
      glyphArray[i] = glyphs[i];
833
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
834
    return_trace (true);
835 836
  }

B
Behdad Esfahbod 已提交
837 838
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
839
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
840
    return_trace (glyphArray.sanitize (c));
B
Behdad Esfahbod 已提交
841 842
  }

843 844 845 846 847 848 849 850
  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;
851
  }
852 853
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  { return glyphs->has (glyphArray[index]); }
854

855
  template <typename set_t>
B
Behdad Esfahbod 已提交
856
  inline bool add_coverage (set_t *glyphs) const {
857
    return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
858 859
  }

B
Behdad Esfahbod 已提交
860 861
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
862
  struct Iter {
863 864
    inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
    inline void fini (void) {}
B
Behdad Esfahbod 已提交
865 866
    inline bool more (void) { return i < c->glyphArray.len; }
    inline void next (void) { i++; }
867 868
    inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
    inline unsigned int get_coverage (void) { return i; }
B
Behdad Esfahbod 已提交
869 870 871 872 873

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

876
  protected:
B
Behdad Esfahbod 已提交
877
  HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
878
  SortedArrayOf<GlyphID>
879
		glyphArray;	/* Array of GlyphIDs--in numerical order */
880
  public:
881
  DEFINE_SIZE_ARRAY (4, glyphArray);
882 883
};

B
Behdad Esfahbod 已提交
884 885
struct CoverageFormat2
{
886 887 888
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
889 890
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
891
    int i = rangeRecord.bsearch (glyph_id);
B
Behdad Esfahbod 已提交
892 893 894
    if (i != -1) {
      const RangeRecord &range = rangeRecord[i];
      return (unsigned int) range.value + (glyph_id - range.start);
895 896 897 898
    }
    return NOT_COVERED;
  }

899
  inline bool serialize (hb_serialize_context_t *c,
900
			 Supplier<GlyphID> &glyphs,
901
			 unsigned int num_glyphs)
902
  {
B
Behdad Esfahbod 已提交
903
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
904
    if (unlikely (!c->extend_min (*this))) return_trace (false);
905

906 907 908 909 910
    if (unlikely (!num_glyphs))
    {
      rangeRecord.len.set (0);
      return_trace (true);
    }
911

912 913 914 915
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
916
    rangeRecord.len.set (num_ranges);
B
Behdad Esfahbod 已提交
917
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
918

919
    unsigned int range = 0;
920
    rangeRecord[range].start = glyphs[0];
921
    rangeRecord[range].value.set (0);
922 923 924
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i]) {
	range++;
925 926 927
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value.set (i);
        rangeRecord[range].end = glyphs[i];
928
      } else {
929
        rangeRecord[range].end = glyphs[i];
930
      }
931
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
932
    return_trace (true);
933 934
  }

B
Behdad Esfahbod 已提交
935 936
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
937
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
938
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
939 940
  }

941 942 943 944 945 946 947 948 949 950 951
  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
  {
952 953 954 955 956
    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 已提交
957
	  index < (unsigned int) range.value + (range.end - range.start) &&
958 959 960 961 962 963 964 965
	  range.intersects (glyphs))
        return true;
      else if (index < range.value)
        return false;
    }
    return false;
  }

966
  template <typename set_t>
B
Behdad Esfahbod 已提交
967
  inline bool add_coverage (set_t *glyphs) const {
968 969
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
970
      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
971
        return false;
B
Behdad Esfahbod 已提交
972
    return true;
973 974
  }

B
Behdad Esfahbod 已提交
975 976
  public:
  /* Older compilers need this to be public. */
977 978 979 980
  struct Iter
  {
    inline void init (const CoverageFormat2 &c_)
    {
B
Behdad Esfahbod 已提交
981 982 983
      c = &c_;
      coverage = 0;
      i = 0;
984 985 986 987 988 989
      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 已提交
990
    }
991
    inline void fini (void) {}
B
Behdad Esfahbod 已提交
992
    inline bool more (void) { return i < c->rangeRecord.len; }
993 994 995 996
    inline void next (void)
    {
      if (j >= c->rangeRecord[i].end)
      {
B
Behdad Esfahbod 已提交
997
        i++;
B
Behdad Esfahbod 已提交
998
	if (more ())
999
	{
1000
	  hb_codepoint_t old = j;
B
Behdad Esfahbod 已提交
1001
	  j = c->rangeRecord[i].start;
1002 1003 1004 1005 1006 1007
	  if (unlikely (j <= old))
	  {
	    /* Broken table. Skip. Important to avoid DoS. */
	   i = c->rangeRecord.len;
	   return;
	  }
1008 1009
	  coverage = c->rangeRecord[i].value;
	}
B
Behdad Esfahbod 已提交
1010
	return;
B
Behdad Esfahbod 已提交
1011
      }
1012
      coverage++;
B
Behdad Esfahbod 已提交
1013 1014
      j++;
    }
1015 1016
    inline hb_codepoint_t get_glyph (void) { return j; }
    inline unsigned int get_coverage (void) { return coverage; }
B
Behdad Esfahbod 已提交
1017 1018 1019

    private:
    const struct CoverageFormat2 *c;
1020 1021
    unsigned int i, coverage;
    hb_codepoint_t j;
B
Behdad Esfahbod 已提交
1022
  };
B
Behdad Esfahbod 已提交
1023
  private:
B
Behdad Esfahbod 已提交
1024

1025
  protected:
B
Behdad Esfahbod 已提交
1026
  HBUINT16	coverageFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1027
  SortedArrayOf<RangeRecord>
1028 1029 1030
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID. rangeCount entries
				 * long */
1031
  public:
1032
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1033 1034
};

B
Behdad Esfahbod 已提交
1035 1036
struct Coverage
{
B
Behdad Esfahbod 已提交
1037
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1038
  {
1039
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1040 1041
    case 1: return u.format1.get_coverage (glyph_id);
    case 2: return u.format2.get_coverage (glyph_id);
1042 1043 1044 1045
    default:return NOT_COVERED;
    }
  }

1046
  inline bool serialize (hb_serialize_context_t *c,
1047
			 Supplier<GlyphID> &glyphs,
1048
			 unsigned int num_glyphs)
1049
  {
B
Behdad Esfahbod 已提交
1050
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1051
    if (unlikely (!c->extend_min (*this))) return_trace (false);
1052 1053 1054 1055
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
1056
    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
1057 1058
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1059 1060 1061
    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);
1062 1063 1064
    }
  }

B
Behdad Esfahbod 已提交
1065 1066
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1067
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1068
    if (!u.format.sanitize (c)) return_trace (false);
1069 1070
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1071 1072 1073
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1074 1075
    }
  }
1076

1077 1078
  inline bool intersects (const hb_set_t *glyphs) const
  {
1079 1080 1081 1082 1083 1084
    switch (u.format)
    {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
1085
  }
1086 1087 1088 1089
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  {
    switch (u.format)
    {
1090 1091 1092 1093
    case 1: return u.format1.intersects_coverage (glyphs, index);
    case 2: return u.format2.intersects_coverage (glyphs, index);
    default:return false;
    }
B
Behdad Esfahbod 已提交
1094 1095
  }

B
Behdad Esfahbod 已提交
1096 1097
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
1098
  template <typename set_t>
1099 1100 1101 1102
  inline bool add_coverage (set_t *glyphs) const
  {
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1103 1104
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1105
    default:return false;
1106 1107 1108
    }
  }

1109 1110
  struct Iter
  {
1111
    inline Iter (const Coverage &c_)
1112
    {
1113
      memset (this, 0, sizeof (*this));
B
Behdad Esfahbod 已提交
1114
      format = c_.u.format;
1115 1116
      switch (format)
      {
B
Minor  
Behdad Esfahbod 已提交
1117 1118
      case 1: u.format1.init (c_.u.format1); return;
      case 2: u.format2.init (c_.u.format2); return;
1119
      default:				     return;
B
Behdad Esfahbod 已提交
1120 1121
      }
    }
1122 1123 1124 1125
    inline bool more (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1126 1127
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
1128
      default:return false;
B
Behdad Esfahbod 已提交
1129 1130
      }
    }
1131 1132 1133 1134
    inline void next (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1135 1136
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
1137
      default:			 break;
B
Behdad Esfahbod 已提交
1138 1139
      }
    }
1140 1141 1142 1143
    inline hb_codepoint_t get_glyph (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1144 1145
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
1146
      default:return 0;
B
Behdad Esfahbod 已提交
1147 1148
      }
    }
1149 1150 1151 1152
    inline unsigned int get_coverage (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1153 1154
      case 1: return u.format1.get_coverage ();
      case 2: return u.format2.get_coverage ();
B
Minor  
Behdad Esfahbod 已提交
1155
      default:return -1;
B
Behdad Esfahbod 已提交
1156 1157 1158 1159
      }
    }

    private:
B
Behdad Esfahbod 已提交
1160
    unsigned int format;
B
Behdad Esfahbod 已提交
1161
    union {
1162
    CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
B
Behdad Esfahbod 已提交
1163 1164 1165 1166
    CoverageFormat1::Iter	format1;
    } u;
  };

1167
  protected:
1168
  union {
B
Behdad Esfahbod 已提交
1169
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1170 1171
  CoverageFormat1	format1;
  CoverageFormat2	format2;
1172
  } u;
B
Behdad Esfahbod 已提交
1173
  public:
B
Behdad Esfahbod 已提交
1174
  DEFINE_SIZE_UNION (2, format);
1175 1176 1177 1178 1179 1180 1181
};


/*
 * Class Definition Table
 */

B
Behdad Esfahbod 已提交
1182 1183
struct ClassDefFormat1
{
1184 1185 1186
  friend struct ClassDef;

  private:
1187
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1188
  {
B
Minor  
Behdad Esfahbod 已提交
1189 1190 1191
    unsigned int i = (unsigned int) (glyph_id - startGlyph);
    if (unlikely (i < classValue.len))
      return classValue[i];
1192 1193 1194
    return 0;
  }

B
Behdad Esfahbod 已提交
1195 1196
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1197
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1198
    return_trace (c->check_struct (this) && classValue.sanitize (c));
B
Behdad Esfahbod 已提交
1199 1200
  }

1201
  template <typename set_t>
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
  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)))
1212
	  return false;
1213 1214 1215 1216 1217

      start = i + 1;
    }
    if (start != count)
      if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1218
	return false;
1219 1220 1221 1222 1223 1224

    return true;
  }

  template <typename set_t>
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1225 1226
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1227
    {
1228
      if (classValue[i] == klass)
1229
        glyphs->add (startGlyph + i);
B
Behdad Esfahbod 已提交
1230 1231
    }
    return true;
1232 1233
  }

1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
  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;
  }
1245
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1246
    unsigned int count = classValue.len;
1247 1248 1249
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1250
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1251 1252 1253 1254 1255 1256 1257 1258 1259
      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. */
    }
1260 1261 1262 1263 1264 1265
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass && glyphs->has (startGlyph + i))
        return true;
    return false;
  }

1266
  protected:
B
Behdad Esfahbod 已提交
1267
  HBUINT16	classFormat;		/* Format identifier--format = 1 */
1268
  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
B
Behdad Esfahbod 已提交
1269
  ArrayOf<HBUINT16>
1270
		classValue;		/* Array of Class Values--one per GlyphID */
1271
  public:
1272
  DEFINE_SIZE_ARRAY (6, classValue);
1273 1274
};

B
Behdad Esfahbod 已提交
1275 1276
struct ClassDefFormat2
{
1277 1278 1279
  friend struct ClassDef;

  private:
1280
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1281
  {
1282
    int i = rangeRecord.bsearch (glyph_id);
B
Minor  
Behdad Esfahbod 已提交
1283
    if (unlikely (i != -1))
B
Behdad Esfahbod 已提交
1284
      return rangeRecord[i].value;
1285 1286 1287
    return 0;
  }

B
Behdad Esfahbod 已提交
1288 1289
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1290
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1291
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
1292 1293
  }

1294
  template <typename set_t>
1295 1296
  inline bool add_coverage (set_t *glyphs) const
  {
1297 1298 1299 1300
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value)
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1301
	  return false;
1302 1303 1304 1305
    return true;
  }

  template <typename set_t>
1306 1307
  inline bool add_class (set_t *glyphs, unsigned int klass) const
  {
1308 1309
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1310
    {
1311
      if (rangeRecord[i].value == klass)
B
Behdad Esfahbod 已提交
1312
        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1313
	  return false;
B
Behdad Esfahbod 已提交
1314 1315
    }
    return true;
1316 1317
  }

1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
  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
  {
1329
    unsigned int count = rangeRecord.len;
1330 1331 1332
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1333
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1334 1335 1336 1337 1338 1339 1340 1341
      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;
      }
1342
      if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1343 1344 1345
        return true;
      /* Fall through. */
    }
1346 1347 1348 1349 1350 1351
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }

1352
  protected:
B
Behdad Esfahbod 已提交
1353
  HBUINT16	classFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1354
  SortedArrayOf<RangeRecord>
1355 1356
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID */
1357
  public:
1358
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1359 1360
};

B
Behdad Esfahbod 已提交
1361 1362
struct ClassDef
{
1363
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1364
  {
1365
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1366 1367
    case 1: return u.format1.get_class (glyph_id);
    case 2: return u.format2.get_class (glyph_id);
1368 1369 1370 1371
    default:return 0;
    }
  }

B
Behdad Esfahbod 已提交
1372 1373
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1374
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1375
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
1376
    switch (u.format) {
B
Behdad Esfahbod 已提交
1377 1378 1379
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1380 1381
    }
  }
1382

1383 1384 1385 1386 1387 1388 1389
  /* 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);
1390
    default:return false;
1391 1392 1393 1394 1395
    }
  }

  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
B
Behdad Esfahbod 已提交
1396
  template <typename set_t>
1397
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1398
    switch (u.format) {
1399 1400
    case 1: return u.format1.add_class (glyphs, klass);
    case 2: return u.format2.add_class (glyphs, klass);
B
Behdad Esfahbod 已提交
1401
    default:return false;
1402 1403 1404
    }
  }

1405 1406 1407 1408 1409 1410 1411
  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;
    }
  }
1412
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1413 1414 1415 1416 1417 1418 1419
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1420
  protected:
1421
  union {
B
Behdad Esfahbod 已提交
1422
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1423 1424
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1425
  } u;
B
Behdad Esfahbod 已提交
1426
  public:
B
Behdad Esfahbod 已提交
1427
  DEFINE_SIZE_UNION (2, format);
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 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
/*
 * 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,
B
Bruce Mitchener 已提交
1479
			 const int *coords, unsigned int coord_len) const
1480 1481 1482 1483
  {
    if (unlikely (region_index >= regionCount))
      return 0.;

1484
    const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1485 1486

    float v = 1.;
1487
    unsigned int count = axisCount;
1488 1489
    for (unsigned int i = 0; i < count; i++)
    {
1490 1491
      int coord = i < coord_len ? coords[i] : 0;
      float factor = axes[i].evaluate (coord);
1492
      if (factor == 0.f)
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
        return 0.;
      v *= factor;
    }
    return v;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
1503
		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1504 1505 1506
  }

  protected:
B
Behdad Esfahbod 已提交
1507 1508
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1509 1510
  UnsizedArrayOf<VarRegionAxis>
		axesZ;
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523
  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,
B
Bruce Mitchener 已提交
1524
			  const int *coords, unsigned int coord_count,
1525 1526 1527 1528 1529 1530 1531 1532
			  const VarRegionList &regions) const
  {
    if (unlikely (inner >= itemCount))
      return 0.;

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

B
Behdad Esfahbod 已提交
1533 1534
   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
   const HBUINT8 *row = bytes + inner * (scount + count);
1535 1536 1537 1538

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

B
Behdad Esfahbod 已提交
1539
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1540 1541
   for (; i < scount; i++)
   {
1542
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1543 1544
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1545
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1546 1547
   for (; i < count; i++)
   {
1548
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
     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 已提交
1561
		  c->check_array (&StructAfter<HBUINT8> (regionIndices),
1562
				  itemCount, get_row_size ()));
1563 1564 1565
  }

  protected:
B
Behdad Esfahbod 已提交
1566 1567 1568
  HBUINT16		itemCount;
  HBUINT16		shortCount;
  ArrayOf<HBUINT16>	regionIndices;
1569
  UnsizedArrayOf<HBUINT8>bytesX;
1570 1571 1572 1573
  public:
  DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
};

1574
struct VariationStore
1575 1576
{
  inline float get_delta (unsigned int outer, unsigned int inner,
B
Bruce Mitchener 已提交
1577
			  const int *coords, unsigned int coord_count) const
1578 1579 1580 1581 1582 1583 1584 1585 1586
  {
    if (unlikely (outer >= dataSets.len))
      return 0.;

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

1587
  inline float get_delta (unsigned int index,
B
Bruce Mitchener 已提交
1588
			  const int *coords, unsigned int coord_count) const
1589 1590 1591 1592 1593 1594
  {
    unsigned int outer = index >> 16;
    unsigned int inner = index & 0xFFFF;
    return get_delta (outer, inner, coords, coord_count);
  }

1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
  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 已提交
1605
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1606
  LOffsetTo<VarRegionList>		regions;
B
Minor  
Behdad Esfahbod 已提交
1607
  LOffsetArrayOf<VarData>		dataSets;
1608 1609 1610 1611
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

1612 1613 1614 1615 1616 1617 1618 1619 1620
/*
 * Feature Variations
 */

struct ConditionFormat1
{
  friend struct Condition;

  private:
1621
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633
  {
    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 已提交
1634 1635
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1636 1637 1638 1639 1640 1641 1642 1643
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1644
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663
  {
    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 已提交
1664
  HBUINT16		format;		/* Format identifier */
1665 1666 1667 1668 1669 1670 1671 1672
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct ConditionSet
{
1673
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1674 1675 1676
  {
    unsigned int count = conditions.len;
    for (unsigned int i = 0; i < count; i++)
1677
      if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
        return false;
    return true;
  }

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

  protected:
B
Minor  
Behdad Esfahbod 已提交
1689
  LOffsetArrayOf<Condition>	conditions;
1690 1691 1692 1693 1694 1695
  public:
  DEFINE_SIZE_ARRAY (2, conditions);
};

struct FeatureTableSubstitutionRecord
{
1696
  friend struct FeatureTableSubstitution;
1697

1698
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1699 1700
  {
    TRACE_SANITIZE (this);
1701
    return_trace (c->check_struct (this) && feature.sanitize (c, base));
1702 1703 1704
  }

  protected:
B
Behdad Esfahbod 已提交
1705
  HBUINT16		featureIndex;
B
Behdad Esfahbod 已提交
1706
  LOffsetTo<Feature>	feature;
1707 1708 1709 1710 1711 1712
  public:
  DEFINE_SIZE_STATIC (6);
};

struct FeatureTableSubstitution
{
1713 1714 1715 1716 1717
  inline const Feature *find_substitute (unsigned int feature_index) const
  {
    unsigned int count = substitutions.len;
    for (unsigned int i = 0; i < count; i++)
    {
1718
      const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1719 1720
      if (record.featureIndex == feature_index)
	return &(this+record.feature);
1721
    }
B
Behdad Esfahbod 已提交
1722
    return nullptr;
1723 1724
  }

1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
  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 */
1735
  ArrayOf<FeatureTableSubstitutionRecord>
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
			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 已提交
1753
  LOffsetTo<ConditionSet>
1754
			conditions;
B
Behdad Esfahbod 已提交
1755
  LOffsetTo<FeatureTableSubstitution>
1756 1757 1758 1759 1760 1761 1762
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct FeatureVariations
{
1763
  enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
1764

1765 1766
  inline bool find_index (const int *coords, unsigned int coord_len,
			  unsigned int *index) const
1767 1768 1769 1770
  {
    unsigned int count = varRecords.len;
    for (unsigned int i = 0; i < count; i++)
    {
1771
      const FeatureVariationRecord &record = varRecords.arrayZ[i];
1772
      if ((this+record.conditions).evaluate (coords, coord_len))
1773 1774 1775 1776
      {
	*index = i;
	return true;
      }
1777
    }
1778
    *index = NOT_FOUND_INDEX;
1779
    return false;
1780 1781
  }

1782 1783 1784 1785 1786 1787 1788
  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);
  }

1789 1790 1791 1792 1793 1794
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    return_trace (c->serializer->embed (*this));
  }

1795 1796 1797 1798 1799 1800 1801 1802 1803 1804
  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 已提交
1805
  LArrayOf<FeatureVariationRecord>
1806 1807
			varRecords;
  public:
1808
  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
1809 1810
};

1811

1812 1813 1814 1815
/*
 * Device Tables
 */

1816
struct HintingDevice
B
Behdad Esfahbod 已提交
1817
{
1818 1819 1820
  friend struct Device;

  private:
B
Behdad Esfahbod 已提交
1821

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

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

B
Minor  
Behdad Esfahbod 已提交
1828 1829 1830
  inline unsigned int get_size (void) const
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
1831 1832
    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 已提交
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
  }

  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:

1843
  inline int get_delta (unsigned int ppem, int scale) const
1844 1845 1846 1847 1848 1849 1850
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

B
Behdad Esfahbod 已提交
1851
    return (int) (pixels * (int64_t) scale / ppem);
1852 1853
  }
  inline int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
1854
  {
1855
    unsigned int f = deltaFormat;
1856
    if (unlikely (f < 1 || f > 3))
1857
      return 0;
1858

1859 1860
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
1861

1862
    unsigned int s = ppem_size - startSize;
1863

1864
    unsigned int byte = deltaValueZ[s >> (4 - f)];
B
Behdad Esfahbod 已提交
1865
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1866
    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1867 1868 1869

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
1870
    if ((unsigned int) delta >= ((mask + 1) >> 1))
1871 1872 1873 1874 1875
      delta -= mask + 1;

    return delta;
  }

1876
  protected:
B
Behdad Esfahbod 已提交
1877 1878 1879
  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
1880 1881 1882 1883
					 * 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
					 */
1884 1885
  UnsizedArrayOf<HBUINT16>
		deltaValueZ;		/* Array of compressed data */
B
Behdad Esfahbod 已提交
1886
  public:
1887
  DEFINE_SIZE_ARRAY (6, deltaValueZ);
1888 1889
};

1890 1891
struct VariationDevice
{
1892 1893 1894
  friend struct Device;

  private:
1895

1896
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1897
  { return font->em_scalef_x (get_delta (font, store)); }
1898

1899
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1900
  { return font->em_scalef_y (get_delta (font, store)); }
1901 1902 1903 1904

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
1905
    return_trace (c->check_struct (this));
1906 1907 1908 1909
  }

  private:

1910
  inline float get_delta (hb_font_t *font, const VariationStore &store) const
1911
  {
1912
    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1913 1914 1915
  }

  protected:
B
Behdad Esfahbod 已提交
1916 1917 1918
  HBUINT16	outerIndex;
  HBUINT16	innerIndex;
  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
1919
  public:
1920
  DEFINE_SIZE_STATIC (6);
1921 1922
};

1923 1924 1925
struct DeviceHeader
{
  protected:
B
Behdad Esfahbod 已提交
1926 1927
  HBUINT16		reserved1;
  HBUINT16		reserved2;
1928
  public:
B
Behdad Esfahbod 已提交
1929
  HBUINT16		format;		/* Format identifier */
1930 1931 1932 1933
  public:
  DEFINE_SIZE_STATIC (6);
};

1934 1935
struct Device
{
1936
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1937 1938 1939 1940 1941
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
1942
    case 0x8000:
1943
      return u.variation.get_x_delta (font, store);
1944 1945 1946 1947
    default:
      return 0;
    }
  }
1948
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1949 1950 1951 1952
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
1953
      return u.hinting.get_y_delta (font);
1954
    case 0x8000:
1955
      return u.variation.get_y_delta (font, store);
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
    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));
1968
    case 0x8000:
1969 1970 1971 1972 1973 1974 1975 1976
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

  protected:
  union {
1977
  DeviceHeader		b;
1978 1979 1980 1981 1982 1983 1984
  HintingDevice		hinting;
  VariationDevice	variation;
  } u;
  public:
  DEFINE_SIZE_UNION (6, b);
};

1985

B
Behdad Esfahbod 已提交
1986
} /* namespace OT */
1987

B
Behdad Esfahbod 已提交
1988

1989
#endif /* HB_OT_LAYOUT_COMMON_HH */