hb-ot-layout-common.hh 61.0 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 107
struct RecordArrayOf : SortedArrayOf<Record<Type> >
{
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 564 565 566 567
  {
    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);
  }

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
     */

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

590
    if (likely (orig_offset.is_null ()))
B
Behdad Esfahbod 已提交
591
      return_trace (true);
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 = (unsigned 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 did not overflow. */
602 603
      new_offset.set (new_offset_int);
      if (new_offset == new_offset_int &&
604
	  c->try_set (&featureParams, new_offset) &&
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
B
Behdad Esfahbod 已提交
652
  { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
653

B
Behdad Esfahbod 已提交
654
  template <typename TSubTable>
655
  const OffsetArrayOf<TSubTable>& get_subtables () const
B
Behdad Esfahbod 已提交
656 657
  { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
  template <typename TSubTable>
658
  OffsetArrayOf<TSubTable>& get_subtables ()
B
Behdad Esfahbod 已提交
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

B
Behdad Esfahbod 已提交
685
  template <typename TSubTable, typename context_t>
686
  typename context_t::return_t dispatch (context_t *c) 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++) {
B
Behdad Esfahbod 已提交
692
      typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
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
    lookupType.set (lookup_type);
707
    lookupFlag.set (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 714
      markFilteringSet.set (lookup_props >> 16);
    }
B
Behdad Esfahbod 已提交
715
    return_trace (true);
716 717
  }

B
Bruce Mitchener 已提交
718
  /* Older compilers need this to NOT be locally defined in a function. */
B
Behdad Esfahbod 已提交
719 720 721
  template <typename TSubTable>
  struct SubTableSubsetWrapper
  {
722 723 724 725
    SubTableSubsetWrapper (const TSubTable &subtable_,
			   unsigned int lookup_type_) :
			     subtable (subtable_),
			     lookup_type (lookup_type_) {}
B
Behdad Esfahbod 已提交
726

727
    bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
728 729 730 731 732 733 734
    { return subtable.dispatch (c, lookup_type); }

    private:
    const TSubTable &subtable;
    unsigned int lookup_type;
  };

735
  template <typename TSubTable>
736
  bool subset (hb_subset_context_t *c) const
737 738 739 740 741 742 743 744 745 746 747 748 749
  {
    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 已提交
750
      SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
751 752 753 754 755 756 757

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

    return_trace (true);
  }

758 759 760 761
  /* Older compilers need this to NOT be locally defined in a function. */
  template <typename TSubTable>
  struct SubTableSanitizeWrapper : TSubTable
  {
762
    bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const
763 764 765
    { return this->dispatch (c, lookup_type); }
  };

B
Behdad Esfahbod 已提交
766
  template <typename TSubTable>
767
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
768
  {
B
Behdad Esfahbod 已提交
769
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
770
    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
771
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
772
    {
B
Behdad Esfahbod 已提交
773
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
774
      if (!markFilteringSet.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
775
    }
B
Behdad Esfahbod 已提交
776

777 778 779
    if (unlikely (!CastR<OffsetArrayOf<SubTableSanitizeWrapper<TSubTable> > > (subTable)
		   .sanitize (c, this, get_type ())))
      return_trace (false);
B
Behdad Esfahbod 已提交
780 781 782 783 784 785 786 787 788 789

    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 已提交
790
	if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
B
Behdad Esfahbod 已提交
791 792 793
	  return_trace (false);
    }
    return_trace (true);
B
Behdad Esfahbod 已提交
794
    return_trace (true);
B
Behdad Esfahbod 已提交
795 796
  }

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

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
816 817
struct CoverageFormat1
{
818 819 820
  friend struct Coverage;

  private:
821
  unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
822
  {
823
    unsigned int i;
824
    glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED);
B
Minor  
Behdad Esfahbod 已提交
825
    return i;
826 827
  }

B
Behdad Esfahbod 已提交
828 829 830
  template <typename Iterator,
	    hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
831
  {
B
Behdad Esfahbod 已提交
832
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
833
    return_trace (glyphArray.serialize (c, glyphs));
834 835
  }

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

842
  bool intersects (const hb_set_t *glyphs) const
843 844 845 846 847
  {
    /* 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 已提交
848
	return true;
849
    return false;
850
  }
851
  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
852
  { return glyphs->has (glyphArray[index]); }
853

854
  template <typename set_t>
855
  bool add_coverage (set_t *glyphs) const
856
  { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
857

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

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

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

B
Behdad Esfahbod 已提交
882 883
struct CoverageFormat2
{
884 885 886
  friend struct Coverage;

  private:
887
  unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
888
  {
889 890 891 892
    const RangeRecord &range = rangeRecord.bsearch (glyph_id);
    return likely (range.start <= range.end) ?
	   (unsigned int) range.value + (glyph_id - range.start) :
	   NOT_COVERED;
893 894
  }

B
Behdad Esfahbod 已提交
895 896 897
  template <typename Iterator,
	    hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
898
  {
B
Behdad Esfahbod 已提交
899
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
900
    if (unlikely (!c->extend_min (*this))) return_trace (false);
901

902
    if (unlikely (!glyphs))
903 904 905 906
    {
      rangeRecord.len.set (0);
      return_trace (true);
    }
907 908
    /* TODO(iter) Port to non-random-access iterator interface. */
    unsigned int count = glyphs.len ();
909

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

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

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

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

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

B
Behdad Esfahbod 已提交
974 975
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
976
  struct iter_t
977
  {
978
    void init (const CoverageFormat2 &c_)
979
    {
B
Behdad Esfahbod 已提交
980 981 982
      c = &c_;
      coverage = 0;
      i = 0;
983 984 985
      j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
      if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
      {
E
Ebrahim Byagowi 已提交
986 987
	/* Broken table. Skip. */
	i = c->rangeRecord.len;
988
      }
B
Behdad Esfahbod 已提交
989
    }
990
    void fini () {}
991
    bool more () const { return i < c->rangeRecord.len; }
992
    void next ()
993 994 995
    {
      if (j >= c->rangeRecord[i].end)
      {
E
Ebrahim Byagowi 已提交
996
	i++;
B
Behdad Esfahbod 已提交
997
	if (more ())
998
	{
999
	  unsigned int old = coverage;
B
Behdad Esfahbod 已提交
1000
	  j = c->rangeRecord[i].start;
1001
	  coverage = c->rangeRecord[i].value;
B
Behdad Esfahbod 已提交
1002
	  if (unlikely (coverage != old + 1))
1003
	  {
B
Behdad Esfahbod 已提交
1004 1005 1006 1007
	    /* Broken table. Skip. Important to avoid DoS.
	     * Also, our callers depend on coverage being
	     * consecutive and monotonically increasing,
	     * ie. iota(). */
1008 1009 1010
	   i = c->rangeRecord.len;
	   return;
	  }
1011
	}
B
Behdad Esfahbod 已提交
1012
	return;
B
Behdad Esfahbod 已提交
1013
      }
1014
      coverage++;
B
Behdad Esfahbod 已提交
1015 1016
      j++;
    }
1017
    hb_codepoint_t get_glyph () const { return j; }
B
Behdad Esfahbod 已提交
1018 1019 1020

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

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

B
Behdad Esfahbod 已提交
1036 1037
struct Coverage
{
B
Behdad Esfahbod 已提交
1038
  /* Has interface. */
1039
  static constexpr unsigned SENTINEL = NOT_COVERED;
1040 1041 1042
  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 已提交
1043
  /* Predicate. */
1044
  bool operator () (hb_codepoint_t k) const { return has (k); }
1045

1046
  unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
1047
  unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1048
  {
1049
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1050 1051
    case 1: return u.format1.get_coverage (glyph_id);
    case 2: return u.format2.get_coverage (glyph_id);
1052 1053 1054 1055
    default:return NOT_COVERED;
    }
  }

B
Behdad Esfahbod 已提交
1056 1057 1058
  template <typename Iterator,
	    hb_enable_if (hb_is_sorted_iterator_of (Iterator, const GlyphID))>
  bool serialize (hb_serialize_context_t *c, Iterator glyphs)
1059
  {
B
Behdad Esfahbod 已提交
1060
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1061
    if (unlikely (!c->extend_min (*this))) return_trace (false);
1062

1063 1064
    /* TODO(iter) Port to non-random-access iterator interface. */
    unsigned int count = glyphs.len ();
1065
    unsigned int num_ranges = 1;
1066
    for (unsigned int i = 1; i < count; i++)
1067
      if (glyphs[i - 1] + 1 != glyphs[i])
E
Ebrahim Byagowi 已提交
1068
	num_ranges++;
1069
    u.format.set (count * 2 < num_ranges * 3 ? 1 : 2);
1070

1071 1072
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1073 1074
    case 1: return_trace (u.format1.serialize (c, glyphs));
    case 2: return_trace (u.format2.serialize (c, glyphs));
B
Behdad Esfahbod 已提交
1075
    default:return_trace (false);
1076 1077 1078
    }
  }

1079
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1080
  {
B
Behdad Esfahbod 已提交
1081
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1082
    if (!u.format.sanitize (c)) return_trace (false);
1083 1084
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1085 1086 1087
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1088 1089
    }
  }
1090

1091
  bool intersects (const hb_set_t *glyphs) const
1092
  {
1093 1094 1095 1096 1097 1098
    switch (u.format)
    {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
1099
  }
1100
  bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
1101 1102 1103
  {
    switch (u.format)
    {
1104 1105 1106 1107
    case 1: return u.format1.intersects_coverage (glyphs, index);
    case 2: return u.format2.intersects_coverage (glyphs, index);
    default:return false;
    }
B
Behdad Esfahbod 已提交
1108 1109
  }

B
Behdad Esfahbod 已提交
1110 1111
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
1112
  template <typename set_t>
1113
  bool add_coverage (set_t *glyphs) const
1114 1115 1116
  {
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1117 1118
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1119
    default:return false;
1120 1121 1122
    }
  }

B
Behdad Esfahbod 已提交
1123
  struct iter_t :
1124 1125 1126
    hb_iter_with_mixin_t<hb_iter_fallback_mixin_t,
			 iter_t,
			 hb_codepoint_t>
1127
  {
1128
    static constexpr bool is_sorted_iterator = true;
B
Behdad Esfahbod 已提交
1129
    iter_t (const Coverage &c_ = Null(Coverage))
1130
    {
1131
      memset (this, 0, sizeof (*this));
B
Behdad Esfahbod 已提交
1132
      format = c_.u.format;
1133 1134
      switch (format)
      {
B
Minor  
Behdad Esfahbod 已提交
1135 1136
      case 1: u.format1.init (c_.u.format1); return;
      case 2: u.format2.init (c_.u.format2); return;
1137
      default:				     return;
B
Behdad Esfahbod 已提交
1138 1139
      }
    }
1140
    bool __more__ () const
1141 1142 1143
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1144 1145
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
1146
      default:return false;
B
Behdad Esfahbod 已提交
1147 1148
      }
    }
1149
    void __next__ ()
1150 1151 1152
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1153 1154
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
1155
      default:			 break;
B
Behdad Esfahbod 已提交
1156 1157
      }
    }
