hb-ot-layout-common.hh 60.7 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 58 59 60 61
#ifndef HB_MAX_SCRIPTS
#define HB_MAX_SCRIPTS	500
#endif

#ifndef HB_MAX_LANGSYS
#define HB_MAX_LANGSYS	2000
#endif

62

63 64 65
namespace OT {


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

B
Behdad Esfahbod 已提交
68

69 70 71 72 73 74
/*
 *
 * OpenType Layout Common Table Formats
 *
 */

75

76 77 78 79
/*
 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
 */

80 81 82 83 84
struct Record_sanitize_closure_t {
  hb_tag_t tag;
  const void *list_base;
};

85
template <typename Type>
B
Behdad Esfahbod 已提交
86 87
struct Record
{
88
  int cmp (hb_tag_t a) const { return tag.cmp (a); }
B
Behdad Esfahbod 已提交
89

90
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
B
Behdad Esfahbod 已提交
91
  {
B
Behdad Esfahbod 已提交
92
    TRACE_SANITIZE (this);
93
    const Record_sanitize_closure_t closure = {tag, base};
B
Behdad Esfahbod 已提交
94
    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
B
Behdad Esfahbod 已提交
95 96
  }

97 98 99 100
  Tag		tag;		/* 4-byte Tag identifier */
  OffsetTo<Type>
		offset;		/* Offset from beginning of object holding
				 * the Record */
B
Behdad Esfahbod 已提交
101 102
  public:
  DEFINE_SIZE_STATIC (6);
103 104 105
};

template <typename Type>
106
struct RecordArrayOf : SortedArrayOf<Record<Type>>
107
{
108
  const OffsetTo<Type>& get_offset (unsigned int i) const
109
  { return (*this)[i].offset; }
110
  OffsetTo<Type>& get_offset (unsigned int i)
111
  { return (*this)[i].offset; }
112
  const Tag& get_tag (unsigned int i) const
113
  { return (*this)[i].tag; }
114 115 116
  unsigned int get_tags (unsigned int start_offset,
			 unsigned int *record_count /* IN/OUT */,
			 hb_tag_t     *record_tags /* OUT */) const
117
  {
B
Behdad Esfahbod 已提交
118
    if (record_count) {
B
Behdad Esfahbod 已提交
119
      const Record<Type> *arr = this->sub_array (start_offset, record_count);
B
Behdad Esfahbod 已提交
120
      unsigned int count = *record_count;
B
Behdad Esfahbod 已提交
121
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
122
	record_tags[i] = arr[i].tag;
B
Behdad Esfahbod 已提交
123 124
    }
    return this->len;
125
  }
126
  bool find_index (hb_tag_t tag, unsigned int *index) const
127
  {
128
    return this->bfind (tag, index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
129 130 131 132 133 134
  }
};

template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
135
  const Type& operator [] (unsigned int i) const
136 137
  { return this+this->get_offset (i); }

138
  bool subset (hb_subset_context_t *c) const
139 140 141 142 143 144
  {
    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++)
145
      out->get_offset (i).serialize_subset (c, (*this)[i], out);
146 147
    return_trace (true);
  }
B
Behdad Esfahbod 已提交
148

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


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

162
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
163
  {
B
Behdad Esfahbod 已提交
164
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
165
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
166 167
  }

168
  bool intersects (const hb_set_t *glyphs) const
169
  { return glyphs->intersects (start, end); }
170

171
  template <typename set_t>
172 173
  bool add_coverage (set_t *glyphs) const
  { return glyphs->add_range (start, end); }
174

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


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

199
  void add_indexes_to (hb_set_t* output /* OUT */) const
200 201 202
  {
    output->add_array (arrayZ, len);
  }
203 204 205
};


206 207 208 209 210
struct Script;
struct LangSys;
struct Feature;


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

224 225
  bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; }
  unsigned int get_required_feature_index () const
B
Behdad Esfahbod 已提交
226
  {
227
    if (reqFeatureIndex == 0xFFFFu)
B
Behdad Esfahbod 已提交
228
      return Index::NOT_FOUND_INDEX;
229 230 231
   return reqFeatureIndex;;
  }

232
  bool subset (hb_subset_context_t *c) const
233 234 235 236 237
  {
    TRACE_SUBSET (this);
    return_trace (c->serializer->embed (*this));
  }

