hb-ot-layout-common-private.hh 49.2 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_PRIVATE_HH
#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
31

32 33
#include "hb-private.hh"
#include "hb-debug.hh"
34
#include "hb-ot-layout-private.hh"
35
#include "hb-open-type-private.hh"
B
Behdad Esfahbod 已提交
36
#include "hb-set-private.hh"
37 38


39 40 41 42 43 44 45 46
#ifndef HB_MAX_NESTING_LEVEL
#define HB_MAX_NESTING_LEVEL	6
#endif
#ifndef HB_MAX_CONTEXT_LENGTH
#define HB_MAX_CONTEXT_LENGTH	64
#endif


47 48 49
namespace OT {


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

B
Behdad Esfahbod 已提交
52

B
Behdad Esfahbod 已提交
53

54 55 56 57 58 59
/*
 *
 * OpenType Layout Common Table Formats
 *
 */

60

61 62 63 64 65
/*
 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
 */

template <typename Type>
B
Behdad Esfahbod 已提交
66 67
struct Record
{
68
  inline int cmp (hb_tag_t a) const {
69
    return tag.cmp (a);
B
Behdad Esfahbod 已提交
70 71
  }

72 73
  struct sanitize_closure_t {
    hb_tag_t tag;
B
Behdad Esfahbod 已提交
74
    const void *list_base;
75
  };
B
Behdad Esfahbod 已提交
76 77
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
78
    TRACE_SANITIZE (this);
79
    const sanitize_closure_t closure = {tag, base};
B
Behdad Esfahbod 已提交
80
    return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
B
Behdad Esfahbod 已提交
81 82
  }

83 84 85 86
  Tag		tag;		/* 4-byte Tag identifier */
  OffsetTo<Type>
		offset;		/* Offset from beginning of object holding
				 * the Record */
B
Behdad Esfahbod 已提交
87 88
  public:
  DEFINE_SIZE_STATIC (6);
89 90 91
};

template <typename Type>
B
Behdad Esfahbod 已提交
92
struct RecordArrayOf : SortedArrayOf<Record<Type> > {
B
Behdad Esfahbod 已提交
93 94
  inline const Tag& get_tag (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
95 96 97
    /* We cheat slightly and don't define separate Null objects
     * for Record types.  Instead, we return the correct Null(Tag)
     * here. */
98
    if (unlikely (i >= this->len)) return Null(Tag);
B
Behdad Esfahbod 已提交
99
    return (*this)[i].tag;
100
  }
B
Behdad Esfahbod 已提交
101 102 103
  inline unsigned int get_tags (unsigned int start_offset,
				unsigned int *record_count /* IN/OUT */,
				hb_tag_t     *record_tags /* OUT */) const
104
  {
B
Behdad Esfahbod 已提交
105
    if (record_count) {
B
Behdad Esfahbod 已提交
106
      const Record<Type> *arr = this->sub_array (start_offset, record_count);
B
Behdad Esfahbod 已提交
107
      unsigned int count = *record_count;
B
Behdad Esfahbod 已提交
108
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
109
	record_tags[i] = arr[i].tag;
B
Behdad Esfahbod 已提交
110 111
    }
    return this->len;
112 113 114
  }
  inline bool find_index (hb_tag_t tag, unsigned int *index) const
  {
115 116
    /* If we want to allow non-sorted data, we can lsearch(). */
    int i = this->/*lsearch*/bsearch (tag);
B
Behdad Esfahbod 已提交
117
    if (i != -1) {
118 119
        if (index) *index = i;
        return true;
B
Behdad Esfahbod 已提交
120 121 122
    } else {
      if (index) *index = Index::NOT_FOUND_INDEX;
      return false;
123 124 125 126 127 128 129 130
    }
  }
};

template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
  inline const Type& operator [] (unsigned int i) const
B
Behdad Esfahbod 已提交
131
  { return this+RecordArrayOf<Type>::operator [](i).offset; }
B
Behdad Esfahbod 已提交
132

B
Behdad Esfahbod 已提交
133 134
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
135
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
136
    return_trace (RecordArrayOf<Type>::sanitize (c, this));
B
Behdad Esfahbod 已提交
137
  }
138 139 140
};


B
Behdad Esfahbod 已提交
141 142 143
struct RangeRecord
{
  inline int cmp (hb_codepoint_t g) const {
B
Minor  
Behdad Esfahbod 已提交
144
    return g < start ? -1 : g <= end ? 0 : +1 ;
B
Behdad Esfahbod 已提交
145 146
  }

B
Behdad Esfahbod 已提交
147 148
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
149
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
150
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
151 152
  }

153
  inline bool intersects (const hb_set_t *glyphs) const {
154 155 156
    return glyphs->intersects (start, end);
  }

157
  template <typename set_t>
B
Behdad Esfahbod 已提交
158
  inline bool add_coverage (set_t *glyphs) const {
159
    return glyphs->add_range (start, end);
160 161
  }

B
Behdad Esfahbod 已提交
162 163
  GlyphID	start;		/* First GlyphID in the range */
  GlyphID	end;		/* Last GlyphID in the range */
B
Behdad Esfahbod 已提交
164
  HBUINT16	value;		/* Value */
B
Behdad Esfahbod 已提交
165 166 167 168 169 170
  public:
  DEFINE_SIZE_STATIC (6);
};
DEFINE_NULL_DATA (RangeRecord, "\000\001");


B
Behdad Esfahbod 已提交
171
struct IndexArray : ArrayOf<Index>
172
{
B
Behdad Esfahbod 已提交
173 174 175
  inline unsigned int get_indexes (unsigned int start_offset,
				   unsigned int *_count /* IN/OUT */,
				   unsigned int *_indexes /* OUT */) const
176
  {
B
Behdad Esfahbod 已提交
177
    if (_count) {
B
Behdad Esfahbod 已提交
178
      const HBUINT16 *arr = this->sub_array (start_offset, _count);
B
Behdad Esfahbod 已提交
179
      unsigned int count = *_count;
B
Behdad Esfahbod 已提交
180
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
181
	_indexes[i] = arr[i];
B
Behdad Esfahbod 已提交
182 183
    }
    return this->len;
184 185 186 187
  }
};


