hb-ot-layout-common.hh 59.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

B
Behdad Esfahbod 已提交
69

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

76

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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


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


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

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

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

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

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

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

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

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

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

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

typedef RecordListOf<Script> ScriptList;

310

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

560
  bool subset (hb_subset_context_t *c) const
561 562 563 564 565 566 567 568
  {
    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);
  }

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

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

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

591
    if (likely (orig_offset.is_null ()))
B
Behdad Esfahbod 已提交
592
      return_trace (true);
593

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

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

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

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

typedef RecordListOf<Feature> FeatureList;


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return_trace (true);
  }

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

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

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

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

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

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

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

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

829
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
830
		  hb_array_t<const GlyphID> 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. */
860 861
  struct Iter
  {
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 867
    hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
    unsigned int get_coverage () const { return i; }
B
Behdad Esfahbod 已提交
868 869 870 871 872

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

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

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

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

896
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
897
		  hb_array_t<const GlyphID> 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
    unsigned int num_ranges = 1;
909
    for (unsigned int i = 1; i < glyphs.length; i++)
910
      if (glyphs[i - 1] + 1 != glyphs[i])
E
Ebrahim Byagowi 已提交
911
	num_ranges++;
912
    rangeRecord.len.set (num_ranges);
B
Behdad Esfahbod 已提交
913
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
914

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

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

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

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

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

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

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

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

1043
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1044
		  hb_array_t<const GlyphID> glyphs)
1045
  {
B
Behdad Esfahbod 已提交
1046
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1047
    if (unlikely (!c->extend_min (*this))) return_trace (false);
1048

1049
    unsigned int num_ranges = 1;
1050
    for (unsigned int i = 1; i < glyphs.length; i++)
1051
      if (glyphs[i - 1] + 1 != glyphs[i])
E
Ebrahim Byagowi 已提交
1052
	num_ranges++;
1053
    u.format.set (glyphs.length * 2 < num_ranges * 3 ? 1 : 2);
1054

1055 1056
    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1057 1058
    case 1: return_trace (u.format1.serialize (c, glyphs));
    case 2: return_trace (u.format2.serialize (c, glyphs));
B
Behdad Esfahbod 已提交
1059
    default:return_trace (false);
1060 1061 1062
    }
  }

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

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

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

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

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

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


/*
 * Class Definition Table
 */

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

B
Behdad Esfahbod 已提交
1184 1185
struct ClassDefFormat1
{
1186 1187 1188
  friend struct ClassDef;

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

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

1201
    if (unlikely (!glyphs))
1202 1203 1204 1205 1206 1207
    {
      startGlyph.set (0);
      classValue.len.set (0);
      return_trace (true);
    }

B
Behdad Esfahbod 已提交
1208
    hb_codepoint_t glyph_min = glyphs[0];
1209
    hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
1210 1211 1212 1213 1214

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

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

1218 1219 1220
    return_trace (true);
  }

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

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

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

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

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

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

    return true;
  }

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

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

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

B
Behdad Esfahbod 已提交
1320 1321
struct ClassDefFormat2
{
1322 1323 1324
  friend struct ClassDef;

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

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

1337
    if (unlikely (!glyphs))
1338 1339 1340 1341 1342 1343
    {
      rangeRecord.len.set (0);
      return_trace (true);
    }

    unsigned int num_ranges = 1;
1344
    for (unsigned int i = 1; i < glyphs.length; i++)
1345 1346 1347 1348 1349 1350 1351 1352 1353
      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]);
1354
    for (unsigned int i = 1; i < glyphs.length; i++)
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367
    {
      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);
  }

1368
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1369 1370 1371 1372 1373
  {
    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;
1374
    hb_vector_t<HBUINT16> klasses;
B
Behdad Esfahbod 已提交
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389

    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);
      }
    }
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
{
1470
  unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1471
  {
1472
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1473 1474
    case 1: return u.format1.get_class (glyph_id);
    case 2: return u.format2.get_class (glyph_id);
1475 1476 1477 1478
    default:return 0;
    }
  }

1479
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1480 1481
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const HBUINT16> klasses)
1482 1483 1484 1485
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);

B
Behdad Esfahbod 已提交
1486
    unsigned int format = 2;
1487
    if (likely (glyphs))