238 239
  bool sanitize (hb_sanitize_context_t *c,
		 const Record_sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
240
  {
B
Behdad Esfahbod 已提交
241
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
242
    return_trace (c->check_struct (this) && featureIndex.sanitize (c));
B
Behdad Esfahbod 已提交
243 244
  }

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

B
Behdad Esfahbod 已提交
256 257
struct Script
{
258
  unsigned int get_lang_sys_count () const
259
  { return langSys.len; }
260
  const Tag& get_lang_sys_tag (unsigned int i) const
261
  { return langSys.get_tag (i); }
262 263 264
  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
B
Behdad Esfahbod 已提交
265
  { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
266
  const LangSys& get_lang_sys (unsigned int i) const
B
Behdad Esfahbod 已提交
267
  {
B
Behdad Esfahbod 已提交
268
    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
269 270
    return this+langSys[i].offset;
  }
271
  bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
272
  { return langSys.find_index (tag, index); }
273

274 275
  bool has_default_lang_sys () const           { return defaultLangSys != 0; }
  const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
276

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

289 290
  bool sanitize (hb_sanitize_context_t *c,
		 const Record_sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
291
  {
B
Behdad Esfahbod 已提交
292
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
293
    return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
B
Behdad Esfahbod 已提交
294 295
  }

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

typedef RecordListOf<Script> ScriptList;

309

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

    /* 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:
332
     * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
333 334 335 336 337 338
     *
     * 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 已提交
339
     * and make the following value checks. If it fails, assume the size
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
     * 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 已提交
368
      return_trace (false);
369 370 371 372
    else if (subfamilyID == 0 &&
	     subfamilyNameID == 0 &&
	     rangeStart == 0 &&
	     rangeEnd == 0)
B
Behdad Esfahbod 已提交
373
      return_trace (true);
374 375 376 377
    else if (designSize < rangeStart ||
	     designSize > rangeEnd ||
	     subfamilyNameID < 256 ||
	     subfamilyNameID > 32767)
B
Behdad Esfahbod 已提交
378
      return_trace (false);
379
    else
B
Behdad Esfahbod 已提交
380
      return_trace (true);
381 382
  }

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

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

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

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

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

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

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

512
  const FeatureParamsSize& get_size_params (hb_tag_t tag) const
513 514 515
  {
    if (tag == HB_TAG ('s','i','z','e'))
      return u.size;
E
Ebrahim Byagowi 已提交
516
    return Null (FeatureParamsSize);
517 518
  }

519
  const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
520 521 522
  {
    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
      return u.stylisticSet;
E
Ebrahim Byagowi 已提交
523
    return Null (FeatureParamsStylisticSet);
524 525
  }

526
  const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
527 528 529
  {
    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
      return u.characterVariants;
E
Ebrahim Byagowi 已提交
530
    return Null (FeatureParamsCharacterVariants);
531 532
  }

533
  private:
534
  union {
535 536 537
  FeatureParamsSize			size;
  FeatureParamsStylisticSet		stylisticSet;
  FeatureParamsCharacterVariants	characterVariants;
538
  } u;
539
  public:
540
  DEFINE_SIZE_STATIC (17);
541
};
542

B
Behdad Esfahbod 已提交
543 544
struct Feature
{
545
  unsigned int get_lookup_count () const
546
  { return lookupIndex.len; }
547
  hb_tag_t get_lookup_index (unsigned int i) const
548
  { return lookupIndex[i]; }
549 550 551
  unsigned int get_lookup_indexes (unsigned int start_index,
				   unsigned int *lookup_count /* IN/OUT */,
				   unsigned int *lookup_tags /* OUT */) const
B
Behdad Esfahbod 已提交
552
  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
553
  void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
554
  { lookupIndex.add_indexes_to (lookup_indexes); }
555

556
  const FeatureParams &get_feature_params () const
557 558
  { return this+featureParams; }

559
  bool subset (hb_subset_context_t *c) const
560 561 562 563
  {
    TRACE_SUBSET (this);
    struct Feature *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);
564
    out->featureParams = 0; /* TODO(subset) FeatureParams. */
565 566 567
    return_trace (true);
  }

568 569
  bool sanitize (hb_sanitize_context_t *c,
		 const Record_sanitize_closure_t *closure = nullptr) const
B
Behdad Esfahbod 已提交
570
  {
B
Behdad Esfahbod 已提交
571
    TRACE_SANITIZE (this);
572
    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
B
Behdad Esfahbod 已提交
573
      return_trace (false);
574

575 576 577 578 579 580
    /* 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.
581 582 583
     *
     * Only do this for the 'size' feature, since at the time of the faulty
     * Adobe tools, only the 'size' feature had FeatureParams defined.
584 585
     */

586 587 588 589
    if (likely (featureParams.is_null ()))
      return_trace (true);

    unsigned int orig_offset = featureParams;
590
    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
B
Behdad Esfahbod 已提交
591
      return_trace (false);
592

593 594 595
    if (featureParams == 0 && closure &&
	closure->tag == HB_TAG ('s','i','z','e') &&
	closure->list_base && closure->list_base < this)
596
    {
597
      unsigned int new_offset_int = orig_offset -
B
Behdad Esfahbod 已提交
598
				    (((char *) this) - ((char *) closure->list_base));
599

B
Behdad Esfahbod 已提交
600
      OffsetTo<FeatureParams> new_offset;
601
      /* Check that it would not overflow. */
602
      new_offset = new_offset_int;
603
      if (new_offset == new_offset_int &&
604
	  c->try_set (&featureParams, new_offset_int) &&
605
	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
B
Behdad Esfahbod 已提交
606
	return_trace (false);
607 608
    }

B
Behdad Esfahbod 已提交
609
    return_trace (true);
B
Behdad Esfahbod 已提交
610 611
  }

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

typedef RecordListOf<Feature> FeatureList;


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

B
Behdad Esfahbod 已提交
641 642
} /* namespace OT */
/* This has to be outside the namespace. */
C
Chun-wei Fan 已提交
643
HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
B
Behdad Esfahbod 已提交
644 645
namespace OT {

B
Behdad Esfahbod 已提交
646 647
struct Lookup
{
648
  unsigned int get_subtable_count () const { return subTable.len; }
649

B
Behdad Esfahbod 已提交
650
  template <typename TSubTable>
651
  const TSubTable& get_subtable (unsigned int i) const
652
  { return this+CastR<OffsetArrayOf<TSubTable>> (subTable)[i]; }
653

B
Behdad Esfahbod 已提交
654
  template <typename TSubTable>
655
  const OffsetArrayOf<TSubTable>& get_subtables () const
656
  { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
B
Behdad Esfahbod 已提交
657
  template <typename TSubTable>
658
  OffsetArrayOf<TSubTable>& get_subtables ()
659
  { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
660

661
  unsigned int get_size () const
662 663 664 665 666 667 668
  {
    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;
  }

669
  unsigned int get_type () const { return lookupType; }
670 671 672 673

  /* 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. */
674
  uint32_t get_props () const
675 676
  {
    unsigned int flag = lookupFlag;
677
    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
678
    {
B
Behdad Esfahbod 已提交
679
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
680
      flag += (markFilteringSet << 16);
681 682 683
    }
    return flag;
  }
684

685
  template <typename TSubTable, typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
686
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
687 688 689 690
  {
    unsigned int lookup_type = get_type ();
    TRACE_DISPATCH (this, lookup_type);
    unsigned int count = get_subtable_count ();
691
    for (unsigned int i = 0; i < count; i++) {
692
      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, hb_forward<Ts> (ds)...);
693
      if (c->stop_sublookup_iteration (r))
E
Ebrahim Byagowi 已提交
694
	return_trace (r);
695
    }
B
Behdad Esfahbod 已提交
696
    return_trace (c->default_return_value ());
697 698
  }

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

718
  template <typename TSubTable>
719
  bool subset (hb_subset_context_t *c) const
720 721 722 723 724 725 726 727 728 729 730 731
  {
    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++)
732
      out_subtables[i].serialize_subset (c, this+subtables[i], out, get_type ());
733 734 735 736

    return_trace (true);
  }

B
Behdad Esfahbod 已提交
737
  template <typename TSubTable>
738
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
739
  {
B
Behdad Esfahbod 已提交
740
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
741
    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
742
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
743
    {
B
Behdad Esfahbod 已提交
744
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
745
      if (!markFilteringSet.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
746
    }
B
Behdad Esfahbod 已提交
747

748
    if (unlikely (!CastR<OffsetArrayOf<TSubTable>> (subTable)
749 750
		   .sanitize (c, this, get_type ())))
      return_trace (false);
B
Behdad Esfahbod 已提交
751 752 753 754 755 756 757 758 759 760

    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++)
E
Ebrahim Byagowi 已提交
761
	if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
B
Behdad Esfahbod 已提交
762 763 764
	  return_trace (false);
    }
    return_trace (true);
B
Behdad Esfahbod 已提交
765
    return_trace (true);
B
Behdad Esfahbod 已提交
766 767
  }

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

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
787 788
struct CoverageFormat1
{
789 790 791
  friend struct Coverage;

  private:
792
  unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
793
  {
794
    unsigned int i;
795
    glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED);
B
Minor  
Behdad Esfahbod 已提交
796
    return i;
797 798
  }

B
Behdad Esfahbod 已提交
799 800 801
  template <typename Iterator,
	    hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
802
  {
B
Behdad Esfahbod 已提交
803
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
804
    return_trace (glyphArray.serialize (c, glyphs));
805 806
  }

807
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
808
  {
B
Behdad Esfahbod 已提交
809
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
810
    return_trace (glyphArray.sanitize (c));
B
Behdad Esfahbod 已提交
811 812
  }

813
  bool intersects (const hb_set_t *glyphs) const
814 815 816 817 818
  {
    /* 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]))
E
Ebrahim Byagowi 已提交
819
	return true;
820
    return false;
821
  }
822
  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
823
  { return glyphs->has (glyphArray[index]); }
824

825
  template <typename set_t>
826
  bool add_coverage (set_t *glyphs) const
827
  { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
828

B
Behdad Esfahbod 已提交
829 830
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
831
  struct iter_t
832
  {
833
    void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
834
    void fini () {}
835
    bool more () const { return i < c->glyphArray.len; }
836
    void next () { i++; }
837
    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
838 839
    bool operator != (const iter_t& o) const
    { return i != o.i || c != o.c; }
B
Behdad Esfahbod 已提交
840 841 842 843 844

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

847
  protected:
B
Behdad Esfahbod 已提交
848
  HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
849
  SortedArrayOf<GlyphID>
850
		glyphArray;	/* Array of GlyphIDs--in numerical order */
851
  public:
852
  DEFINE_SIZE_ARRAY (4, glyphArray);
853 854
};

B
Behdad Esfahbod 已提交
855 856
struct CoverageFormat2
{
857 858 859
  friend struct Coverage;

  private:
860
  unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
861
  {
862 863 864 865
    const RangeRecord &range = rangeRecord.bsearch (glyph_id);
    return likely (range.start <= range.end) ?
	   (unsigned int) range.value + (glyph_id - range.start) :
	   NOT_COVERED;
866 867
  }

B
Behdad Esfahbod 已提交
868 869 870
  template <typename Iterator,
	    hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
871
  {
B
Behdad Esfahbod 已提交
872
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
873
    if (unlikely (!c->extend_min (*this))) return_trace (false);
874

875
    if (unlikely (!glyphs))
876
    {
877
      rangeRecord.len = 0;
878 879
      return_trace (true);
    }
880 881
    /* TODO(iter) Port to non-random-access iterator interface. */
    unsigned int count = glyphs.len ();
882

883
    unsigned int num_ranges = 1;
884
    for (unsigned int i = 1; i < count; i++)
885
      if (glyphs[i - 1] + 1 != glyphs[i])
E
Ebrahim Byagowi 已提交
886
	num_ranges++;
887
    rangeRecord.len = num_ranges;
B
Behdad Esfahbod 已提交
888
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
889

890
    unsigned int range = 0;
891
    rangeRecord[range].start = glyphs[0];
892
    rangeRecord[range].value = 0;
893
    for (unsigned int i = 1; i < count; i++)
894 895 896
    {
      if (glyphs[i - 1] + 1 != glyphs[i])
      {
897
	rangeRecord[range].end = glyphs[i - 1];
898
	range++;
899
	rangeRecord[range].start = glyphs[i];
900
	rangeRecord[range].value = i;
901
      }
902
    }
903
    rangeRecord[range].end = glyphs[count - 1];
B
Behdad Esfahbod 已提交
904
    return_trace (true);
905 906
  }

907
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
908
  {
B
Behdad Esfahbod 已提交
909
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
910
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
911 912
  }

913
  bool intersects (const hb_set_t *glyphs) const
914 915 916 917 918
  {
    /* 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))
E
Ebrahim Byagowi 已提交
919
	return true;
920 921
    return false;
  }
922
  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
923
  {
924 925 926 927 928
    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 已提交
929
	  index < (unsigned int) range.value + (range.end - range.start) &&
930
	  range.intersects (glyphs))
E
Ebrahim Byagowi 已提交
931
	return true;
932
      else if (index < range.value)
E
Ebrahim Byagowi 已提交
933
	return false;
934 935 936 937
    }
    return false;
  }

938
  template <typename set_t>
939 940
  bool add_coverage (set_t *glyphs) const
  {
941 942
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
943
      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
E
Ebrahim Byagowi 已提交
944
	return false;
B
Behdad Esfahbod 已提交
945
    return true;
946 947
  }

B
Behdad Esfahbod 已提交
948 949
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
950
  struct iter_t
951
  {
952
    void init (const CoverageFormat2 &c_)
953
    {
B
Behdad Esfahbod 已提交
954 955 956
      c = &c_;
      coverage = 0;
      i = 0;
957 958 959
      j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
      if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
      {
E
Ebrahim Byagowi 已提交
960 961
	/* Broken table. Skip. */
	i = c->rangeRecord.len;
962
      }
B
Behdad Esfahbod 已提交
963
    }
964
    void fini () {}
965
    bool more () const { return i < c->rangeRecord.len; }
966
    void next ()
967 968 969
    {
      if (j >= c->rangeRecord[i].end)
      {
E
Ebrahim Byagowi 已提交
970
	i++;
B
Behdad Esfahbod 已提交
971
	if (more ())
972
	{
973
	  unsigned int old = coverage;
B
Behdad Esfahbod 已提交
974
	  j = c->rangeRecord[i].start;
975
	  coverage = c->rangeRecord[i].value;
B
Behdad Esfahbod 已提交
976
	  if (unlikely (coverage != old + 1))
977
	  {
B
Behdad Esfahbod 已提交
978 979 980 981
	    /* Broken table. Skip. Important to avoid DoS.
	     * Also, our callers depend on coverage being
	     * consecutive and monotonically increasing,
	     * ie. iota(). */
982 983 984
	   i = c->rangeRecord.len;
	   return;
	  }
985
	}
B
Behdad Esfahbod 已提交
986
	return;
B
Behdad Esfahbod 已提交
987
      }
988
      coverage++;
B
Behdad Esfahbod 已提交
989 990
      j++;
    }
991
    hb_codepoint_t get_glyph () const { return j; }
992 993
    bool operator != (const iter_t& o) const
    { return i != o.i || j != o.j || c != o.c; }
B
Behdad Esfahbod 已提交
994 995 996

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

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

B
Behdad Esfahbod 已提交
1012 1013
struct Coverage
{
B
Behdad Esfahbod 已提交
1014
  /* Has interface. */
1015
  static constexpr unsigned SENTINEL = NOT_COVERED;
1016 1017 1018
  typedef unsigned int value_t;
  value_t operator [] (hb_codepoint_t k) const { return get (k); }
  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
B
Behdad Esfahbod 已提交
1019
  /* Predicate. */
1020
  bool operator () (hb_codepoint_t k) const { return has (k); }
1021

1022
  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
1023
  unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1024
  {
1025
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1026 1027
    case 1: return u.format1.get_coverage (glyph_id);
    case 2: return u.format2.get_coverage (glyph_id);
1028 1029 1030 1031
    default:return NOT_COVERED;
    }
  }

B
Behdad Esfahbod 已提交
1032 1033 1034
  template <typename Iterator,
	    hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
1035
  {
B
Behdad Esfahbod 已提交
1036
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1037
    if (unlikely (!c->extend_min (*this))) return_trace (false);
1038

1039 1040
    /* TODO(iter) Port to non-random-access iterator interface. */
    unsigned int count = glyphs.len ();
1041
    unsigned int num_ranges = 1;
1042
    for (unsigned int i = 1; i < count; i++)
1043
      if (glyphs[i - 1] + 1 != glyphs[i])
E
Ebrahim Byagowi 已提交
1044
	num_ranges++;
1045
    u.format = count * 2 < num_ranges * 3 ? 1 : 2;
1046

1047 1048
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1049 1050
    case 1: return_trace (u.format1.serialize (c, glyphs));
    case 2: return_trace (u.format2.serialize (c, glyphs));
B
Behdad Esfahbod 已提交
1051
    default:return_trace (false);
1052 1053 1054
    }
  }

1055
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1056
  {
B
Behdad Esfahbod 已提交
1057
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1058
    if (!u.format.sanitize (c)) return_trace (false);
1059 1060
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1061 1062 1063
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1064 1065
    }
  }
1066

1067
  bool intersects (const hb_set_t *glyphs) const
1068
  {
1069 1070 1071 1072 1073 1074
    switch (u.format)
    {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
1075
  }
1076
  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
1077 1078 1079
  {
    switch (u.format)
    {
1080 1081 1082 1083
    case 1: return u.format1.intersects_coverage (glyphs, index);
    case 2: return u.format2.intersects_coverage (glyphs, index);
    default:return false;
    }
B
Behdad Esfahbod 已提交
1084 1085
  }

B
Behdad Esfahbod 已提交
1086 1087
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
1088
  template <typename set_t>
1089
  bool add_coverage (set_t *glyphs) const
1090 1091 1092
  {
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1093 1094
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1095
    default:return false;
1096 1097 1098
    }
  }

1099
  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
1100
  {
1101
    static constexpr bool is_sorted_iterator = true;
B
Behdad Esfahbod 已提交
1102
    iter_t (const Coverage &c_ = Null(Coverage))
1103
    {
1104
      memset (this, 0, sizeof (*this));
B
Behdad Esfahbod 已提交
1105
      format = c_.u.format;
1106 1107
      switch (format)
      {
B
Minor  
Behdad Esfahbod 已提交
1108 1109
      case 1: u.format1.init (c_.u.format1); return;
      case 2: u.format2.init (c_.u.format2); return;
1110
      default:				     return;
B
Behdad Esfahbod 已提交
1111 1112
      }
    }
1113
    bool __more__ () const
1114 1115 1116
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1117 1118
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
1119
      default:return false;
B
Behdad Esfahbod 已提交
1120 1121
      }
    }