188 189 190 191 192
struct Script;
struct LangSys;
struct Feature;


B
Behdad Esfahbod 已提交
193 194
struct LangSys
{
195 196 197 198
  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 已提交
199 200 201 202
  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); }
203

204
  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
B
Behdad Esfahbod 已提交
205
  inline unsigned int get_required_feature_index (void) const
B
Behdad Esfahbod 已提交
206
  {
207
    if (reqFeatureIndex == 0xFFFFu)
B
Behdad Esfahbod 已提交
208
      return Index::NOT_FOUND_INDEX;
209 210 211
   return reqFeatureIndex;;
  }

212
  inline bool sanitize (hb_sanitize_context_t *c,
B
Behdad Esfahbod 已提交
213
			const Record<LangSys>::sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
214
  {
B
Behdad Esfahbod 已提交
215
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
216
    return_trace (c->check_struct (this) && featureIndex.sanitize (c));
B
Behdad Esfahbod 已提交
217 218
  }

B
Behdad Esfahbod 已提交
219
  Offset16	lookupOrderZ;	/* = Null (reserved for an offset to a
220
				 * reordering table) */
B
Behdad Esfahbod 已提交
221
  HBUINT16	reqFeatureIndex;/* Index of a feature required for this
222
				 * language system--if no required features
223
				 * = 0xFFFFu */
224
  IndexArray	featureIndex;	/* Array of indices into the FeatureList */
B
Behdad Esfahbod 已提交
225
  public:
226
  DEFINE_SIZE_ARRAY (6, featureIndex);
227
};
B
Behdad Esfahbod 已提交
228
DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
229 230


B
Behdad Esfahbod 已提交
231 232
struct Script
{
233 234 235 236
  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 已提交
237 238 239 240
  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 已提交
241 242
  inline const LangSys& get_lang_sys (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
243
    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
244 245
    return this+langSys[i].offset;
  }
246 247
  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
  { return langSys.find_index (tag, index); }
248

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

252
  inline bool sanitize (hb_sanitize_context_t *c,
B
Behdad Esfahbod 已提交
253
			const Record<Script>::sanitize_closure_t * = nullptr) const
B
Behdad Esfahbod 已提交
254
  {
B
Behdad Esfahbod 已提交
255
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
256
    return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
B
Behdad Esfahbod 已提交
257 258
  }

259
  protected:
260 261 262
  OffsetTo<LangSys>
		defaultLangSys;	/* Offset to DefaultLangSys table--from
				 * beginning of Script table--may be Null */
B
Behdad Esfahbod 已提交
263
  RecordArrayOf<LangSys>
264 265
		langSys;	/* Array of LangSysRecords--listed
				 * alphabetically by LangSysTag */
266
  public:
267
  DEFINE_SIZE_ARRAY (4, langSys);
268 269 270 271
};

typedef RecordListOf<Script> ScriptList;

272

273
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
274 275
struct FeatureParamsSize
{
B
Behdad Esfahbod 已提交
276 277
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
278
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
279
    if (unlikely (!c->check_struct (this))) return_trace (false);
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

    /* 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:
295
     * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
296 297 298 299 300 301
     *
     * 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 已提交
302
     * and make the following value checks. If it fails, assume the size
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
     * 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 已提交
331
      return_trace (false);
332 333 334 335
    else if (subfamilyID == 0 &&
	     subfamilyNameID == 0 &&
	     rangeStart == 0 &&
	     rangeEnd == 0)
B
Behdad Esfahbod 已提交
336
      return_trace (true);
337 338 339 340
    else if (designSize < rangeStart ||
	     designSize > rangeEnd ||
	     subfamilyNameID < 256 ||
	     subfamilyNameID > 32767)
B
Behdad Esfahbod 已提交
341
      return_trace (false);
342
    else
B
Behdad Esfahbod 已提交
343
      return_trace (true);
344 345
  }

B
Behdad Esfahbod 已提交
346
  HBUINT16	designSize;	/* Represents the design size in 720/inch
347 348 349 350
				 * 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 已提交
351
  HBUINT16	subfamilyID;	/* Has no independent meaning, but serves
352 353 354 355 356 357 358 359 360
				 * 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 已提交
361
  HBUINT16	subfamilyNameID;/* If the preceding value is non-zero, this
362 363 364 365 366 367 368 369 370 371 372 373 374
				 * 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 已提交
375
  HBUINT16	rangeStart;	/* Large end of the recommended usage range
376 377
				 * (inclusive), stored in 720/inch units
				 * (decipoints). */
B
Behdad Esfahbod 已提交
378
  HBUINT16	rangeEnd;	/* Small end of the recommended usage range
379 380
				   (exclusive), stored in 720/inch units
				 * (decipoints). */
381 382 383 384
  public:
  DEFINE_SIZE_STATIC (10);
};

385
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
386 387
struct FeatureParamsStylisticSet
{
B
Behdad Esfahbod 已提交
388 389
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
390 391 392
    TRACE_SANITIZE (this);
    /* Right now minorVersion is at zero.  Which means, any table supports
     * the uiNameID field. */
B
Behdad Esfahbod 已提交
393
    return_trace (c->check_struct (this));
394 395
  }

B
Behdad Esfahbod 已提交
396
  HBUINT16	version;	/* (set to 0): This corresponds to a “minor”
397 398 399 400
				 * version number. Additional data may be
				 * added to the end of this Feature Parameters
				 * table in the future. */