1158 1159
    typedef hb_codepoint_t __item_t__;
    __item_t__ __item__ () const { return get_glyph (); }
1160

1161
    hb_codepoint_t get_glyph () const
1162 1163 1164
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1165 1166
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
1167
      default:return 0;
B
Behdad Esfahbod 已提交
1168 1169
      }
    }
B
Behdad Esfahbod 已提交
1170 1171

    private:
B
Behdad Esfahbod 已提交
1172
    unsigned int format;
B
Behdad Esfahbod 已提交
1173
    union {
B
Behdad Esfahbod 已提交
1174 1175
    CoverageFormat2::iter_t	format2; /* Put this one first since it's larger; helps shut up compiler. */
    CoverageFormat1::iter_t	format1;
B
Behdad Esfahbod 已提交
1176 1177
    } u;
  };
B
Behdad Esfahbod 已提交
1178
  iter_t iter () const { return iter_t (*this); }
B
Behdad Esfahbod 已提交
1179

1180
  protected:
1181
  union {
B
Behdad Esfahbod 已提交
1182
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1183 1184
  CoverageFormat1	format1;
  CoverageFormat2	format2;
1185
  } u;
B
Behdad Esfahbod 已提交
1186
  public:
B
Behdad Esfahbod 已提交
1187
  DEFINE_SIZE_UNION (2, format);