1122
    void __next__ ()
1123 1124 1125
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1126 1127
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
1128
      default:			 break;
B
Behdad Esfahbod 已提交
1129 1130
      }
    }
1131 1132
    typedef hb_codepoint_t __item_t__;
    __item_t__ __item__ () const { return get_glyph (); }
1133

1134
    hb_codepoint_t get_glyph () const
1135 1136 1137
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1138 1139
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
1140
      default:return 0;
B
Behdad Esfahbod 已提交
1141 1142
      }
    }
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
    bool operator != (const iter_t& o) const
    {
      if (format != o.format) return true;
      switch (format)
      {
      case 1: return u.format1 != o.u.format1;
      case 2: return u.format2 != o.u.format2;
      default:return false;
      }
    }
B
Behdad Esfahbod 已提交
1153 1154

    private:
B
Behdad Esfahbod 已提交
1155
    unsigned int format;
B
Behdad Esfahbod 已提交
1156
    union {
B
Behdad Esfahbod 已提交
1157 1158
    CoverageFormat2::iter_t	format2; /* Put this one first since it's larger; helps shut up compiler. */
    CoverageFormat1::iter_t	format1;
B
Behdad Esfahbod 已提交
1159 1160
    } u;
  };
B
Behdad Esfahbod 已提交
1161
  iter_t iter () const { return iter_t (*this); }