B
Behdad Esfahbod 已提交
401
  NameID	uiNameID;	/* The 'name' table name ID that specifies a
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
				 * 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);
};

419
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
420 421
struct FeatureParamsCharacterVariants
{
B
Behdad Esfahbod 已提交
422 423
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
424
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
425 426
    return_trace (c->check_struct (this) &&
		  characters.sanitize (c));
427
  }
428

B
Behdad Esfahbod 已提交
429
  HBUINT16	format;			/* Format number is set to 0. */
B
Behdad Esfahbod 已提交
430
  NameID	featUILableNameID;	/* The ‘name’ table name ID that
431 432 433
					 * specifies a string (or strings,
					 * for multiple languages) for a
					 * user-interface label for this
B
Behdad Esfahbod 已提交
434
					 * feature. (May be nullptr.) */
B
Behdad Esfahbod 已提交
435
  NameID	featUITooltipTextNameID;/* The ‘name’ table name ID that
436 437 438 439
					 * specifies a string (or strings,
					 * for multiple languages) that an
					 * application can use for tooltip
					 * text for this feature. (May be
B
Behdad Esfahbod 已提交
440
					 * nullptr.) */
B
Behdad Esfahbod 已提交
441
  NameID	sampleTextNameID;	/* The ‘name’ table name ID that
442 443
					 * specifies sample text that
					 * illustrates the effect of this
B
Behdad Esfahbod 已提交
444
					 * feature. (May be nullptr.) */
B
Behdad Esfahbod 已提交
445
  HBUINT16	numNamedParameters;	/* Number of named parameters. (May
446
					 * be zero.) */
B
Behdad Esfahbod 已提交
447
  NameID	firstParamUILabelNameID;/* The first ‘name’ table name ID
448 449 450 451 452 453 454 455 456 457 458 459 460
					 * used to specify strings for
					 * user-interface labels for the
					 * feature parameters. (Must be zero
					 * if numParameters is zero.) */
  ArrayOf<UINT24>
		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);
};

461 462
struct FeatureParams
{
B
Behdad Esfahbod 已提交
463 464
  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
  {
465
    TRACE_SANITIZE (this);
466
    if (tag == HB_TAG ('s','i','z','e'))
B
Behdad Esfahbod 已提交
467
      return_trace (u.size.sanitize (c));
468
    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
B
Behdad Esfahbod 已提交
469
      return_trace (u.stylisticSet.sanitize (c));
470
    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
B
Behdad Esfahbod 已提交
471 472
      return_trace (u.characterVariants.sanitize (c));
    return_trace (true);
473 474
  }

475 476 477 478 479 480 481 482
  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);
  }

  private:
483
  union {
484 485 486
  FeatureParamsSize			size;
  FeatureParamsStylisticSet		stylisticSet;
  FeatureParamsCharacterVariants	characterVariants;
487
  } u;
488
  DEFINE_SIZE_STATIC (17);
489
};
490

B
Behdad Esfahbod 已提交
491 492
struct Feature
{
493 494 495 496
  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 已提交
497 498 499 500
  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); }
501

502 503 504
  inline const FeatureParams &get_feature_params (void) const
  { return this+featureParams; }

505
  inline bool sanitize (hb_sanitize_context_t *c,
B
Behdad Esfahbod 已提交
506
			const Record<Feature>::sanitize_closure_t *closure = nullptr) const
B
Behdad Esfahbod 已提交
507
  {
B
Behdad Esfahbod 已提交
508
    TRACE_SANITIZE (this);
509
    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
B
Behdad Esfahbod 已提交
510
      return_trace (false);
511

512 513 514 515 516 517
    /* 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.
518 519 520
     *
     * Only do this for the 'size' feature, since at the time of the faulty
     * Adobe tools, only the 'size' feature had FeatureParams defined.
521 522
     */

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

527
    if (likely (orig_offset.is_null ()))
B
Behdad Esfahbod 已提交
528
      return_trace (true);
529

530 531 532
    if (featureParams == 0 && closure &&
	closure->tag == HB_TAG ('s','i','z','e') &&
	closure->list_base && closure->list_base < this)
533
    {
534
      unsigned int new_offset_int = (unsigned int) orig_offset -
B
Behdad Esfahbod 已提交
535
				    (((char *) this) - ((char *) closure->list_base));
536

B
Behdad Esfahbod 已提交
537
      OffsetTo<FeatureParams> new_offset;
538
      /* Check that it did not overflow. */
539 540
      new_offset.set (new_offset_int);
      if (new_offset == new_offset_int &&
541
	  c->try_set (&featureParams, new_offset) &&
542
	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
B
Behdad Esfahbod 已提交
543
	return_trace (false);
544 545 546

      if (c->edit_count > 1)
        c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
547 548
    }

B
Behdad Esfahbod 已提交
549
    return_trace (true);
B
Behdad Esfahbod 已提交
550 551
  }

552 553
  OffsetTo<FeatureParams>
		 featureParams;	/* Offset to Feature Parameters table (if one
554 555 556
				 * has been defined for the feature), relative
				 * to the beginning of the Feature Table; = Null
				 * if not required */
557
  IndexArray	 lookupIndex;	/* Array of LookupList indices */
558
  public:
559
  DEFINE_SIZE_ARRAY (4, lookupIndex);
560 561 562 563 564
};

typedef RecordListOf<Feature> FeatureList;


B
Behdad Esfahbod 已提交
565
struct LookupFlag : HBUINT16
B
Behdad Esfahbod 已提交
566
{
B
Behdad Esfahbod 已提交
567
  enum Flags {
B
Behdad Esfahbod 已提交
568 569 570 571
    RightToLeft		= 0x0001u,
    IgnoreBaseGlyphs	= 0x0002u,
    IgnoreLigatures	= 0x0004u,
    IgnoreMarks		= 0x0008u,
B
Behdad Esfahbod 已提交
572
    IgnoreFlags		= 0x000Eu,
573 574
    UseMarkFilteringSet	= 0x0010u,
    Reserved		= 0x00E0u,
575
    MarkAttachmentType	= 0xFF00u
B
Behdad Esfahbod 已提交
576
  };
577 578
  public:
  DEFINE_SIZE_STATIC (2);
579 580
};