1188 1189 1190 1191 1192 1193 1194
};


/*
 * Class Definition Table
 */

B
Behdad Esfahbod 已提交
1195
static inline void ClassDef_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1196 1197
				       hb_array_t<const GlyphID> glyphs,
				       hb_array_t<const HBUINT16> klasses);
B
Behdad Esfahbod 已提交
1198

B
Behdad Esfahbod 已提交
1199 1200
struct ClassDefFormat1
{
1201 1202 1203
  friend struct ClassDef;

  private:
1204
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1205
  {
B
Minor  
Behdad Esfahbod 已提交
1206
    return classValue[(unsigned int) (glyph_id - startGlyph)];
1207 1208
  }

1209
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1210
		  hb_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1211
		  hb_array_t<const HBUINT16> klasses)
1212 1213 1214 1215
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

1216
    if (unlikely (!glyphs))
1217 1218 1219 1220 1221 1222
    {
      startGlyph.set (0);
      classValue.len.set (0);
      return_trace (true);
    }

B
Behdad Esfahbod 已提交
1223
    hb_codepoint_t glyph_min = glyphs[0];
1224
    hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
1225 1226 1227 1228 1229

    startGlyph.set (glyph_min);
    classValue.len.set (glyph_max - glyph_min + 1);
    if (unlikely (!c->extend (classValue))) return_trace (false);

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

1233 1234 1235
    return_trace (true);
  }

1236
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1237 1238
  {
    TRACE_SUBSET (this);
1239
    const hb_set_t &glyphset = *c->plan->glyphset;
B
Behdad Esfahbod 已提交
1240
    const hb_map_t &glyph_map = *c->plan->glyph_map;
B
Behdad Esfahbod 已提交
1241
    hb_sorted_vector_t<GlyphID> glyphs;
1242 1243
    hb_vector_t<HBUINT16> klasses;

1244 1245 1246 1247
    hb_codepoint_t start = startGlyph;
    hb_codepoint_t end   = start + classValue.len;
    for (hb_codepoint_t g = start; g < end; g++)
    {
B
Behdad Esfahbod 已提交
1248
      if (!glyphset.has (g)) continue;
1249 1250
      unsigned int value = classValue[g - start];
      if (!value) continue;
1251
      glyphs.push()->set (glyph_map[g]);
1252
      klasses.push()->set (value);
1253
    }
1254
    c->serializer->propagate_error (glyphs, klasses);
B
Behdad Esfahbod 已提交
1255
    ClassDef_serialize (c->serializer, glyphs, klasses);
1256
    return_trace ((bool) glyphs);
B
Behdad Esfahbod 已提交
1257 1258
  }