B
Behdad Esfahbod 已提交
1162

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


/*
 * Class Definition Table
 */

B
Behdad Esfahbod 已提交
1178
static inline void ClassDef_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1179 1180
				       hb_array_t<const GlyphID> glyphs,
				       hb_array_t<const HBUINT16> klasses);
B
Behdad Esfahbod 已提交
1181

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

  private:
1187
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1188
  {
B
Minor  
Behdad Esfahbod 已提交
1189
    return classValue[(unsigned int) (glyph_id - startGlyph)];
1190 1191
  }

1192
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1193
		  hb_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1194
		  hb_array_t<const HBUINT16> klasses)
1195 1196 1197 1198
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

1199
    if (unlikely (!glyphs))
1200
    {
1201 1202
      startGlyph = 0;
      classValue.len = 0;
1203 1204 1205
      return_trace (true);
    }

B
Minor  
Behdad Esfahbod 已提交
1206 1207
    hb_codepoint_t glyph_min = +glyphs | hb_reduce (hb_min, 0xFFFFu);
    hb_codepoint_t glyph_max = +glyphs | hb_reduce (hb_max, 0u);
1208

1209 1210
    startGlyph = glyph_min;
    classValue.len = glyph_max - glyph_min + 1;
1211 1212
    if (unlikely (!c->extend (classValue))) return_trace (false);

1213
    for (unsigned int i = 0; i < glyphs.length; i++)
1214
      classValue[glyphs[i] - glyph_min] = klasses[i];
B
Behdad Esfahbod 已提交
1215

1216 1217 1218
    return_trace (true);
  }

1219
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1220 1221
  {
    TRACE_SUBSET (this);
1222
    const hb_set_t &glyphset = *c->plan->glyphset ();
B
Behdad Esfahbod 已提交
1223
    const hb_map_t &glyph_map = *c->plan->glyph_map;
B
Behdad Esfahbod 已提交
1224
    hb_sorted_vector_t<GlyphID> glyphs;
1225 1226
    hb_vector_t<HBUINT16> klasses;

1227 1228 1229 1230
    hb_codepoint_t start = startGlyph;
    hb_codepoint_t end   = start + classValue.len;
    for (hb_codepoint_t g = start; g < end; g++)
    {
B
Behdad Esfahbod 已提交
1231
      if (!glyphset.has (g)) continue;
1232 1233
      unsigned int value = classValue[g - start];
      if (!value) continue;
1234 1235
      glyphs.push(glyph_map[g]);
      klasses.push(value);
1236
    }
1237
    c->serializer->propagate_error (glyphs, klasses);
B
Behdad Esfahbod 已提交
1238
    ClassDef_serialize (c->serializer, glyphs, klasses);
1239
    return_trace ((bool) glyphs);
B
Behdad Esfahbod 已提交
1240 1241
  }