B
Behdad Esfahbod 已提交
581 582
} /* namespace OT */
/* This has to be outside the namespace. */
C
Chun-wei Fan 已提交
583
HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
B
Behdad Esfahbod 已提交
584 585
namespace OT {

B
Behdad Esfahbod 已提交
586 587 588
struct Lookup
{
  inline unsigned int get_subtable_count (void) const { return subTable.len; }
589

590 591 592 593 594 595 596 597 598 599 600
  template <typename SubTableType>
  inline const SubTableType& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }

  template <typename SubTableType>
  inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
  template <typename SubTableType>
  inline OffsetArrayOf<SubTableType>& get_subtables (void)
  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }

601
  inline unsigned int get_type (void) const { return lookupType; }
602 603 604 605 606

  /* 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
607 608
  {
    unsigned int flag = lookupFlag;
609
    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
610
    {
B
Behdad Esfahbod 已提交
611
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
612
      flag += (markFilteringSet << 16);
613 614 615
    }
    return flag;
  }
616

617 618 619 620 621 622 623 624 625
  template <typename SubTableType, typename context_t>
  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++) {
      typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
B
Behdad Esfahbod 已提交
626
        return_trace (r);
627
    }
B
Behdad Esfahbod 已提交
628
    return_trace (c->default_return_value ());
629 630
  }

631 632 633 634 635
  inline bool serialize (hb_serialize_context_t *c,
			 unsigned int lookup_type,
			 uint32_t lookup_props,
			 unsigned int num_subtables)
  {
B
Behdad Esfahbod 已提交
636
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
637
    if (unlikely (!c->extend_min (*this))) return_trace (false);
638
    lookupType.set (lookup_type);
639
    lookupFlag.set (lookup_props & 0xFFFFu);
B
Behdad Esfahbod 已提交
640
    if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
641
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
642
    {
B
Behdad Esfahbod 已提交
643
      HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
644 645
      markFilteringSet.set (lookup_props >> 16);
    }
B
Behdad Esfahbod 已提交
646
    return_trace (true);
647 648
  }

B
Behdad Esfahbod 已提交
649 650
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
651
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
652
    /* Real sanitize of the subtables is done by GSUB/GPOS/... */
B
Behdad Esfahbod 已提交
653
    if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
654
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
655
    {
B
Behdad Esfahbod 已提交
656
      const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
B
Behdad Esfahbod 已提交
657
      if (!markFilteringSet.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
658
    }
B
Behdad Esfahbod 已提交
659
    return_trace (true);
B
Behdad Esfahbod 已提交
660 661
  }

662
  private:
B
Behdad Esfahbod 已提交
663 664
  HBUINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
  HBUINT16	lookupFlag;		/* Lookup qualifiers */
B
Behdad Esfahbod 已提交
665
  ArrayOf<Offset16>
666
		subTable;		/* Array of SubTables */
B
Behdad Esfahbod 已提交
667
  HBUINT16	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
668 669
					 * structure. This field is only present if bit
					 * UseMarkFilteringSet of lookup flags is set. */
B
Behdad Esfahbod 已提交
670
  public:
671
  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
672 673 674 675 676 677 678 679 680
};

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
681 682
struct CoverageFormat1
{
683 684 685
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
686 687
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
688
    int i = glyphArray.bsearch (glyph_id);
689
    static_assert ((((unsigned int) -1) == NOT_COVERED), "");
B
Minor  
Behdad Esfahbod 已提交
690
    return i;
691 692
  }

693
  inline bool serialize (hb_serialize_context_t *c,
694
			 Supplier<GlyphID> &glyphs,
695
			 unsigned int num_glyphs)
696
  {
B
Behdad Esfahbod 已提交
697
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
698
    if (unlikely (!c->extend_min (*this))) return_trace (false);
699
    glyphArray.len.set (num_glyphs);
B
Behdad Esfahbod 已提交
700
    if (unlikely (!c->extend (glyphArray))) return_trace (false);
701
    for (unsigned int i = 0; i < num_glyphs; i++)
702
      glyphArray[i] = glyphs[i];
703
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
704
    return_trace (true);
705 706
  }

B
Behdad Esfahbod 已提交
707 708
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
709
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
710
    return_trace (glyphArray.sanitize (c));
B
Behdad Esfahbod 已提交
711 712
  }

713
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
714 715 716
    return glyphs->has (glyphArray[index]);
  }

717
  template <typename set_t>
B
Behdad Esfahbod 已提交
718 719
  inline bool add_coverage (set_t *glyphs) const {
    return glyphs->add_sorted_array (glyphArray.array, glyphArray.len);
720 721
  }

B
Behdad Esfahbod 已提交
722 723
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
724
  struct Iter {
B
Behdad Esfahbod 已提交
725 726 727
    inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
    inline bool more (void) { return i < c->glyphArray.len; }
    inline void next (void) { i++; }
728 729
    inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
    inline unsigned int get_coverage (void) { return i; }
B
Behdad Esfahbod 已提交
730 731 732 733 734

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

737
  protected:
B
Behdad Esfahbod 已提交
738
  HBUINT16	coverageFormat;	/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
739
  SortedArrayOf<GlyphID>
740
		glyphArray;	/* Array of GlyphIDs--in numerical order */
741
  public:
742
  DEFINE_SIZE_ARRAY (4, glyphArray);
743 744
};

B
Behdad Esfahbod 已提交
745 746
struct CoverageFormat2
{
747 748 749
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
750 751
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
752
    int i = rangeRecord.bsearch (glyph_id);
B
Behdad Esfahbod 已提交
753 754 755
    if (i != -1) {
      const RangeRecord &range = rangeRecord[i];
      return (unsigned int) range.value + (glyph_id - range.start);
756 757 758 759
    }
    return NOT_COVERED;
  }