1259
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1260
  {
B
Behdad Esfahbod 已提交
1261
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1262
    return_trace (c->check_struct (this) && classValue.sanitize (c));
B
Behdad Esfahbod 已提交
1263 1264
  }

1265
  template <typename set_t>
1266 1267
  bool add_coverage (set_t *glyphs) const
  {
1268 1269 1270 1271 1272
    unsigned int start = 0;
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
    {
      if (classValue[i])
E
Ebrahim Byagowi 已提交
1273
	continue;
1274 1275 1276

      if (start != i)
	if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1277
	  return false;
1278 1279 1280 1281 1282

      start = i + 1;
    }
    if (start != count)
      if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1283
	return false;
1284 1285 1286 1287 1288

    return true;
  }

  template <typename set_t>
1289 1290
  bool add_class (set_t *glyphs, unsigned int klass) const
  {
1291 1292
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
E
Ebrahim Byagowi 已提交
1293
      if (classValue[i] == klass) glyphs->add (startGlyph + i);
B
Behdad Esfahbod 已提交
1294
    return true;
1295 1296
  }

1297
  bool intersects (const hb_set_t *glyphs) const
1298 1299 1300 1301 1302 1303
  {
    /* 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 已提交
1304
      if (classValue[iter - start]) return true;
1305 1306
    return false;
  }
1307 1308
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
  {
1309
    unsigned int count = classValue.len;
1310 1311 1312
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1313
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
E
Ebrahim Byagowi 已提交
1314 1315
      if (!hb_set_next (glyphs, &g)) return false;
      if (g < startGlyph) return true;
1316
      g = startGlyph + count - 1;
E
Ebrahim Byagowi 已提交
1317
      if (hb_set_next (glyphs, &g)) return true;
1318 1319
      /* Fall through. */
    }
1320 1321
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass && glyphs->has (startGlyph + i))
E
Ebrahim Byagowi 已提交
1322
	return true;
1323 1324 1325
    return false;
  }

1326
  protected:
B
Behdad Esfahbod 已提交
1327 1328
  HBUINT16	classFormat;	/* Format identifier--format = 1 */
  GlyphID	startGlyph;	/* First GlyphID of the classValueArray */
B
Behdad Esfahbod 已提交
1329
  ArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
1330
		classValue;	/* Array of Class Values--one per GlyphID */
1331
  public:
1332
  DEFINE_SIZE_ARRAY (6, classValue);
1333 1334
};

B
Behdad Esfahbod 已提交
1335 1336
struct ClassDefFormat2
{
1337 1338 1339
  friend struct ClassDef;

  private:
1340
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1341
  {
1342
    return rangeRecord.bsearch (glyph_id).value;
1343 1344
  }

1345
  bool serialize (hb_serialize_context_t *c,
B
Minor  
Behdad Esfahbod 已提交
1346
		  hb_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1347
		  hb_array_t<const HBUINT16> klasses)
1348 1349 1350 1351
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

1352
    if (unlikely (!glyphs))
1353 1354 1355 1356 1357 1358
    {
      rangeRecord.len.set (0);
      return_trace (true);
    }

    unsigned int num_ranges = 1;
1359
    for (unsigned int i = 1; i < glyphs.length; i++)
1360 1361 1362 1363 1364 1365 1366 1367 1368
      if (glyphs[i - 1] + 1 != glyphs[i] ||
	  klasses[i - 1] != klasses[i])
	num_ranges++;
    rangeRecord.len.set (num_ranges);
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);

    unsigned int range = 0;
    rangeRecord[range].start = glyphs[0];
    rangeRecord[range].value.set (klasses[0]);
1369
    for (unsigned int i = 1; i < glyphs.length; i++)
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
    {
      if (glyphs[i - 1] + 1 != glyphs[i] ||
	  klasses[i - 1] != klasses[i])
      {
	range++;
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value = klasses[i];
      }
      rangeRecord[range].end = glyphs[i];
    }
    return_trace (true);
  }

1383
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1384 1385 1386 1387 1388
  {
    TRACE_SUBSET (this);
    const hb_set_t &glyphset = *c->plan->glyphset;
    const hb_map_t &glyph_map = *c->plan->glyph_map;
    hb_vector_t<GlyphID> glyphs;
1389
    hb_vector_t<HBUINT16> klasses;
B
Behdad Esfahbod 已提交
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404

    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;
	glyphs.push ()->set (glyph_map[g]);
	klasses.push ()->set (value);
      }
    }
1405
    c->serializer->propagate_error (glyphs, klasses);
B
Behdad Esfahbod 已提交
1406
    ClassDef_serialize (c->serializer, glyphs, klasses);
1407
    return_trace ((bool) glyphs);
B
Behdad Esfahbod 已提交
1408 1409
  }