1242
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1243
  {
B
Behdad Esfahbod 已提交
1244
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1245
    return_trace (c->check_struct (this) && classValue.sanitize (c));
B
Behdad Esfahbod 已提交
1246 1247
  }

1248
  template <typename set_t>
1249 1250
  bool add_coverage (set_t *glyphs) const
  {
1251 1252 1253 1254 1255
    unsigned int start = 0;
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
    {
      if (classValue[i])
E
Ebrahim Byagowi 已提交
1256
	continue;
1257 1258 1259

      if (start != i)
	if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1260
	  return false;
1261 1262 1263 1264 1265

      start = i + 1;
    }
    if (start != count)
      if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1266
	return false;
1267 1268 1269 1270 1271

    return true;
  }

  template <typename set_t>
1272 1273
  bool add_class (set_t *glyphs, unsigned int klass) const
  {
1274 1275
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
E
Ebrahim Byagowi 已提交
1276
      if (classValue[i] == klass) glyphs->add (startGlyph + i);
B
Behdad Esfahbod 已提交
1277
    return true;
1278 1279
  }

1280
  bool intersects (const hb_set_t *glyphs) const
1281 1282 1283 1284 1285 1286
  {
    /* 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;)
E
Ebrahim Byagowi 已提交
1287
      if (classValue[iter - start]) return true;
1288 1289
    return false;
  }
1290 1291
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
  {
1292
    unsigned int count = classValue.len;
1293 1294 1295
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1296
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
E
Ebrahim Byagowi 已提交
1297 1298
      if (!hb_set_next (glyphs, &g)) return false;
      if (g < startGlyph) return true;
1299
      g = startGlyph + count - 1;
E
Ebrahim Byagowi 已提交
1300
      if (hb_set_next (glyphs, &g)) return true;
1301 1302
      /* Fall through. */
    }
1303 1304
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass && glyphs->has (startGlyph + i))
E
Ebrahim Byagowi 已提交
1305
	return true;
1306 1307 1308
    return false;
  }

1309
  protected:
B
Behdad Esfahbod 已提交
1310 1311
  HBUINT16	classFormat;	/* Format identifier--format = 1 */
  GlyphID	startGlyph;	/* First GlyphID of the classValueArray */
B
Behdad Esfahbod 已提交
1312
  ArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
1313
		classValue;	/* Array of Class Values--one per GlyphID */
1314
  public:
1315
  DEFINE_SIZE_ARRAY (6, classValue);
1316 1317
};

B
Behdad Esfahbod 已提交
1318 1319
struct ClassDefFormat2
{
1320 1321 1322
  friend struct ClassDef;

  private:
1323
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1324
  {
1325
    return rangeRecord.bsearch (glyph_id).value;
1326 1327
  }

1328
  bool serialize (hb_serialize_context_t *c,
B
Minor  
Behdad Esfahbod 已提交
1329
		  hb_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1330
		  hb_array_t<const HBUINT16> klasses)
1331 1332 1333 1334
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

1335
    if (unlikely (!glyphs))
1336
    {
1337
      rangeRecord.len = 0;
1338 1339 1340
      return_trace (true);
    }

1341
    unsigned int count = glyphs.len ();
1342
    unsigned int num_ranges = 1;
1343
    for (unsigned int i = 1; i < count; i++)
1344 1345 1346
      if (glyphs[i - 1] + 1 != glyphs[i] ||
	  klasses[i - 1] != klasses[i])
	num_ranges++;
1347
    rangeRecord.len = num_ranges;
1348 1349 1350 1351
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);

    unsigned int range = 0;
    rangeRecord[range].start = glyphs[0];
1352
    rangeRecord[range].value = klasses[0];
1353
    for (unsigned int i = 1; i < count; i++)
1354 1355 1356 1357
    {
      if (glyphs[i - 1] + 1 != glyphs[i] ||
	  klasses[i - 1] != klasses[i])
      {
1358
	rangeRecord[range].end = glyphs[i - 1];
1359 1360 1361 1362 1363
	range++;
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value = klasses[i];
      }
    }
1364
    rangeRecord[range].end = glyphs[count - 1];
1365 1366 1367
    return_trace (true);
  }

1368
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1369 1370
  {
    TRACE_SUBSET (this);
1371
    const hb_set_t &glyphset = *c->plan->glyphset ();
B
Behdad Esfahbod 已提交
1372 1373
    const hb_map_t &glyph_map = *c->plan->glyph_map;
    hb_vector_t<GlyphID> glyphs;
1374
    hb_vector_t<HBUINT16> klasses;
B
Behdad Esfahbod 已提交
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385

    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
    {
      unsigned int value = rangeRecord[i].value;
      if (!value) continue;
      hb_codepoint_t start = rangeRecord[i].start;
      hb_codepoint_t end   = rangeRecord[i].end + 1;
      for (hb_codepoint_t g = start; g < end; g++)
      {
	if (!glyphset.has (g)) continue;
1386 1387
	glyphs.push (glyph_map[g]);
	klasses.push (value);
B
Behdad Esfahbod 已提交
1388 1389
      }
    }
1390
    c->serializer->propagate_error (glyphs, klasses);
B
Behdad Esfahbod 已提交
1391
    ClassDef_serialize (c->serializer, glyphs, klasses);
1392
    return_trace ((bool) glyphs);
B
Behdad Esfahbod 已提交
1393 1394
  }

1395
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1396
  {
B
Behdad Esfahbod 已提交
1397
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1398
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
1399 1400
  }

1401
  template <typename set_t>
1402
  bool add_coverage (set_t *glyphs) const
1403
  {
1404 1405 1406 1407
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value)
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1408
	  return false;
1409 1410 1411 1412
    return true;
  }

  template <typename set_t>
1413
  bool add_class (set_t *glyphs, unsigned int klass) const
1414
  {
1415 1416
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1417
    {
1418
      if (rangeRecord[i].value == klass)
E
Ebrahim Byagowi 已提交
1419
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1420
	  return false;
B
Behdad Esfahbod 已提交
1421 1422
    }
    return true;
1423 1424
  }

1425
  bool intersects (const hb_set_t *glyphs) const