760
  inline bool serialize (hb_serialize_context_t *c,
761
			 Supplier<GlyphID> &glyphs,
762
			 unsigned int num_glyphs)
763
  {
B
Behdad Esfahbod 已提交
764
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
765
    if (unlikely (!c->extend_min (*this))) return_trace (false);
766

767 768 769 770 771
    if (unlikely (!num_glyphs))
    {
      rangeRecord.len.set (0);
      return_trace (true);
    }
772

773 774 775 776
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
777
    rangeRecord.len.set (num_ranges);
B
Behdad Esfahbod 已提交
778
    if (unlikely (!c->extend (rangeRecord))) return_trace (false);
779

780
    unsigned int range = 0;
781
    rangeRecord[range].start = glyphs[0];
782
    rangeRecord[range].value.set (0);
783 784 785
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i]) {
	range++;
786 787 788
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value.set (i);
        rangeRecord[range].end = glyphs[i];
789
      } else {
790
        rangeRecord[range].end = glyphs[i];
791
      }
792
    glyphs += num_glyphs;
B
Behdad Esfahbod 已提交
793
    return_trace (true);
794 795
  }

B
Behdad Esfahbod 已提交
796 797
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
798
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
799
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
800 801
  }

802
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
803 804 805 806 807
    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 已提交
808
	  index < (unsigned int) range.value + (range.end - range.start) &&
809 810 811 812 813 814 815 816
	  range.intersects (glyphs))
        return true;
      else if (index < range.value)
        return false;
    }
    return false;
  }

817
  template <typename set_t>
B
Behdad Esfahbod 已提交
818
  inline bool add_coverage (set_t *glyphs) const {
819 820
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
821
      if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
822
        return false;
B
Behdad Esfahbod 已提交
823
    return true;
824 825
  }

B
Behdad Esfahbod 已提交
826 827
  public:
  /* Older compilers need this to be public. */
828 829 830 831
  struct Iter
  {
    inline void init (const CoverageFormat2 &c_)
    {
B
Behdad Esfahbod 已提交
832 833 834 835 836 837
      c = &c_;
      coverage = 0;
      i = 0;
      j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
    }
    inline bool more (void) { return i < c->rangeRecord.len; }
838 839 840 841
    inline void next (void)
    {
      if (j >= c->rangeRecord[i].end)
      {
B
Behdad Esfahbod 已提交
842
        i++;
B
Behdad Esfahbod 已提交
843
	if (more ())
844
	{
B
Behdad Esfahbod 已提交
845
	  j = c->rangeRecord[i].start;
846 847
	  coverage = c->rangeRecord[i].value;
	}
B
Behdad Esfahbod 已提交
848
	return;
B
Behdad Esfahbod 已提交
849
      }
850
      coverage++;
B
Behdad Esfahbod 已提交
851 852
      j++;
    }
853 854
    inline hb_codepoint_t get_glyph (void) { return j; }
    inline unsigned int get_coverage (void) { return coverage; }
B
Behdad Esfahbod 已提交
855 856 857

    private:
    const struct CoverageFormat2 *c;
B
Behdad Esfahbod 已提交
858
    unsigned int i, j, coverage;
B
Behdad Esfahbod 已提交
859
  };
B
Behdad Esfahbod 已提交
860
  private:
B
Behdad Esfahbod 已提交
861

862
  protected:
B
Behdad Esfahbod 已提交
863
  HBUINT16	coverageFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
864
  SortedArrayOf<RangeRecord>
865 866 867
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID. rangeCount entries
				 * long */
868
  public:
869
  DEFINE_SIZE_ARRAY (4, rangeRecord);
870 871
};

B
Behdad Esfahbod 已提交
872 873
struct Coverage
{
B
Behdad Esfahbod 已提交
874
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
875
  {
876
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
877 878
    case 1: return u.format1.get_coverage (glyph_id);
    case 2: return u.format2.get_coverage (glyph_id);
879 880 881 882
    default:return NOT_COVERED;
    }
  }

883
  inline bool serialize (hb_serialize_context_t *c,
884
			 Supplier<GlyphID> &glyphs,
885
			 unsigned int num_glyphs)
886
  {
B
Behdad Esfahbod 已提交
887
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
888
    if (unlikely (!c->extend_min (*this))) return_trace (false);
889 890 891 892
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
893 894
    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
    switch (u.format) {
B
Behdad Esfahbod 已提交
895 896 897
    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);
898 899 900
    }
  }

B
Behdad Esfahbod 已提交
901 902
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
903
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
904
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
905
    switch (u.format) {
B
Behdad Esfahbod 已提交
906 907 908
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
909 910
    }
  }
911

912
  inline bool intersects (const hb_set_t *glyphs) const {
B
Behdad Esfahbod 已提交
913 914 915 916 917 918 919
    /* TODO speed this up */
    Coverage::Iter iter;
    for (iter.init (*this); iter.more (); iter.next ()) {
      if (glyphs->has (iter.get_glyph ()))
        return true;
    }
    return false;
920
  }
B
Behdad Esfahbod 已提交
921

922
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
923 924 925 926 927
    switch (u.format) {
    case 1: return u.format1.intersects_coverage (glyphs, index);
    case 2: return u.format2.intersects_coverage (glyphs, index);
    default:return false;
    }
B
Behdad Esfahbod 已提交
928 929
  }

B
Behdad Esfahbod 已提交
930 931
  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
932
  template <typename set_t>
B
Behdad Esfahbod 已提交
933
  inline bool add_coverage (set_t *glyphs) const {
934
    switch (u.format) {
B
Behdad Esfahbod 已提交
935 936
    case 1: return u.format1.add_coverage (glyphs);
    case 2: return u.format2.add_coverage (glyphs);
937
    default:return false;
938 939 940
    }
  }