1488
    {
B
Behdad Esfahbod 已提交
1489
      hb_codepoint_t glyph_min = glyphs[0];
1490
      hb_codepoint_t glyph_max = glyphs[glyphs.length - 1];
B
Behdad Esfahbod 已提交
1491 1492

      unsigned int num_ranges = 1;
1493
      for (unsigned int i = 1; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
1494 1495 1496 1497 1498 1499
	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;
1500
    }
B
Behdad Esfahbod 已提交
1501
    u.format.set (format);
1502 1503 1504

    switch (u.format)
    {
B
Behdad Esfahbod 已提交
1505 1506
    case 1: return_trace (u.format1.serialize (c, glyphs, klasses));
    case 2: return_trace (u.format2.serialize (c, glyphs, klasses));
1507 1508 1509 1510
    default:return_trace (false);
    }
  }

1511
  bool subset (hb_subset_context_t *c) const
B
Behdad Esfahbod 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520
  {
    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);
    }
  }

1521
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1522
  {
B
Behdad Esfahbod 已提交
1523
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1524
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
1525
    switch (u.format) {
B
Behdad Esfahbod 已提交
1526 1527 1528
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1529 1530
    }
  }
1531

1532 1533 1534
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
  template <typename set_t>
1535 1536
  bool add_coverage (set_t *glyphs) const
  {
1537 1538 1539
    switch (u.format) {
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1540
    default:return false;
1541 1542 1543 1544 1545
    }
  }

  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
B
Behdad Esfahbod 已提交
1546
  template <typename set_t>
1547 1548
  bool add_class (set_t *glyphs, unsigned int klass) const
  {
1549
    switch (u.format) {
1550 1551
    case 1: return u.format1.add_class (glyphs, klass);
    case 2: return u.format2.add_class (glyphs, klass);
B
Behdad Esfahbod 已提交
1552
    default:return false;
1553 1554 1555
    }
  }

1556 1557
  bool intersects (const hb_set_t *glyphs) const
  {
1558 1559 1560 1561 1562 1563
    switch (u.format) {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
  }
1564 1565
  bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
  {
1566 1567 1568 1569 1570 1571 1572
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1573
  protected:
1574
  union {
B
Behdad Esfahbod 已提交
1575
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1576 1577
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1578
  } u;
B
Behdad Esfahbod 已提交
1579
  public:
B
Behdad Esfahbod 已提交
1580
  DEFINE_SIZE_UNION (2, format);
1581 1582
};

B
Behdad Esfahbod 已提交
1583
static inline void ClassDef_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1584 1585 1586
				       hb_array_t<const GlyphID> glyphs,
				       hb_array_t<const HBUINT16> klasses)
{ c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); }
B
Behdad Esfahbod 已提交
1587

1588

1589 1590 1591 1592 1593 1594
/*
 * Item Variation Store
 */

struct VarRegionAxis
{
1595
  float evaluate (int coord) const
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617
  {
    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);
  }

1618
  bool sanitize (hb_sanitize_context_t *c) const
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
  {
    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
{
1636
  float evaluate (unsigned int region_index,
B
Bruce Mitchener 已提交
1637
			 const int *coords, unsigned int coord_len) const
1638 1639 1640 1641
  {
    if (unlikely (region_index >= regionCount))
      return 0.;

1642
    const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1643 1644

    float v = 1.;
1645
    unsigned int count = axisCount;
1646 1647
    for (unsigned int i = 0; i < count; i++)
    {
1648 1649
      int coord = i < coord_len ? coords[i] : 0;
      float factor = axes[i].evaluate (coord);
1650
      if (factor == 0.f)
E
Ebrahim Byagowi 已提交
1651
	return 0.;
1652 1653 1654 1655 1656
      v *= factor;
    }
    return v;
  }

1657
  bool sanitize (hb_sanitize_context_t *c) const
1658 1659 1660
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
1661
		  axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1662 1663
  }

1664
  unsigned int get_region_count () const { return regionCount; }
1665

1666
  protected:
B
Behdad Esfahbod 已提交
1667 1668
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1669 1670
  UnsizedArrayOf<VarRegionAxis>
		axesZ;
1671 1672 1673 1674 1675 1676
  public:
  DEFINE_SIZE_ARRAY (4, axesZ);
};

struct VarData
{
1677
  unsigned int get_region_index_count () const
M
Michiharu Ariza 已提交
1678 1679
  { return regionIndices.len; }

1680
  unsigned int get_row_size () const
1681 1682
  { return shortCount + regionIndices.len; }

1683
  unsigned int get_size () const
1684 1685
  { return itemCount * get_row_size (); }

1686
  float get_delta (unsigned int inner,
B
Bruce Mitchener 已提交
1687
			  const int *coords, unsigned int coord_count,
1688 1689 1690 1691 1692 1693 1694 1695
			  const VarRegionList &regions) const
  {
    if (unlikely (inner >= itemCount))
      return 0.;

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

B
Behdad Esfahbod 已提交
1696 1697
   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
   const HBUINT8 *row = bytes + inner * (scount + count);
1698 1699 1700 1701

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

B
Behdad Esfahbod 已提交
1702
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1703 1704
   for (; i < scount; i++)
   {
1705
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1706 1707
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1708
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1709 1710
   for (; i < count; i++)
   {
1711
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1712 1713 1714 1715 1716 1717
     delta += scalar * *bcursor++;
   }

   return delta;
  }

1718
  void get_scalars (int *coords, unsigned int coord_count,
M
Michiharu Ariza 已提交
1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
                    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);
   }
  }
1729 1730

  bool sanitize (hb_sanitize_context_t *c) const
1731 1732 1733
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
E
Ebrahim Byagowi 已提交
1734
		  regionIndices.sanitize (c) &&
1735
		  shortCount <= regionIndices.len &&
1736 1737 1738
		  c->check_range (&StructAfter<HBUINT8> (regionIndices),
				  itemCount,
				  get_row_size ()));
1739 1740 1741
  }

  protected:
B
Behdad Esfahbod 已提交
1742 1743 1744
  HBUINT16		itemCount;
  HBUINT16		shortCount;
  ArrayOf<HBUINT16>	regionIndices;
B
Behdad Esfahbod 已提交
1745
/*UnsizedArrayOf<HBUINT8>bytesX;*/
1746
  public:
B
Behdad Esfahbod 已提交
1747
  DEFINE_SIZE_ARRAY (6, regionIndices);
1748 1749
};

1750
struct VariationStore
1751
{
1752 1753
  float get_delta (unsigned int outer, unsigned int inner,
		   const int *coords, unsigned int coord_count) const
1754 1755 1756 1757 1758 1759 1760 1761 1762
  {
    if (unlikely (outer >= dataSets.len))
      return 0.;

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

1763 1764
  float get_delta (unsigned int index,
		   const int *coords, unsigned int coord_count) const
1765 1766 1767 1768 1769 1770
  {
    unsigned int outer = index >> 16;
    unsigned int inner = index & 0xFFFF;
    return get_delta (outer, inner, coords, coord_count);
  }

1771
  bool sanitize (hb_sanitize_context_t *c) const
1772 1773 1774 1775 1776 1777 1778 1779
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  format == 1 &&
		  regions.sanitize (c, this) &&
		  dataSets.sanitize (c, this));
  }

1780
  unsigned int get_region_index_count (unsigned int ivs) const
M
Michiharu Ariza 已提交
1781 1782
  { return (this+dataSets[ivs]).get_region_index_count (); }

1783 1784 1785 1786
  void get_scalars (unsigned int ivs,
		    int *coords, unsigned int coord_count,
		    float *scalars /*OUT*/,
		    unsigned int num_scalars) const
M
Michiharu Ariza 已提交
1787 1788 1789 1790
  {
    (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
                                      &scalars[0], num_scalars);
  }
1791

1792
  protected:
B
Behdad Esfahbod 已提交
1793
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1794
  LOffsetTo<VarRegionList>		regions;
B
Minor  
Behdad Esfahbod 已提交
1795
  LOffsetArrayOf<VarData>		dataSets;
1796 1797 1798 1799
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

1800 1801 1802 1803 1804 1805 1806 1807 1808
/*
 * Feature Variations
 */

struct ConditionFormat1
{
  friend struct Condition;

  private:
1809
  bool evaluate (const int *coords, unsigned int coord_len) const
1810 1811 1812 1813 1814
  {
    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
  }

1815
  bool sanitize (hb_sanitize_context_t *c) const
1816 1817 1818 1819 1820 1821
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  protected:
B
Behdad Esfahbod 已提交
1822 1823
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1824 1825 1826 1827 1828 1829 1830 1831
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1832
  bool evaluate (const int *coords, unsigned int coord_len) const
1833 1834 1835 1836 1837 1838 1839
  {
    switch (u.format) {
    case 1: return u.format1.evaluate (coords, coord_len);
    default:return false;
    }
  }

1840
  bool sanitize (hb_sanitize_context_t *c) const
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
  {
    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 已提交
1852
  HBUINT16		format;		/* Format identifier */
1853 1854 1855 1856 1857 1858 1859 1860
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct ConditionSet
{
1861
  bool evaluate (const int *coords, unsigned int coord_len) const
1862 1863 1864
  {
    unsigned int count = conditions.len;
    for (unsigned int i = 0; i < count; i++)
1865
      if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
E
Ebrahim Byagowi 已提交
1866
	return false;
1867 1868 1869
    return true;
  }

1870
  bool sanitize (hb_sanitize_context_t *c) const
1871 1872 1873 1874 1875 1876
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, this));
  }

  protected:
B
Minor  
Behdad Esfahbod 已提交
1877
  LOffsetArrayOf<Condition>	conditions;
1878 1879 1880 1881 1882 1883
  public:
  DEFINE_SIZE_ARRAY (2, conditions);
};

struct FeatureTableSubstitutionRecord
{
1884
  friend struct FeatureTableSubstitution;
1885

1886
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1887 1888
  {
    TRACE_SANITIZE (this);
1889
    return_trace (c->check_struct (this) && feature.sanitize (c, base));
1890 1891 1892
  }

  protected:
B
Behdad Esfahbod 已提交
1893
  HBUINT16		featureIndex;
B
Behdad Esfahbod 已提交
1894
  LOffsetTo<Feature>	feature;
1895 1896 1897 1898 1899 1900
  public:
  DEFINE_SIZE_STATIC (6);
};

struct FeatureTableSubstitution
{
1901
  const Feature *find_substitute (unsigned int feature_index) const
1902 1903 1904 1905
  {
    unsigned int count = substitutions.len;
    for (unsigned int i = 0; i < count; i++)
    {
1906
      const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1907 1908
      if (record.featureIndex == feature_index)
	return &(this+record.feature);
1909
    }
B
Behdad Esfahbod 已提交
1910
    return nullptr;
1911 1912
  }

1913
  bool sanitize (hb_sanitize_context_t *c) const
1914 1915 1916 1917 1918 1919 1920 1921 1922
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  substitutions.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
1923
  ArrayOf<FeatureTableSubstitutionRecord>
1924 1925 1926 1927 1928 1929 1930 1931 1932
			substitutions;
  public:
  DEFINE_SIZE_ARRAY (6, substitutions);
};

struct FeatureVariationRecord
{
  friend struct FeatureVariations;

1933
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1934 1935 1936 1937 1938 1939 1940
  {
    TRACE_SANITIZE (this);
    return_trace (conditions.sanitize (c, base) &&
		  substitutions.sanitize (c, base));
  }

  protected:
B
Behdad Esfahbod 已提交
1941
  LOffsetTo<ConditionSet>
1942
			conditions;
B
Behdad Esfahbod 已提交
1943
  LOffsetTo<FeatureTableSubstitution>
1944 1945 1946 1947 1948 1949 1950
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct FeatureVariations
{
1951
  enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
1952

1953
  bool find_index (const int *coords, unsigned int coord_len,
1954
			  unsigned int *index) const
1955 1956 1957 1958
  {
    unsigned int count = varRecords.len;
    for (unsigned int i = 0; i < count; i++)
    {
1959
      const FeatureVariationRecord &record = varRecords.arrayZ[i];
1960
      if ((this+record.conditions).evaluate (coords, coord_len))
1961 1962 1963 1964
      {
	*index = i;
	return true;
      }
1965
    }
1966
    *index = NOT_FOUND_INDEX;
1967
    return false;
1968 1969
  }

1970 1971
  const Feature *find_substitute (unsigned int variations_index,
				  unsigned int feature_index) const
1972 1973 1974 1975 1976
  {
    const FeatureVariationRecord &record = varRecords[variations_index];
    return (this+record.substitutions).find_substitute (feature_index);
  }

1977
  bool subset (hb_subset_context_t *c) const
1978 1979 1980 1981 1982
  {
    TRACE_SUBSET (this);
    return_trace (c->serializer->embed (*this));
  }

1983
  bool sanitize (hb_sanitize_context_t *c) const
1984 1985 1986 1987 1988 1989 1990 1991 1992
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  varRecords.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
B
Behdad Esfahbod 已提交
1993
  LArrayOf<FeatureVariationRecord>
1994 1995
			varRecords;
  public:
1996
  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
1997 1998
};

1999

2000 2001 2002 2003
/*
 * Device Tables
 */

2004
struct HintingDevice
B
Behdad Esfahbod 已提交
2005
{
2006 2007 2008
  friend struct Device;

  private:
B
Behdad Esfahbod 已提交
2009

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

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

2016
  unsigned int get_size () const
B
Minor  
Behdad Esfahbod 已提交
2017 2018
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
2019 2020
    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 已提交
2021 2022
  }

2023
  bool sanitize (hb_sanitize_context_t *c) const
B
Minor  
Behdad Esfahbod 已提交
2024 2025 2026 2027 2028 2029 2030
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
  }

  private:

2031
  int get_delta (unsigned int ppem, int scale) const
2032 2033 2034 2035 2036 2037 2038
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

B
Behdad Esfahbod 已提交
2039
    return (int) (pixels * (int64_t) scale / ppem);
2040
  }
2041
  int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
2042
  {
2043
    unsigned int f = deltaFormat;
2044
    if (unlikely (f < 1 || f > 3))
2045
      return 0;
2046

2047 2048
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
2049

2050
    unsigned int s = ppem_size - startSize;
2051

2052
    unsigned int byte = deltaValueZ[s >> (4 - f)];
B
Behdad Esfahbod 已提交
2053
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
2054
    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
2055 2056 2057

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
2058
    if ((unsigned int) delta >= ((mask + 1) >> 1))
2059 2060 2061 2062 2063
      delta -= mask + 1;

    return delta;
  }

2064
  protected:
B
Behdad Esfahbod 已提交
2065 2066 2067
  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
2068 2069 2070 2071
					 * 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
					 */
2072 2073
  UnsizedArrayOf<HBUINT16>
		deltaValueZ;		/* Array of compressed data */
B
Behdad Esfahbod 已提交
2074
  public:
2075
  DEFINE_SIZE_ARRAY (6, deltaValueZ);
2076 2077
};

2078 2079
struct VariationDevice
{
2080 2081 2082
  friend struct Device;

  private:
2083

2084
  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
2085
  { return font->em_scalef_x (get_delta (font, store)); }
2086

2087
  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
2088
  { return font->em_scalef_y (get_delta (font, store)); }
2089

2090
  bool sanitize (hb_sanitize_context_t *c) const
2091 2092
  {
    TRACE_SANITIZE (this);
2093
    return_trace (c->check_struct (this));
2094 2095 2096 2097
  }

  private:

2098
  float get_delta (hb_font_t *font, const VariationStore &store) const
2099
  {
2100
    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
2101 2102 2103
  }

  protected:
B
Behdad Esfahbod 已提交
2104 2105 2106
  HBUINT16	outerIndex;
  HBUINT16	innerIndex;
  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
2107
  public:
2108
  DEFINE_SIZE_STATIC (6);
2109 2110
};

2111 2112 2113
struct DeviceHeader
{
  protected:
B
Behdad Esfahbod 已提交
2114 2115
  HBUINT16		reserved1;
  HBUINT16		reserved2;
2116
  public:
B
Behdad Esfahbod 已提交
2117
  HBUINT16		format;		/* Format identifier */
2118 2119 2120 2121
  public:
  DEFINE_SIZE_STATIC (6);
};

2122 2123
struct Device
{
2124
  hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2125 2126 2127 2128 2129
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
2130
    case 0x8000:
2131
      return u.variation.get_x_delta (font, store);
2132 2133 2134 2135
    default:
      return 0;
    }
  }
2136
  hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2137 2138 2139 2140
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
2141
      return u.hinting.get_y_delta (font);
2142
    case 0x8000:
2143
      return u.variation.get_y_delta (font, store);
2144 2145 2146 2147 2148
    default:
      return 0;
    }
  }

2149
  bool sanitize (hb_sanitize_context_t *c) const
2150 2151 2152 2153 2154 2155
  {
    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));
2156
    case 0x8000:
2157 2158 2159 2160 2161 2162 2163 2164
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

  protected:
  union {
2165
  DeviceHeader		b;
2166 2167 2168 2169 2170 2171 2172
  HintingDevice		hinting;
  VariationDevice	variation;
  } u;
  public:
  DEFINE_SIZE_UNION (6, b);
};

2173

B
Behdad Esfahbod 已提交
2174
} /* namespace OT */
2175

B
Behdad Esfahbod 已提交
2176

2177
#endif /* HB_OT_LAYOUT_COMMON_HH */