1426 1427 1428 1429 1430
  {
    /* 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))
E
Ebrahim Byagowi 已提交
1431
	return true;
1432 1433
    return false;
  }
1434
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
1435
  {
1436
    unsigned int count = rangeRecord.len;
1437 1438 1439
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1440
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1441 1442 1443 1444 1445 1446 1447 1448
      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;
      }
1449
      if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
E
Ebrahim Byagowi 已提交
1450
	return true;
1451 1452
      /* Fall through. */
    }
1453 1454
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
E
Ebrahim Byagowi 已提交
1455
	return true;
1456 1457 1458
    return false;
  }

1459
  protected:
B
Behdad Esfahbod 已提交
1460
  HBUINT16	classFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1461
  SortedArrayOf<RangeRecord>
1462 1463
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID */
1464
  public:
1465
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1466 1467
};

B
Behdad Esfahbod 已提交
1468 1469
struct ClassDef
{
B
Behdad Esfahbod 已提交
1470
  /* Has interface. */
1471
  static constexpr unsigned SENTINEL = 0;
1472 1473 1474
  typedef unsigned int value_t;
  value_t operator [] (hb_codepoint_t k) const { return get (k); }
  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
B
Behdad Esfahbod 已提交
1475 1476
  /* Projection. */
  hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
1477

1478
  unsigned int get (hb_codepoint_t k) const { return get_class (k); }
1479
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1480
  {
1481
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1482 1483
    case 1: return u.format1.get_class (glyph_id);
    case 2: return u.format2.get_class (glyph_id);
1484 1485 1486 1487
    default:return 0;
    }
  }

1488
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1489 1490
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const HBUINT16> klasses)
1491 1492 1493 1494
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

B
Behdad Esfahbod 已提交
1495
    unsigned int format = 2;
1496
    if (likely (glyphs))
1497
    {
1498 1499
      hb_codepoint_t glyph_min = +glyphs | hb_reduce (hb_min, 0xFFFFu);
      hb_codepoint_t glyph_max = +glyphs | hb_reduce (hb_max, 0u);
B
Behdad Esfahbod 已提交
1500

1501
      unsigned int count = glyphs.len ();
B
Behdad Esfahbod 已提交
1502
      unsigned int num_ranges = 1;
1503
      for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
1504 1505 1506 1507 1508 1509
	if (glyphs[i - 1] + 1 != glyphs[i] ||
	    klasses[i - 1] != klasses[i])
	  num_ranges++;

      if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3)
        format = 1;
1510
    }
1511
    u.format = format;
1512 1513 1514

    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1515 1516
    case 1: return_trace (u.format1.serialize (c, glyphs, klasses));
    case 2: return_trace (u.format2.serialize (c, glyphs, klasses));
1517 1518 1519 1520
    default:return_trace (false);
    }
  }

1521
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1522 1523 1524 1525 1526 1527 1528 1529 1530
  {
    TRACE_SUBSET (this);
    switch (u.format) {
    case 1: return_trace (u.format1.subset (c));
    case 2: return_trace (u.format2.subset (c));
    default:return_trace (false);
    }
  }

1531
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1532
  {
B
Behdad Esfahbod 已提交
1533
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1534
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
1535
    switch (u.format) {
B
Behdad Esfahbod 已提交
1536 1537 1538
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1539 1540
    }
  }
1541

1542 1543 1544
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
  template <typename set_t>
1545 1546
  bool add_coverage (set_t *glyphs) const
  {
1547 1548 1549
    switch (u.format) {
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1550
    default:return false;
1551 1552 1553 1554 1555
    }
  }

  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
B
Behdad Esfahbod 已提交
1556
  template <typename set_t>
1557 1558
  bool add_class (set_t *glyphs, unsigned int klass) const
  {
1559
    switch (u.format) {
1560 1561
    case 1: return u.format1.add_class (glyphs, klass);
    case 2: return u.format2.add_class (glyphs, klass);
B
Behdad Esfahbod 已提交
1562
    default:return false;
1563 1564 1565
    }
  }

1566 1567
  bool intersects (const hb_set_t *glyphs) const
  {
1568 1569 1570 1571 1572 1573
    switch (u.format) {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
  }
1574 1575
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
  {
1576 1577 1578 1579 1580 1581 1582
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1583
  protected:
1584
  union {
B
Behdad Esfahbod 已提交
1585
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1586 1587
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1588
  } u;
B
Behdad Esfahbod 已提交
1589
  public:
B
Behdad Esfahbod 已提交
1590
  DEFINE_SIZE_UNION (2, format);
1591 1592
};

B
Behdad Esfahbod 已提交
1593
static inline void ClassDef_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1594 1595 1596
				       hb_array_t<const GlyphID> glyphs,
				       hb_array_t<const HBUINT16> klasses)
{ c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); }
B
Behdad Esfahbod 已提交
1597

1598

1599 1600 1601 1602 1603 1604
/*
 * Item Variation Store
 */

struct VarRegionAxis
{
1605
  float evaluate (int coord) const
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
  {
    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);
  }

1628
  bool sanitize (hb_sanitize_context_t *c) const
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645
  {
    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
{
1646
  float evaluate (unsigned int region_index,
B
Bruce Mitchener 已提交
1647
			 const int *coords, unsigned int coord_len) const
1648 1649 1650 1651
  {
    if (unlikely (region_index >= regionCount))
      return 0.;

1652
    const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1653 1654

    float v = 1.;
1655
    unsigned int count = axisCount;
1656 1657
    for (unsigned int i = 0; i < count; i++)
    {
1658 1659
      int coord = i < coord_len ? coords[i] : 0;
      float factor = axes[i].evaluate (coord);
1660
      if (factor == 0.f)
E
Ebrahim Byagowi 已提交
1661
	return 0.;
1662 1663 1664 1665 1666
      v *= factor;
    }
    return v;
  }

1667
  bool sanitize (hb_sanitize_context_t *c) const
1668 1669 1670
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
1671
		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1672 1673
  }

1674
  unsigned int get_region_count () const { return regionCount; }
1675

1676
  protected:
B
Behdad Esfahbod 已提交
1677 1678
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1679 1680
  UnsizedArrayOf<VarRegionAxis>
		axesZ;
1681 1682 1683 1684 1685 1686
  public:
  DEFINE_SIZE_ARRAY (4, axesZ);
};