1410
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1411
  {
B
Behdad Esfahbod 已提交
1412
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1413
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
1414 1415
  }

1416
  template <typename set_t>
1417
  bool add_coverage (set_t *glyphs) const
1418
  {
1419 1420 1421 1422
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value)
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1423
	  return false;
1424 1425 1426 1427
    return true;
  }

  template <typename set_t>
1428
  bool add_class (set_t *glyphs, unsigned int klass) const
1429
  {
1430 1431
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1432
    {
1433
      if (rangeRecord[i].value == klass)
E
Ebrahim Byagowi 已提交
1434
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1435
	  return false;
B
Behdad Esfahbod 已提交
1436 1437
    }
    return true;
1438 1439
  }

1440
  bool intersects (const hb_set_t *glyphs) const
1441 1442 1443 1444 1445
  {
    /* 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 已提交
1446
	return true;
1447 1448
    return false;
  }
1449
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
1450
  {
1451
    unsigned int count = rangeRecord.len;
1452 1453 1454
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1455
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1456 1457 1458 1459 1460 1461 1462 1463
      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;
      }
1464
      if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
E
Ebrahim Byagowi 已提交
1465
	return true;
1466 1467
      /* Fall through. */
    }
1468 1469
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
E
Ebrahim Byagowi 已提交
1470
	return true;
1471 1472 1473
    return false;
  }

1474
  protected:
B
Behdad Esfahbod 已提交
1475
  HBUINT16	classFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1476
  SortedArrayOf<RangeRecord>
1477 1478
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID */
1479
  public:
1480
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1481 1482
};

B
Behdad Esfahbod 已提交
1483 1484
struct ClassDef
{
B
Behdad Esfahbod 已提交
1485
  /* Has interface. */
1486
  static constexpr unsigned SENTINEL = 0;
1487 1488 1489
  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 已提交
1490 1491
  /* Projection. */
  hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
1492

1493
  unsigned int get (hb_codepoint_t k) const { return get_class (k); }
1494
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1495
  {
1496
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1497 1498
    case 1: return u.format1.get_class (glyph_id);
    case 2: return u.format2.get_class (glyph_id);
1499 1500 1501 1502
    default:return 0;
    }
  }

1503
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1504 1505
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const HBUINT16> klasses)
1506 1507 1508 1509
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

B
Behdad Esfahbod 已提交
1510
    unsigned int format = 2;
1511
    if (likely (glyphs))
1512
    {
B
Behdad Esfahbod 已提交
1513
      hb_codepoint_t glyph_min = glyphs[0];
1514
      hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
B
Behdad Esfahbod 已提交
1515 1516

      unsigned int num_ranges = 1;
1517
      for (unsigned int i = 1; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
1518 1519 1520 1521 1522 1523
	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;
1524
    }
B
Behdad Esfahbod 已提交
1525
    u.format.set (format);
1526 1527 1528

    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1529 1530
    case 1: return_trace (u.format1.serialize (c, glyphs, klasses));
    case 2: return_trace (u.format2.serialize (c, glyphs, klasses));
1531 1532 1533 1534
    default:return_trace (false);
    }
  }

1535
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1536 1537 1538 1539 1540 1541 1542 1543 1544
  {
    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);
    }
  }

1545
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1546
  {
B
Behdad Esfahbod 已提交
1547
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1548
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
1549
    switch (u.format) {
B
Behdad Esfahbod 已提交
1550 1551 1552
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1553 1554
    }
  }
1555

1556 1557 1558
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
  template <typename set_t>
1559 1560
  bool add_coverage (set_t *glyphs) const
  {
1561 1562 1563
    switch (u.format) {
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1564
    default:return false;
1565 1566 1567 1568 1569
    }
  }

  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
B
Behdad Esfahbod 已提交
1570
  template <typename set_t>
1571 1572
  bool add_class (set_t *glyphs, unsigned int klass) const
  {
1573
    switch (u.format) {
1574 1575
    case 1: return u.format1.add_class (glyphs, klass);
    case 2: return u.format2.add_class (glyphs, klass);
B
Behdad Esfahbod 已提交
1576
    default:return false;
1577 1578 1579
    }
  }

1580 1581
  bool intersects (const hb_set_t *glyphs) const
  {
1582 1583 1584 1585 1586 1587
    switch (u.format) {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
  }
1588 1589
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
  {
1590 1591 1592 1593 1594 1595 1596
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1597
  protected:
1598
  union {
B
Behdad Esfahbod 已提交
1599
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1600 1601
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1602
  } u;
B
Behdad Esfahbod 已提交
1603
  public:
B
Behdad Esfahbod 已提交
1604
  DEFINE_SIZE_UNION (2, format);
1605 1606
};

B
Behdad Esfahbod 已提交
1607
static inline void ClassDef_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1608 1609 1610
				       hb_array_t<const GlyphID> glyphs,
				       hb_array_t<const HBUINT16> klasses)
{ c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); }
B
Behdad Esfahbod 已提交
1611