B
Behdad Esfahbod 已提交
941
  struct Iter {
942
    Iter (void) : format (0), u () {};
B
Behdad Esfahbod 已提交
943
    inline void init (const Coverage &c_) {
B
Behdad Esfahbod 已提交
944 945
      format = c_.u.format;
      switch (format) {
B
Minor  
Behdad Esfahbod 已提交
946 947 948
      case 1: u.format1.init (c_.u.format1); return;
      case 2: u.format2.init (c_.u.format2); return;
      default:                               return;
B
Behdad Esfahbod 已提交
949 950
      }
    }
B
Behdad Esfahbod 已提交
951
    inline bool more (void) {
B
Behdad Esfahbod 已提交
952 953 954
      switch (format) {
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
955
      default:return false;
B
Behdad Esfahbod 已提交
956 957
      }
    }
B
Behdad Esfahbod 已提交
958
    inline void next (void) {
B
Behdad Esfahbod 已提交
959 960 961 962 963 964
      switch (format) {
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
      default:                   break;
      }
    }
965
    inline hb_codepoint_t get_glyph (void) {
B
Behdad Esfahbod 已提交
966 967 968
      switch (format) {
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
969
      default:return 0;
B
Behdad Esfahbod 已提交
970 971
      }
    }
972
    inline unsigned int get_coverage (void) {
B
Behdad Esfahbod 已提交
973
      switch (format) {
B
Behdad Esfahbod 已提交
974 975
      case 1: return u.format1.get_coverage ();
      case 2: return u.format2.get_coverage ();
B
Minor  
Behdad Esfahbod 已提交
976
      default:return -1;
B
Behdad Esfahbod 已提交
977 978 979 980
      }
    }

    private:
B
Behdad Esfahbod 已提交
981
    unsigned int format;
B
Behdad Esfahbod 已提交
982
    union {
983
    CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
B
Behdad Esfahbod 已提交
984 985 986 987
    CoverageFormat1::Iter	format1;
    } u;
  };

988
  protected:
989
  union {
B
Behdad Esfahbod 已提交
990
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
991 992
  CoverageFormat1	format1;
  CoverageFormat2	format2;
993
  } u;
B
Behdad Esfahbod 已提交
994
  public:
B
Behdad Esfahbod 已提交
995
  DEFINE_SIZE_UNION (2, format);
996 997 998 999 1000 1001 1002
};


/*
 * Class Definition Table
 */

B
Behdad Esfahbod 已提交
1003 1004
struct ClassDefFormat1
{
1005 1006 1007
  friend struct ClassDef;

  private:
1008
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1009
  {
B
Minor  
Behdad Esfahbod 已提交
1010 1011 1012
    unsigned int i = (unsigned int) (glyph_id - startGlyph);
    if (unlikely (i < classValue.len))
      return classValue[i];
1013 1014 1015
    return 0;
  }

B
Behdad Esfahbod 已提交
1016 1017
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1018
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1019
    return_trace (c->check_struct (this) && classValue.sanitize (c));
B
Behdad Esfahbod 已提交
1020 1021
  }

1022
  template <typename set_t>
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
  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)))
1033
	  return false;
1034 1035 1036 1037 1038

      start = i + 1;
    }
    if (start != count)
      if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1039
	return false;
1040 1041 1042 1043 1044 1045

    return true;
  }

  template <typename set_t>
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1046 1047
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1048
    {
1049
      if (classValue[i] == klass)
1050
        glyphs->add (startGlyph + i);
B
Behdad Esfahbod 已提交
1051 1052
    }
    return true;
1053 1054
  }

1055
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1056
    unsigned int count = classValue.len;
1057 1058 1059
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1060
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1061 1062 1063 1064 1065 1066 1067 1068 1069
      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. */
    }
1070 1071 1072 1073 1074 1075
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass && glyphs->has (startGlyph + i))
        return true;
    return false;
  }

1076
  protected:
B
Behdad Esfahbod 已提交
1077
  HBUINT16	classFormat;		/* Format identifier--format = 1 */
1078
  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
B
Behdad Esfahbod 已提交
1079
  ArrayOf<HBUINT16>
1080
		classValue;		/* Array of Class Values--one per GlyphID */
1081
  public:
1082
  DEFINE_SIZE_ARRAY (6, classValue);
1083 1084
};

B
Behdad Esfahbod 已提交
1085 1086
struct ClassDefFormat2
{
1087 1088 1089
  friend struct ClassDef;

  private:
1090
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1091
  {
1092
    int i = rangeRecord.bsearch (glyph_id);
B
Minor  
Behdad Esfahbod 已提交
1093
    if (unlikely (i != -1))
B
Behdad Esfahbod 已提交
1094
      return rangeRecord[i].value;
1095 1096 1097
    return 0;
  }

B
Behdad Esfahbod 已提交
1098 1099
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1100
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1101
    return_trace (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
1102 1103
  }

1104
  template <typename set_t>
1105 1106 1107 1108 1109
  inline bool add_coverage (set_t *glyphs) const {
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value)
	if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1110
	  return false;
1111 1112 1113 1114 1115
    return true;
  }

  template <typename set_t>
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1116 1117
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1118
    {
1119
      if (rangeRecord[i].value == klass)
B
Behdad Esfahbod 已提交
1120
        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1121
	  return false;
B
Behdad Esfahbod 已提交
1122 1123
    }
    return true;
1124 1125
  }

1126
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1127
    unsigned int count = rangeRecord.len;
1128 1129 1130
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
1131
      hb_codepoint_t g = HB_SET_VALUE_INVALID;
1132 1133 1134 1135 1136 1137 1138 1139
      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;
      }
1140
      if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1141 1142 1143
        return true;
      /* Fall through. */
    }
1144 1145 1146 1147 1148 1149
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }

1150
  protected:
B
Behdad Esfahbod 已提交
1151
  HBUINT16	classFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1152
  SortedArrayOf<RangeRecord>
1153 1154
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID */
1155
  public:
1156
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1157 1158
};

B
Behdad Esfahbod 已提交
1159 1160
struct ClassDef
{
1161
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1162
  {
1163
    switch (u.format) {
B
Minor  
Behdad Esfahbod 已提交
1164 1165
    case 1: return u.format1.get_class (glyph_id);
    case 2: return u.format2.get_class (glyph_id);
1166 1167 1168 1169
    default:return 0;
    }
  }

B
Behdad Esfahbod 已提交
1170 1171
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1172
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1173
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
1174
    switch (u.format) {
B
Behdad Esfahbod 已提交
1175 1176 1177
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
1178 1179
    }
  }
1180

1181 1182 1183 1184 1185 1186 1187
  /* 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);
1188
    default:return false;
1189 1190 1191 1192 1193
    }
  }

  /* Might return false if array looks unsorted.
   * Used for faster rejection of corrupt data. */
B
Behdad Esfahbod 已提交
1194
  template <typename set_t>
1195
  inline bool add_class (set_t *glyphs, unsigned int klass) const {
1196
    switch (u.format) {
1197 1198
    case 1: return u.format1.add_class (glyphs, klass);
    case 2: return u.format2.add_class (glyphs, klass);
B
Behdad Esfahbod 已提交
1199
    default:return false;
1200 1201 1202
    }
  }

1203
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1204 1205 1206 1207 1208 1209 1210
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1211
  protected:
1212
  union {
B
Behdad Esfahbod 已提交
1213
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1214 1215
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1216
  } u;
B
Behdad Esfahbod 已提交
1217
  public:
B
Behdad Esfahbod 已提交
1218
  DEFINE_SIZE_UNION (2, format);
1219 1220 1221
};


1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
/*
 * 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.;

    const VarRegionAxis *axes = axesZ + (region_index * axisCount);

    float v = 1.;
1278
    unsigned int count = axisCount;
1279 1280
    for (unsigned int i = 0; i < count; i++)
    {
1281 1282
      int coord = i < coord_len ? coords[i] : 0;
      float factor = axes[i].evaluate (coord);
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
      if (factor == 0.)
        return 0.;
      v *= factor;
    }
    return v;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  c->check_array (axesZ, axesZ[0].static_size,
				  (unsigned int) axisCount * (unsigned int) regionCount));
  }

  protected:
B
Behdad Esfahbod 已提交
1299 1300
  HBUINT16	axisCount;
  HBUINT16	regionCount;
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323
  VarRegionAxis	axesZ[VAR];
  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 已提交
1324 1325
   const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
   const HBUINT8 *row = bytes + inner * (scount + count);
1326 1327 1328 1329

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

B
Behdad Esfahbod 已提交
1330
   const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1331 1332 1333 1334 1335
   for (; i < scount; i++)
   {
     float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
     delta += scalar * *scursor++;
   }
B
Behdad Esfahbod 已提交
1336
   const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
   for (; i < count; i++)
   {
     float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
     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 已提交
1352
		  c->check_array (&StructAfter<HBUINT8> (regionIndices),
1353 1354 1355 1356
				  get_row_size (), itemCount));
  }

  protected:
B
Behdad Esfahbod 已提交
1357 1358 1359 1360
  HBUINT16		itemCount;
  HBUINT16		shortCount;
  ArrayOf<HBUINT16>	regionIndices;
  HBUINT8			bytesX[VAR];
1361 1362 1363 1364
  public:
  DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
};

1365
struct VariationStore
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
{
  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);
  }

1378 1379 1380 1381 1382 1383 1384 1385
  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);
  }

1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
  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 已提交
1396
  HBUINT16				format;
B
Behdad Esfahbod 已提交
1397
  LOffsetTo<VarRegionList>		regions;
B
Behdad Esfahbod 已提交
1398
  OffsetArrayOf<VarData, HBUINT32>	dataSets;
1399 1400 1401 1402
  public:
  DEFINE_SIZE_ARRAY (8, dataSets);
};

1403 1404 1405 1406 1407 1408 1409 1410 1411
/*
 * Feature Variations
 */

struct ConditionFormat1
{
  friend struct Condition;