struct VarData
{
1687
  unsigned int get_region_index_count () const
M
Michiharu Ariza 已提交
1688 1689
  { return regionIndices.len; }

1690
  unsigned int get_row_size () const
1691 1692
  { return shortCount + regionIndices.len; }

1693
  unsigned int get_size () const
1694 1695
  { return itemCount * get_row_size (); }

1696
  float get_delta (unsigned int inner,
B
Bruce Mitchener 已提交
1697
			  const int *coords, unsigned int coord_count,
1698 1699 1700 1701 1702 1703 1704 1705
			  const VarRegionList &regions) const
  {
    if (unlikely (inner >= itemCount))
      return 0.;

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

B
Behdad Esfahbod 已提交
1706 1707
   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
   const HBUINT8 *row = bytes + inner * (scount + count);
1708 1709 1710 1711

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

B
Behdad Esfahbod 已提交
1712
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1713 1714
   for (; i < scount; i++)
   {
1715
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1716 1717
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1718
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1719 1720
   for (; i < count; i++)
   {
1721
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1722 1723 1724 1725 1726 1727
     delta += scalar * *bcursor++;
   }

   return delta;
  }

1728
  void get_scalars (int *coords, unsigned int coord_count,
M
Michiharu Ariza 已提交
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
                    const VarRegionList &regions,
                    float *scalars /*OUT */,
                    unsigned int num_scalars) const
  {
    assert (num_scalars == regionIndices.len);
   for (unsigned int i = 0; i < num_scalars; i++)
   {
     scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
   }
  }
1739 1740

  bool sanitize (hb_sanitize_context_t *c) const
1741 1742 1743
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
E
Ebrahim Byagowi 已提交
1744
		  regionIndices.sanitize (c) &&
1745
		  shortCount <= regionIndices.len &&
1746 1747 1748
		  c->check_range (&StructAfter<HBUINT8> (regionIndices),
				  itemCount,
				  get_row_size ()));
1749 1750 1751
  }

  protected:
B
Behdad Esfahbod 已提交
1752 1753 1754
  HBUINT16		itemCount;
  HBUINT16		shortCount;
  ArrayOf<HBUINT16>	regionIndices;
B
Behdad Esfahbod 已提交
1755
/*UnsizedArrayOf<HBUINT8>bytesX;*/
1756
  public:
B
Behdad Esfahbod 已提交
1757
  DEFINE_SIZE_ARRAY (6, regionIndices);
1758 1759
};

1760
struct VariationStore
1761
{
1762 1763
  float get_delta (unsigned int outer, unsigned int inner,
		   const int *coords, unsigned int coord_count) const
1764 1765 1766 1767 1768 1769 1770 1771 1772
  {
    if (unlikely (outer >= dataSets.len))
      return 0.;

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

1773 1774
  float get_delta (unsigned int index,
		   const int *coords, unsigned int coord_count) const
1775 1776 1777 1778 1779 1780
  {
    unsigned int outer = index >> 16;
    unsigned int inner = index & 0xFFFF;
    return get_delta (outer, inner, coords, coord_count);
  }

1781
  bool sanitize (hb_sanitize_context_t *c) const
1782 1783 1784 1785 1786 1787 1788 1789
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  format == 1 &&
		  regions.sanitize (c, this) &&
		  dataSets.sanitize (c, this));
  }

1790
  unsigned int get_region_index_count (unsigned int ivs) const
M
Michiharu Ariza 已提交
1791 1792
  { return (this+dataSets[ivs]).get_region_index_count (); }

1793 1794 1795 1796
  void get_scalars (unsigned int ivs,
		    int *coords, unsigned int coord_count,
		    float *scalars /*OUT*/,
		    unsigned int num_scalars) const
M
Michiharu Ariza 已提交
1797 1798 1799 1800
  {
    (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
                                      &scalars[0], num_scalars);
  }
1801

1802
  protected:
B
Behdad Esfahbod 已提交
1803
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1804
  LOffsetTo<VarRegionList>		regions;
B
Minor  
Behdad Esfahbod 已提交
1805
  LOffsetArrayOf<VarData>		dataSets;
1806 1807 1808 1809
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

1810 1811 1812 1813 1814 1815 1816 1817 1818
/*
 * Feature Variations
 */

struct ConditionFormat1
{
  friend struct Condition;

  private:
1819
  bool evaluate (const int *coords, unsigned int coord_len) const
1820 1821 1822 1823 1824
  {
    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
  }

1825
  bool sanitize (hb_sanitize_context_t *c) const
1826 1827 1828 1829 1830 1831
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  protected:
B
Behdad Esfahbod 已提交
1832 1833
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1834 1835 1836 1837 1838 1839 1840 1841
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1842
  bool evaluate (const int *coords, unsigned int coord_len) const
1843 1844 1845 1846 1847 1848 1849
  {
    switch (u.format) {
    case 1: return u.format1.evaluate (coords, coord_len);
    default:return false;
    }
  }

1850
  bool sanitize (hb_sanitize_context_t *c) const
1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
  {
    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 已提交
1862
  HBUINT16		format;		/* Format identifier */
1863 1864 1865 1866 1867 1868 1869 1870
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct ConditionSet
{
1871
  bool evaluate (const int *coords, unsigned int coord_len) const
1872 1873 1874
  {
    unsigned int count = conditions.len;
    for (unsigned int i = 0; i < count; i++)
1875
      if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
E
Ebrahim Byagowi 已提交
1876
	return false;
1877 1878 1879
    return true;
  }

1880
  bool sanitize (hb_sanitize_context_t *c) const
1881 1882 1883 1884 1885 1886
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, this));
  }

  protected:
B
Minor  
Behdad Esfahbod 已提交
1887
  LOffsetArrayOf<Condition>	conditions;
1888 1889 1890 1891 1892 1893
  public:
  DEFINE_SIZE_ARRAY (2, conditions);
};

struct FeatureTableSubstitutionRecord
{
1894
  friend struct FeatureTableSubstitution;
1895

1896
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1897 1898
  {
    TRACE_SANITIZE (this);
1899
    return_trace (c->check_struct (this) && feature.sanitize (c, base));
1900 1901 1902
  }

  protected:
B
Behdad Esfahbod 已提交
1903
  HBUINT16		featureIndex;
B
Behdad Esfahbod 已提交
1904
  LOffsetTo<Feature>	feature;
1905 1906 1907 1908 1909 1910
  public:
  DEFINE_SIZE_STATIC (6);
};

struct FeatureTableSubstitution
{
1911
  const Feature *find_substitute (unsigned int feature_index) const
1912 1913 1914 1915
  {
    unsigned int count = substitutions.len;
    for (unsigned int i = 0; i < count; i++)
    {
1916
      const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1917 1918
      if (record.featureIndex == feature_index)
	return &(this+record.feature);
1919
    }
B
Behdad Esfahbod 已提交
1920
    return nullptr;
1921 1922
  }

1923
  bool sanitize (hb_sanitize_context_t *c) const
1924 1925 1926 1927 1928 1929 1930 1931 1932
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  substitutions.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
1933
  ArrayOf<FeatureTableSubstitutionRecord>
1934 1935 1936 1937 1938 1939 1940 1941 1942
			substitutions;
  public:
  DEFINE_SIZE_ARRAY (6, substitutions);
};

struct FeatureVariationRecord
{
  friend struct FeatureVariations;

1943
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1944 1945 1946 1947 1948 1949 1950
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, base) &&
		  substitutions.sanitize (c, base));
  }

  protected:
B
Behdad Esfahbod 已提交
1951
  LOffsetTo<ConditionSet>
1952
			conditions;
B
Behdad Esfahbod 已提交
1953
  LOffsetTo<FeatureTableSubstitution>
1954 1955 1956 1957 1958 1959 1960
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct FeatureVariations
{
1961
  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
1962

1963
  bool find_index (const int *coords, unsigned int coord_len,
1964
			  unsigned int *index) const
1965 1966 1967 1968
  {
    unsigned int count = varRecords.len;
    for (unsigned int i = 0; i < count; i++)
    {
1969
      const FeatureVariationRecord &record = varRecords.arrayZ[i];
1970
      if ((this+record.conditions).evaluate (coords, coord_len))
1971 1972 1973 1974
      {
	*index = i;
	return true;
      }
1975
    }
1976
    *index = NOT_FOUND_INDEX;
1977
    return false;
1978 1979
  }

1980 1981
  const Feature *find_substitute (unsigned int variations_index,
				  unsigned int feature_index) const
1982 1983 1984 1985 1986
  {
    const FeatureVariationRecord &record = varRecords[variations_index];
    return (this+record.substitutions).find_substitute (feature_index);
  }

1987
  FeatureVariations* copy (hb_serialize_context_t *c) const
1988
  {
1989 1990
    TRACE_SERIALIZE (this);
    return_trace (c->embed (*this));
1991 1992
  }

1993
  bool sanitize (hb_sanitize_context_t *c) const
1994 1995 1996 1997 1998 1999 2000 2001 2002
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  varRecords.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
B
Behdad Esfahbod 已提交
2003
  LArrayOf<FeatureVariationRecord>
2004 2005
			varRecords;
  public:
2006
  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
2007 2008
};

2009

2010 2011 2012 2013
/*
 * Device Tables
 */

2014
struct HintingDevice
B
Behdad Esfahbod 已提交
2015
{
2016 2017 2018
  friend struct Device;

  private:
B
Behdad Esfahbod 已提交
2019

2020
  hb_position_t get_x_delta (hb_font_t *font) const
2021
  { return get_delta (font->x_ppem, font->x_scale); }
B
Behdad Esfahbod 已提交
2022

2023
  hb_position_t get_y_delta (hb_font_t *font) const
2024
  { return get_delta (font->y_ppem, font->y_scale); }
B
Behdad Esfahbod 已提交
2025

2026
  unsigned int get_size () const
B
Minor  
Behdad Esfahbod 已提交
2027 2028
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
2029 2030
    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 已提交
2031 2032
  }

2033
  bool sanitize (hb_sanitize_context_t *c) const
B
Minor  
Behdad Esfahbod 已提交
2034 2035 2036 2037 2038 2039 2040
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
  }

  private:

2041
  int get_delta (unsigned int ppem, int scale) const
2042 2043 2044 2045 2046 2047 2048
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

B
Behdad Esfahbod 已提交
2049
    return (int) (pixels * (int64_t) scale / ppem);
2050
  }
2051
  int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
2052
  {
2053
    unsigned int f = deltaFormat;
2054
    if (unlikely (f < 1 || f > 3))
2055
      return 0;
2056

2057 2058
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
2059

2060
    unsigned int s = ppem_size - startSize;
2061

2062
    unsigned int byte = deltaValueZ[s >> (4 - f)];
B
Behdad Esfahbod 已提交
2063
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
2064
    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
2065 2066 2067

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
2068
    if ((unsigned int) delta >= ((mask + 1) >> 1))
2069 2070 2071 2072 2073
      delta -= mask + 1;

    return delta;
  }

2074
  protected:
B
Behdad Esfahbod 已提交
2075 2076 2077
  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
2078 2079 2080 2081
					 * 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
					 */
2082 2083
  UnsizedArrayOf<HBUINT16>
		deltaValueZ;		/* Array of compressed data */
B
Behdad Esfahbod 已提交
2084
  public:
2085
  DEFINE_SIZE_ARRAY (6, deltaValueZ);
2086 2087
};

2088 2089
struct VariationDevice
{
2090 2091 2092
  friend struct Device;

  private:
2093

2094
  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
2095
  { return font->em_scalef_x (get_delta (font, store)); }
2096

2097
  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
2098
  { return font->em_scalef_y (get_delta (font, store)); }
2099

2100
  bool sanitize (hb_sanitize_context_t *c) const
2101 2102
  {
    TRACE_SANITIZE (this);
2103
    return_trace (c->check_struct (this));
2104 2105 2106 2107
  }

  private:

2108
  float get_delta (hb_font_t *font, const VariationStore &store) const
2109
  {
2110
    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
2111 2112 2113
  }

  protected:
B
Behdad Esfahbod 已提交
2114 2115 2116
  HBUINT16	outerIndex;
  HBUINT16	innerIndex;
  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
2117
  public:
2118
  DEFINE_SIZE_STATIC (6);
2119 2120
};

2121 2122 2123
struct DeviceHeader
{
  protected:
B
Behdad Esfahbod 已提交
2124 2125
  HBUINT16		reserved1;
  HBUINT16		reserved2;
2126
  public:
B
Behdad Esfahbod 已提交
2127
  HBUINT16		format;		/* Format identifier */
2128 2129 2130 2131
  public:
  DEFINE_SIZE_STATIC (6);
};

2132 2133
struct Device
{
2134
  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2135 2136 2137 2138 2139
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
2140
    case 0x8000:
2141
      return u.variation.get_x_delta (font, store);
2142 2143 2144 2145
    default:
      return 0;
    }
  }
2146
  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2147 2148 2149 2150
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
2151
      return u.hinting.get_y_delta (font);
2152
    case 0x8000:
2153
      return u.variation.get_y_delta (font, store);
2154 2155 2156 2157 2158
    default:
      return 0;
    }
  }

2159
  bool sanitize (hb_sanitize_context_t *c) const
2160 2161 2162 2163 2164 2165
  {
    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));
2166
    case 0x8000:
2167 2168 2169 2170 2171 2172 2173 2174
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

  protected:
  union {
2175
  DeviceHeader		b;
2176 2177 2178 2179 2180 2181 2182
  HintingDevice		hinting;
  VariationDevice	variation;
  } u;
  public:
  DEFINE_SIZE_UNION (6, b);
};

2183

B
Behdad Esfahbod 已提交
2184
} /* namespace OT */
2185

B
Behdad Esfahbod 已提交
2186

2187
#endif /* HB_OT_LAYOUT_COMMON_HH */