1612

1613 1614 1615 1616 1617 1618
/*
 * Item Variation Store
 */

struct VarRegionAxis
{
1619
  float evaluate (int coord) const
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641
  {
    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);
  }

1642
  bool sanitize (hb_sanitize_context_t *c) const
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
  {
    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
{
1660
  float evaluate (unsigned int region_index,
B
Bruce Mitchener 已提交
1661
			 const int *coords, unsigned int coord_len) const
1662 1663 1664 1665
  {
    if (unlikely (region_index >= regionCount))
      return 0.;

1666
    const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1667 1668

    float v = 1.;
1669
    unsigned int count = axisCount;
1670 1671
    for (unsigned int i = 0; i < count; i++)
    {
1672 1673
      int coord = i < coord_len ? coords[i] : 0;
      float factor = axes[i].evaluate (coord);
1674
      if (factor == 0.f)
E
Ebrahim Byagowi 已提交
1675
	return 0.;
1676 1677 1678 1679 1680
      v *= factor;
    }
    return v;
  }

1681
  bool sanitize (hb_sanitize_context_t *c) const
1682 1683 1684
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
1685
		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1686 1687
  }

1688
  unsigned int get_region_count () const { return regionCount; }
1689

1690
  protected:
B
Behdad Esfahbod 已提交
1691 1692
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1693 1694
  UnsizedArrayOf<VarRegionAxis>
		axesZ;
1695 1696 1697 1698 1699 1700
  public:
  DEFINE_SIZE_ARRAY (4, axesZ);
};

struct VarData
{
1701
  unsigned int get_region_index_count () const
M
Michiharu Ariza 已提交
1702 1703
  { return regionIndices.len; }

1704
  unsigned int get_row_size () const
1705 1706
  { return shortCount + regionIndices.len; }

1707
  unsigned int get_size () const
1708 1709
  { return itemCount * get_row_size (); }

1710
  float get_delta (unsigned int inner,
B
Bruce Mitchener 已提交
1711
			  const int *coords, unsigned int coord_count,
1712 1713 1714 1715 1716 1717 1718 1719
			  const VarRegionList &regions) const
  {
    if (unlikely (inner >= itemCount))
      return 0.;

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

B
Behdad Esfahbod 已提交
1720 1721
   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
   const HBUINT8 *row = bytes + inner * (scount + count);
1722 1723 1724 1725

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

B
Behdad Esfahbod 已提交
1726
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1727 1728
   for (; i < scount; i++)
   {
1729
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1730 1731
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1732
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1733 1734
   for (; i < count; i++)
   {
1735
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1736 1737 1738 1739 1740 1741
     delta += scalar * *bcursor++;
   }

   return delta;
  }

1742
  void get_scalars (int *coords, unsigned int coord_count,
M
Michiharu Ariza 已提交
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
                    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);
   }
  }
1753 1754

  bool sanitize (hb_sanitize_context_t *c) const
1755 1756 1757
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
E
Ebrahim Byagowi 已提交
1758
		  regionIndices.sanitize (c) &&
1759
		  shortCount <= regionIndices.len &&
1760 1761 1762
		  c->check_range (&StructAfter<HBUINT8> (regionIndices),
				  itemCount,
				  get_row_size ()));
1763 1764 1765
  }

  protected:
B
Behdad Esfahbod 已提交
1766 1767 1768
  HBUINT16		itemCount;
  HBUINT16		shortCount;
  ArrayOf<HBUINT16>	regionIndices;
B
Behdad Esfahbod 已提交
1769
/*UnsizedArrayOf<HBUINT8>bytesX;*/
1770
  public:
B
Behdad Esfahbod 已提交
1771
  DEFINE_SIZE_ARRAY (6, regionIndices);
1772 1773
};

1774
struct VariationStore
1775
{
1776 1777
  float get_delta (unsigned int outer, unsigned int inner,
		   const int *coords, unsigned int coord_count) const
1778 1779 1780 1781 1782 1783 1784 1785 1786
  {
    if (unlikely (outer >= dataSets.len))
      return 0.;

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

1787 1788
  float get_delta (unsigned int index,
		   const int *coords, unsigned int coord_count) const
1789 1790 1791 1792 1793 1794
  {
    unsigned int outer = index >> 16;
    unsigned int inner = index & 0xFFFF;
    return get_delta (outer, inner, coords, coord_count);
  }

1795
  bool sanitize (hb_sanitize_context_t *c) const
1796 1797 1798 1799 1800 1801 1802 1803
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  format == 1 &&
		  regions.sanitize (c, this) &&
		  dataSets.sanitize (c, this));
  }

1804
  unsigned int get_region_index_count (unsigned int ivs) const
M
Michiharu Ariza 已提交
1805 1806
  { return (this+dataSets[ivs]).get_region_index_count (); }

1807 1808 1809 1810
  void get_scalars (unsigned int ivs,
		    int *coords, unsigned int coord_count,
		    float *scalars /*OUT*/,
		    unsigned int num_scalars) const