  private:
1412
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
  {
    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 已提交
1425 1426
  HBUINT16	format;		/* Format identifier--format = 1 */
  HBUINT16	axisIndex;
1427 1428 1429 1430 1431 1432 1433 1434
  F2DOT14	filterRangeMinValue;
  F2DOT14	filterRangeMaxValue;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct Condition
{
1435
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
  {
    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 已提交
1455
  HBUINT16		format;		/* Format identifier */
1456 1457 1458 1459 1460 1461 1462 1463
  ConditionFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct ConditionSet
{
1464
  inline bool evaluate (const int *coords, unsigned int coord_len) const
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
  {
    unsigned int count = conditions.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+conditions.array[i]).evaluate (coords, coord_len))
        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 已提交
1480
  OffsetArrayOf<Condition, HBUINT32> conditions;
1481 1482 1483 1484 1485 1486
  public:
  DEFINE_SIZE_ARRAY (2, conditions);
};

struct FeatureTableSubstitutionRecord
{
1487
  friend struct FeatureTableSubstitution;
1488

1489
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1490 1491
  {
    TRACE_SANITIZE (this);
1492
    return_trace (c->check_struct (this) && feature.sanitize (c, base));
1493 1494 1495
  }

  protected:
B
Behdad Esfahbod 已提交
1496
  HBUINT16		featureIndex;
B
Behdad Esfahbod 已提交
1497
  LOffsetTo<Feature>	feature;
1498 1499 1500 1501 1502 1503
  public:
  DEFINE_SIZE_STATIC (6);
};

struct FeatureTableSubstitution
{
1504 1505 1506 1507 1508
  inline const Feature *find_substitute (unsigned int feature_index) const
  {
    unsigned int count = substitutions.len;
    for (unsigned int i = 0; i < count; i++)
    {
1509 1510 1511
      const FeatureTableSubstitutionRecord &record = substitutions.array[i];
      if (record.featureIndex == feature_index)
	return &(this+record.feature);
1512
    }
B
Behdad Esfahbod 已提交
1513
    return nullptr;
1514 1515
  }

1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
  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 */
1526
  ArrayOf<FeatureTableSubstitutionRecord>
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
			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 已提交
1544
  LOffsetTo<ConditionSet>
1545
			conditions;
B
Behdad Esfahbod 已提交
1546
  LOffsetTo<FeatureTableSubstitution>
1547 1548 1549 1550 1551 1552 1553
			substitutions;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct FeatureVariations
{
1554 1555
  static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;

1556 1557
  inline bool find_index (const int *coords, unsigned int coord_len,
			  unsigned int *index) const
1558 1559 1560 1561 1562 1563
  {
    unsigned int count = varRecords.len;
    for (unsigned int i = 0; i < count; i++)
    {
      const FeatureVariationRecord &record = varRecords.array[i];
      if ((this+record.conditions).evaluate (coords, coord_len))
1564 1565 1566 1567
      {
	*index = i;
	return true;
      }
1568
    }
1569
    *index = NOT_FOUND_INDEX;
1570
    return false;
1571 1572
  }

1573 1574 1575 1576 1577 1578 1579
  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);
  }

1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
  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 已提交
1590
  LArrayOf<FeatureVariationRecord>
1591 1592 1593 1594 1595
			varRecords;
  public:
  DEFINE_SIZE_ARRAY (8, varRecords);
};

1596

1597 1598 1599 1600
/*
 * Device Tables
 */

1601
struct HintingDevice
B
Behdad Esfahbod 已提交
1602
{
1603 1604 1605
  friend struct Device;

  private:
B
Behdad Esfahbod 已提交
1606

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

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

B
Minor  
Behdad Esfahbod 已提交
1613 1614 1615
  inline unsigned int get_size (void) const
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
1616 1617
    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 已提交
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
  }

  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:

1628
  inline int get_delta (unsigned int ppem, int scale) const
1629 1630 1631 1632 1633 1634 1635
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

B
Behdad Esfahbod 已提交
1636
    return (int) (pixels * (int64_t) scale / ppem);
1637 1638
  }
  inline int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
1639
  {
1640
    unsigned int f = deltaFormat;
1641
    if (unlikely (f < 1 || f > 3))
1642
      return 0;
1643

1644 1645
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
1646

1647
    unsigned int s = ppem_size - startSize;
1648

1649
    unsigned int byte = deltaValue[s >> (4 - f)];
B
Behdad Esfahbod 已提交
1650
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1651
    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1652 1653 1654

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
1655
    if ((unsigned int) delta >= ((mask + 1) >> 1))
1656 1657 1658 1659 1660
      delta -= mask + 1;

    return delta;
  }

1661
  protected:
B
Behdad Esfahbod 已提交
1662 1663 1664
  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
1665 1666 1667 1668
					 * 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
					 */
B
Behdad Esfahbod 已提交
1669
  HBUINT16	deltaValue[VAR];	/* Array of compressed data */
B
Behdad Esfahbod 已提交
1670
  public:
1671
  DEFINE_SIZE_ARRAY (6, deltaValue);
1672 1673
};

1674 1675
struct VariationDevice
{
1676 1677 1678
  friend struct Device;

  private:
1679

1680
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1681
  { return font->em_scalef_x (get_delta (font, store)); }
1682

1683
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1684
  { return font->em_scalef_y (get_delta (font, store)); }
1685 1686 1687 1688

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
1689
    return_trace (c->check_struct (this));
1690 1691 1692 1693
  }

  private:

1694
  inline float get_delta (hb_font_t *font, const VariationStore &store) const
1695
  {
1696
    return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1697 1698 1699
  }

  protected:
B
Behdad Esfahbod 已提交
1700 1701 1702
  HBUINT16	outerIndex;
  HBUINT16	innerIndex;
  HBUINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
1703
  public:
1704
  DEFINE_SIZE_STATIC (6);
1705 1706
};

1707 1708 1709
struct DeviceHeader
{
  protected:
B
Behdad Esfahbod 已提交
1710 1711
  HBUINT16		reserved1;
  HBUINT16		reserved2;
1712
  public:
B
Behdad Esfahbod 已提交
1713
  HBUINT16		format;		/* Format identifier */
1714 1715 1716 1717
  public:
  DEFINE_SIZE_STATIC (6);
};

1718 1719
struct Device
{
1720
  inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1721 1722 1723 1724 1725
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
      return u.hinting.get_x_delta (font);
1726
    case 0x8000:
1727
      return u.variation.get_x_delta (font, store);
1728 1729 1730 1731
    default:
      return 0;
    }
  }
1732
  inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1733 1734 1735 1736
  {
    switch (u.b.format)
    {
    case 1: case 2: case 3:
B
Behdad Esfahbod 已提交
1737
      return u.hinting.get_y_delta (font);
1738
    case 0x8000:
1739
      return u.variation.get_y_delta (font, store);
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
    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));
1752
    case 0x8000:
1753 1754 1755 1756 1757 1758 1759 1760
      return_trace (u.variation.sanitize (c));
    default:
      return_trace (true);
    }
  }

  protected:
  union {
1761
  DeviceHeader		b;
1762 1763 1764 1765 1766 1767 1768
  HintingDevice		hinting;
  VariationDevice	variation;
  } u;
  public:
  DEFINE_SIZE_UNION (6, b);
};

1769

B
Behdad Esfahbod 已提交
1770
} /* namespace OT */
1771

B
Behdad Esfahbod 已提交
1772

1773
#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */