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

29 30
#ifndef HB_OT_LAYOUT_COMMON_HH
#define HB_OT_LAYOUT_COMMON_HH
31

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


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


55 56 57
namespace OT {


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

B
Behdad Esfahbod 已提交
60

B
Behdad Esfahbod 已提交
61

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

68

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

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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


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


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

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

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

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

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

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

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

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

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

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

typedef RecordListOf<Script> ScriptList;

314

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
612
    return_trace (true);
B
Behdad Esfahbod 已提交
613 614
  }

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

typedef RecordListOf<Feature> FeatureList;


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

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

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

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

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

664 665 666 667 668 669 670 671
  inline unsigned int get_size (void) const
  {
    const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable);
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
      return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this;
    return (const char *) &markFilteringSet - (const char *) this;
  }

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

  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
   * higher 16-bit is mark-filtering-set if the lookup uses one.
   * Not to be confused with glyph_props which is very similar. */
  inline uint32_t get_props (void) const
678 679
  {
    unsigned int flag = lookupFlag;
680
    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
681
    {
B
Behdad Esfahbod 已提交
682
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
683
      flag += (markFilteringSet << 16);
684 685 686
    }
    return flag;
  }
687

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

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

B
Behdad Esfahbod 已提交
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
  /* Older compileres need this to NOT be locally defined in a function. */
  template <typename TSubTable>
  struct SubTableSubsetWrapper
  {
    inline SubTableSubsetWrapper (const TSubTable &subtable_,
				  unsigned int lookup_type_) :
				    subtable (subtable_),
				    lookup_type (lookup_type_) {}

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

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

738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
  template <typename TSubTable>
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    struct Lookup *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);

    /* Subset the actual subtables. */
    /* TODO Drop empty ones, either by calling intersects() beforehand,
     * or just dropping null offsets after. */
    const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
    OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
    unsigned int count = subTable.len;
    for (unsigned int i = 0; i < count; i++)
    {
B
Behdad Esfahbod 已提交
753
      SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
754 755 756 757 758 759 760

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

    return_trace (true);
  }

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

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

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

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

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
809 810
struct CoverageFormat1
{
811 812 813
  friend struct Coverage;

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

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

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

841 842 843 844 845 846 847 848
  inline bool intersects (const hb_set_t *glyphs) const
  {
    /* TODO Speed up, using hb_set_next() and bsearch()? */
    unsigned int count = glyphArray.len;
    for (unsigned int i = 0; i < count; i++)
      if (glyphs->has (glyphArray[i]))
        return true;
    return false;
849
  }
850 851
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  { return glyphs->has (glyphArray[index]); }
852

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

B
Behdad Esfahbod 已提交
858 859
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
860
  struct Iter {
B
Behdad Esfahbod 已提交
861
    inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
862
    inline void fini (void) {};
B
Behdad Esfahbod 已提交
863 864
    inline bool more (void) { return i < c->glyphArray.len; }
    inline void next (void) { i++; }
865 866
    inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
    inline unsigned int get_coverage (void) { return 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:
B
Behdad Esfahbod 已提交
887 888
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
889
    int i = rangeRecord.bsearch (glyph_id);
B
Behdad Esfahbod 已提交
890 891 892
    if (i != -1) {
      const RangeRecord &range = rangeRecord[i];
      return (unsigned int) range.value + (glyph_id - range.start);
893 894 895 896
    }
    return NOT_COVERED;
  }

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

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

910 911 912 913
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        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 921 922
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i]) {
	range++;
923 924 925
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value.set (i);
        rangeRecord[range].end = glyphs[i];
926
      } else {
927
        rangeRecord[range].end = glyphs[i];
928
      }
929
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
930
    return_trace (true);
931 932
  }

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

939 940 941 942 943 944 945 946 947 948 949
  inline bool intersects (const hb_set_t *glyphs) const
  {
    /* TODO Speed up, using hb_set_next() and bsearch()? */
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  {
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 957 958 959 960 961 962 963
	  range.intersects (glyphs))
        return true;
      else if (index < range.value)
        return false;
    }
    return false;
  }

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
1063 1064
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
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 1076
  inline bool intersects (const hb_set_t *glyphs) const
  {
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 1085 1086 1087
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
  {
    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 1098 1099 1100
  inline bool add_coverage (set_t *glyphs) const
  {
    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 (void) : format (0), u () {};
1110 1111
    inline void init (const Coverage &c_)
    {
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 1121 1122 1123 1124
    inline void fini (void) {}
    inline bool more (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1125 1126
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
1127
      default:return false;
B
Behdad Esfahbod 已提交
1128 1129
      }
    }
1130 1131 1132 1133
    inline void next (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1134 1135
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
1136
      default:			 break;
B
Behdad Esfahbod 已提交
1137 1138
      }
    }
1139 1140 1141 1142
    inline hb_codepoint_t get_glyph (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1143 1144
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
1145
      default:return 0;
B
Behdad Esfahbod 已提交
1146 1147
      }
    }
1148 1149 1150 1151
    inline unsigned int get_coverage (void)
    {
      switch (format)
      {
B
Behdad Esfahbod 已提交
1152 1153
      case 1: return u.format1.get_coverage ();
      case 2: return u.format2.get_coverage ();
B
Minor  
Behdad Esfahbod 已提交
1154
      default:return -1;
B
Behdad Esfahbod 已提交
1155 1156 1157 1158
      }
    }

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

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


/*
 * Class Definition Table
 */

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

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

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

1200
  template <typename set_t>
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
  inline bool add_coverage (set_t *glyphs) const {
    unsigned int start = 0;
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
    {
      if (classValue[i])
        continue;

      if (start != i)
	if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1211
	  return false;
1212 1213 1214 1215 1216

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

    return true;
  }

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

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

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

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

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

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

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

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

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

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

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

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

1382 1383 1384 1385 1386 1387 1388
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
  template <typename set_t>
  inline bool add_coverage (set_t *glyphs) const {
    switch (u.format) {
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
1389
    default:return false;
1390 1391 1392 1393 1394
    }
  }

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

1404 1405 1406 1407 1408 1409 1410
  inline bool intersects (const hb_set_t *glyphs) const {
    switch (u.format) {
    case 1: return u.format1.intersects (glyphs);
    case 2: return u.format2.intersects (glyphs);
    default:return false;
    }
  }
1411
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1412 1413 1414 1415 1416 1417 1418
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1419
  protected:
1420
  union {
B
Behdad Esfahbod 已提交
1421
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1422 1423
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1424
  } u;
B
Behdad Esfahbod 已提交
1425
  public:
B
Behdad Esfahbod 已提交
1426
  DEFINE_SIZE_UNION (2, format);
1427 1428 1429
};


1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
/*
 * Item Variation Store
 */

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

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

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

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

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

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

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

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

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

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

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

  protected:
B
Behdad Esfahbod 已提交
1506 1507
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1508 1509
  UnsizedArrayOf<VarRegionAxis>
		axesZ;
1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
  public:
  DEFINE_SIZE_ARRAY (4, axesZ);
};

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
1538
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1539 1540
   for (; i < scount; i++)
   {
1541
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1542 1543
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1544
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1545 1546
   for (; i < count; i++)
   {
1547
     float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
     delta += scalar * *bcursor++;
   }

   return delta;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  regionIndices.sanitize(c) &&
		  shortCount <= regionIndices.len &&
B
Behdad Esfahbod 已提交
1560
		  c->check_array (&StructAfter<HBUINT8> (regionIndices),
1561
				  itemCount, get_row_size ()));
1562 1563 1564
  }

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

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

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

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

1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  format == 1 &&
		  regions.sanitize (c, this) &&
		  dataSets.sanitize (c, this));
  }

  protected:
B
Behdad Esfahbod 已提交
1604
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1605
  LOffsetTo<VarRegionList>		regions;
B
Behdad Esfahbod 已提交
1606
  OffsetArrayOf<VarData, HBUINT32>	dataSets;
1607 1608 1609 1610
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

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

struct ConditionFormat1
{
  friend struct Condition;

  private:
1620
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
  {
    int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
    return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
  }

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

  protected:
B
Behdad Esfahbod 已提交
1633 1634
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1635 1636 1637 1638 1639 1640 1641 1642
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1643
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
  {
    switch (u.format) {
    case 1: return u.format1.evaluate (coords, coord_len);
    default:return false;
    }
  }

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

  protected:
  union {
B
Behdad Esfahbod 已提交
1663
  HBUINT16		format;		/* Format identifier */
1664 1665 1666 1667 1668 1669 1670 1671
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

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

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

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

struct FeatureTableSubstitutionRecord
{
1695
  friend struct FeatureTableSubstitution;
1696

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

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

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

1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  substitutions.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
1734
  ArrayOf<FeatureTableSubstitutionRecord>
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
			substitutions;
  public:
  DEFINE_SIZE_ARRAY (6, substitutions);
};

struct FeatureVariationRecord
{
  friend struct FeatureVariations;

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

  protected:
B
Behdad Esfahbod 已提交
1752
  LOffsetTo<ConditionSet>
1753
			conditions;
B
Behdad Esfahbod 已提交
1754
  LOffsetTo<FeatureTableSubstitution>
1755 1756 1757 1758 1759 1760 1761
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

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

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

1781 1782 1783 1784 1785 1786 1787
  inline const Feature *find_substitute (unsigned int variations_index,
					 unsigned int feature_index) const
  {
    const FeatureVariationRecord &record = varRecords[variations_index];
    return (this+record.substitutions).find_substitute (feature_index);
  }

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

1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  varRecords.sanitize (c, this));
  }

  protected:
  FixedVersion<>	version;	/* Version--0x00010000u */
B
Behdad Esfahbod 已提交
1804
  LArrayOf<FeatureVariationRecord>
1805 1806
			varRecords;
  public:
1807
  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
1808 1809
};

1810

1811 1812 1813 1814
/*
 * Device Tables
 */

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

  private:
B
Behdad Esfahbod 已提交
1820

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

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

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

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

  private:

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

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

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

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

1861
    unsigned int s = ppem_size - startSize;
1862

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

    int delta = bits & mask;

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

    return delta;
  }

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

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

  private:
1894

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

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

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

  private:

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

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

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

1933 1934
struct Device
{
1935
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1936 1937 1938 1939 1940
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
1941
    case 0x8000:
1942
      return u.variation.get_x_delta (font, store);
1943 1944 1945 1946
    default:
      return 0;
    }
  }
1947
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1948 1949 1950 1951
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
1952
      return u.hinting.get_y_delta (font);
1953
    case 0x8000:
1954
      return u.variation.get_y_delta (font, store);
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
    default:
      return 0;
    }
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (!u.b.format.sanitize (c)) return_trace (false);
    switch (u.b.format) {
    case 1: case 2: case 3:
      return_trace (u.hinting.sanitize (c));
1967
    case 0x8000:
1968 1969 1970 1971 1972 1973 1974 1975
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

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

1984

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

B
Behdad Esfahbod 已提交
1987

1988
#endif /* HB_OT_LAYOUT_COMMON_HH */