M
Michiharu Ariza 已提交
1811 1812 1813 1814
  {
    (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
                                      &scalars[0], num_scalars);
  }
1815

1816
  protected:
B
Behdad Esfahbod 已提交
1817
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1818
  LOffsetTo<VarRegionList>		regions;
B
Minor  
Behdad Esfahbod 已提交
1819
  LOffsetArrayOf<VarData>		dataSets;
1820 1821 1822 1823
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

1824 1825 1826 1827 1828 1829 1830 1831 1832
/*
 * Feature Variations
 */

struct ConditionFormat1
{
  friend struct Condition;

  private:
1833
  bool evaluate (const int *coords, unsigned int coord_len) const
1834 1835 1836 1837 1838
  {
    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
  }

1839
  bool sanitize (hb_sanitize_context_t *c) const
1840 1841 1842 1843 1844 1845
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  protected:
B
Behdad Esfahbod 已提交
1846 1847
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1848 1849 1850 1851 1852 1853 1854 1855
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1856
  bool evaluate (const int *coords, unsigned int coord_len) const
1857 1858 1859 1860 1861 1862 1863
  {
    switch (u.format) {
    case 1: return u.format1.evaluate (coords, coord_len);
    default:return false;
    }
  }

1864
  bool sanitize (hb_sanitize_context_t *c) const
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
  {
    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 已提交
1876
  HBUINT16		format;		/* Format identifier */
1877 1878 1879 1880 1881 1882 1883 1884
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct ConditionSet
{
1885
  bool evaluate (const int *coords, unsigned int coord_len) const
1886 1887 1888
  {
    unsigned int count = conditions.len;
    for (unsigned int i = 0; i < count; i++)
1889
      if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
E
Ebrahim Byagowi 已提交
1890
	return false;
1891 1892 1893
    return true;
  }

1894
  bool sanitize (hb_sanitize_context_t *c) const
1895 1896 1897 1898 1899 1900
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, this));
  }

  protected:
B
Minor  
Behdad Esfahbod 已提交
1901
  LOffsetArrayOf<Condition>	conditions;
1902 1903 1904 1905 1906 1907
  public:
  DEFINE_SIZE_ARRAY (2, conditions);
};

struct FeatureTableSubstitutionRecord
{
1908
  friend struct FeatureTableSubstitution;
1909

1910
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1911 1912
  {
    TRACE_SANITIZE (this);
1913
    return_trace (c->check_struct (this) && feature.sanitize (c, base));
1914 1915 1916
  }

  protected:
B
Behdad Esfahbod 已提交
1917
  HBUINT16		featureIndex;
B
Behdad Esfahbod 已提交
1918
  LOffsetTo<Feature>	feature;
1919 1920 1921 1922 1923 1924
  public:
  DEFINE_SIZE_STATIC (6);
};

struct FeatureTableSubstitution
{
1925
  const Feature *find_substitute (unsigned int feature_index) const
1926 1927 1928 1929
  {
    unsigned int count = substitutions.len;
    for (unsigned int i = 0; i < count; i++)
    {
1930
      const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1931 1932
      if (record.featureIndex == feature_index)
	return &(this+record.feature);
1933
    }
B
Behdad Esfahbod 已提交
1934
    return nullptr;
1935 1936
  }

1937
  bool sanitize (hb_sanitize_context_t *c) const
1938 1939 1940 1941 1942 1943 1944 1945 1946
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  substitutions.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
1947
  ArrayOf<FeatureTableSubstitutionRecord>
1948 1949 1950 1951 1952 1953 1954 1955 1956
			substitutions;
  public:
  DEFINE_SIZE_ARRAY (6, substitutions);
};

struct FeatureVariationRecord
{
  friend struct FeatureVariations;

1957
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1958 1959 1960 1961 1962 1963 1964
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, base) &&
		  substitutions.sanitize (c, base));
  }

  protected:
B
Behdad Esfahbod 已提交
1965
  LOffsetTo<ConditionSet>
1966
			conditions;
B
Behdad Esfahbod 已提交
1967
  LOffsetTo<FeatureTableSubstitution>
1968 1969 1970 1971 1972 1973 1974
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct FeatureVariations
{
1975
  static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
1976

1977
  bool find_index (const int *coords, unsigned int coord_len,
1978
			  unsigned int *index) const
1979 1980 1981 1982
  {
    unsigned int count = varRecords.len;
    for (unsigned int i = 0; i < count; i++)
    {
1983
      const FeatureVariationRecord &record = varRecords.arrayZ[i];
1984
      if ((this+record.conditions).evaluate (coords, coord_len))
1985 1986 1987 1988
      {
	*index = i;
	return true;
      }
1989
    }
1990
    *index = NOT_FOUND_INDEX;
1991
    return false;
1992 1993
  }

1994 1995
  const Feature *find_substitute (unsigned int variations_index,
				  unsigned int feature_index) const
1996 1997 1998 1999 2000
  {
    const FeatureVariationRecord &record = varRecords[variations_index];
    return (this+record.substitutions).find_substitute (feature_index);
  }

2001
  bool subset (hb_subset_context_t *c) const
2002 2003 2004 2005 2006
  {
    TRACE_SUBSET (this);
    return_trace (c->serializer->embed (*this));
  }

2007
  bool sanitize (hb_sanitize_context_t *c) const
2008 2009 2010 2011 2012 2013 2014 2015 2016
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  varRecords.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
B
Behdad Esfahbod 已提交
2017
  LArrayOf<FeatureVariationRecord>
2018 2019
			varRecords;
  public:
2020
  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
2021 2022
};

2023

2024 2025 2026 2027
/*
 * Device Tables
 */

2028
struct HintingDevice
B
Behdad Esfahbod 已提交
2029
{
2030 2031 2032
  friend struct Device;

  private:
B
Behdad Esfahbod 已提交
2033

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

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

2040
  unsigned int get_size () const
B
Minor  
Behdad Esfahbod 已提交
2041 2042
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
2043 2044
    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 已提交
2045 2046
  }

2047
  bool sanitize (hb_sanitize_context_t *c) const
B
Minor  
Behdad Esfahbod 已提交
2048 2049 2050 2051 2052 2053 2054
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
  }

  private:

2055
  int get_delta (unsigned int ppem, int scale) const
2056 2057 2058 2059 2060 2061 2062
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

B
Behdad Esfahbod 已提交
2063
    return (int) (pixels * (int64_t) scale / ppem);
2064
  }
2065
  int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
2066
  {
2067
    unsigned int f = deltaFormat;
2068
    if (unlikely (f < 1 || f > 3))
2069
      return 0;
2070

2071 2072
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
2073

2074
    unsigned int s = ppem_size - startSize;
2075

2076
    unsigned int byte = deltaValueZ[s >> (4 - f)];
B
Behdad Esfahbod 已提交
2077
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
2078
    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
2079 2080 2081

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
2082
    if ((unsigned int) delta >= ((mask + 1) >> 1))
2083 2084 2085 2086 2087
      delta -= mask + 1;

    return delta;
  }

2088
  protected:
B
Behdad Esfahbod 已提交
2089 2090 2091
  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
2092 2093 2094 2095
					 * 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
					 */
2096 2097
  UnsizedArrayOf<HBUINT16>
		deltaValueZ;		/* Array of compressed data */
B
Behdad Esfahbod 已提交
2098
  public:
2099
  DEFINE_SIZE_ARRAY (6, deltaValueZ);
2100 2101
};

2102 2103
struct VariationDevice
{
2104 2105 2106
  friend struct Device;

  private:
2107

2108
  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
2109
  { return font->em_scalef_x (get_delta (font, store)); }
2110

2111
  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
2112
  { return font->em_scalef_y (get_delta (font, store)); }
2113

2114
  bool sanitize (hb_sanitize_context_t *c) const
2115 2116
  {
    TRACE_SANITIZE (this);
2117
    return_trace (c->check_struct (this));
2118 2119 2120 2121
  }

  private:

2122
  float get_delta (hb_font_t *font, const VariationStore &store) const
2123
  {
2124
    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
2125 2126 2127
  }

  protected:
B
Behdad Esfahbod 已提交
2128 2129 2130
  HBUINT16	outerIndex;
  HBUINT16	innerIndex;
  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
2131
  public:
2132
  DEFINE_SIZE_STATIC (6);
2133 2134
};

2135 2136 2137
struct DeviceHeader
{
  protected:
B
Behdad Esfahbod 已提交
2138 2139
  HBUINT16		reserved1;
  HBUINT16		reserved2;
2140
  public:
B
Behdad Esfahbod 已提交
2141
  HBUINT16		format;		/* Format identifier */
2142 2143 2144 2145
  public:
  DEFINE_SIZE_STATIC (6);
};

2146 2147
struct Device
{
2148
  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2149 2150 2151 2152 2153
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
2154
    case 0x8000:
2155
      return u.variation.get_x_delta (font, store);
2156 2157 2158 2159
    default:
      return 0;
    }
  }
2160
  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2161 2162 2163 2164
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
2165
      return u.hinting.get_y_delta (font);
2166
    case 0x8000:
2167
      return u.variation.get_y_delta (font, store);
2168 2169 2170 2171 2172
    default:
      return 0;
    }
  }

2173
  bool sanitize (hb_sanitize_context_t *c) const
2174 2175 2176 2177 2178 2179
  {
    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));
2180
    case 0x8000:
2181 2182 2183 2184 2185 2186 2187 2188
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

  protected:
  union {
2189
  DeviceHeader		b;
2190 2191 2192 2193 2194 2195 2196
  HintingDevice		hinting;
  VariationDevice	variation;
  } u;
  public:
  DEFINE_SIZE_UNION (6, b);
};

2197

B
Behdad Esfahbod 已提交
2198
} /* namespace OT */
2199

B
Behdad Esfahbod 已提交
2200

2201
#endif /* HB_OT_LAYOUT_COMMON_HH */