hb-ot-layout-common-private.hh 34.9 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
#include "hb-ot-layout-private.hh"
33
#include "hb-open-type-private.hh"
B
Behdad Esfahbod 已提交
34
#include "hb-set-private.hh"
35 36


37 38 39
namespace OT {


B
Minor  
Behdad Esfahbod 已提交
40
#define NOT_COVERED		((unsigned int) -1)
B
Behdad Esfahbod 已提交
41 42
#define MAX_NESTING_LEVEL	8

B
Behdad Esfahbod 已提交
43

B
Behdad Esfahbod 已提交
44

45 46 47 48 49 50
/*
 *
 * OpenType Layout Common Table Formats
 *
 */

51

52 53 54 55 56
/*
 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
 */

template <typename Type>
B
Behdad Esfahbod 已提交
57 58
struct Record
{
59
  inline int cmp (hb_tag_t a) const {
60
    return tag.cmp (a);
B
Behdad Esfahbod 已提交
61 62
  }

63 64 65 66
  struct sanitize_closure_t {
    hb_tag_t tag;
    void *list_base;
  };
B
Behdad Esfahbod 已提交
67
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
B
Behdad Esfahbod 已提交
68
    TRACE_SANITIZE (this);
69 70
    const sanitize_closure_t closure = {tag, base};
    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
B
Behdad Esfahbod 已提交
71 72
  }

73 74 75 76
  Tag		tag;		/* 4-byte Tag identifier */
  OffsetTo<Type>
		offset;		/* Offset from beginning of object holding
				 * the Record */
B
Behdad Esfahbod 已提交
77 78
  public:
  DEFINE_SIZE_STATIC (6);
79 80 81
};

template <typename Type>
B
Behdad Esfahbod 已提交
82
struct RecordArrayOf : SortedArrayOf<Record<Type> > {
B
Behdad Esfahbod 已提交
83 84
  inline const Tag& get_tag (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
85 86 87
    /* We cheat slightly and don't define separate Null objects
     * for Record types.  Instead, we return the correct Null(Tag)
     * here. */
88
    if (unlikely (i >= this->len)) return Null(Tag);
B
Behdad Esfahbod 已提交
89
    return (*this)[i].tag;
90
  }
B
Behdad Esfahbod 已提交
91 92 93
  inline unsigned int get_tags (unsigned int start_offset,
				unsigned int *record_count /* IN/OUT */,
				hb_tag_t     *record_tags /* OUT */) const
94
  {
B
Behdad Esfahbod 已提交
95
    if (record_count) {
B
Behdad Esfahbod 已提交
96
      const Record<Type> *arr = this->sub_array (start_offset, record_count);
B
Behdad Esfahbod 已提交
97
      unsigned int count = *record_count;
B
Behdad Esfahbod 已提交
98
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
99
	record_tags[i] = arr[i].tag;
B
Behdad Esfahbod 已提交
100 101
    }
    return this->len;
102 103 104
  }
  inline bool find_index (hb_tag_t tag, unsigned int *index) const
  {
B
Behdad Esfahbod 已提交
105 106
    int i = this->search (tag);
    if (i != -1) {
107 108
        if (index) *index = i;
        return true;
B
Behdad Esfahbod 已提交
109 110 111
    } else {
      if (index) *index = Index::NOT_FOUND_INDEX;
      return false;
112 113 114 115 116 117 118 119
    }
  }
};

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

B
Behdad Esfahbod 已提交
122
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
123
    TRACE_SANITIZE (this);
124
    return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
B
Behdad Esfahbod 已提交
125
  }
126 127 128
};


B
Behdad Esfahbod 已提交
129 130 131
struct RangeRecord
{
  inline int cmp (hb_codepoint_t g) const {
B
Minor  
Behdad Esfahbod 已提交
132
    return g < start ? -1 : g <= end ? 0 : +1 ;
B
Behdad Esfahbod 已提交
133 134 135
  }

  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
136
    TRACE_SANITIZE (this);
137
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
138 139
  }

140
  inline bool intersects (const hb_set_t *glyphs) const {
141 142 143
    return glyphs->intersects (start, end);
  }

144 145
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const {
146 147 148
    glyphs->add_range (start, end);
  }

B
Behdad Esfahbod 已提交
149 150 151 152 153 154 155 156 157
  GlyphID	start;		/* First GlyphID in the range */
  GlyphID	end;		/* Last GlyphID in the range */
  USHORT	value;		/* Value */
  public:
  DEFINE_SIZE_STATIC (6);
};
DEFINE_NULL_DATA (RangeRecord, "\000\001");


B
Behdad Esfahbod 已提交
158
struct IndexArray : ArrayOf<Index>
159
{
B
Behdad Esfahbod 已提交
160 161 162
  inline unsigned int get_indexes (unsigned int start_offset,
				   unsigned int *_count /* IN/OUT */,
				   unsigned int *_indexes /* OUT */) const
163
  {
B
Behdad Esfahbod 已提交
164
    if (_count) {
B
Behdad Esfahbod 已提交
165
      const USHORT *arr = this->sub_array (start_offset, _count);
B
Behdad Esfahbod 已提交
166
      unsigned int count = *_count;
B
Behdad Esfahbod 已提交
167
      for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
168
	_indexes[i] = arr[i];
B
Behdad Esfahbod 已提交
169 170
    }
    return this->len;
171 172 173 174
  }
};


175 176 177 178 179
struct Script;
struct LangSys;
struct Feature;


B
Behdad Esfahbod 已提交
180 181
struct LangSys
{
182 183 184 185
  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 已提交
186 187 188 189
  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); }
190

B
Behdad Esfahbod 已提交
191
  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
B
Behdad Esfahbod 已提交
192
  inline unsigned int get_required_feature_index (void) const
B
Behdad Esfahbod 已提交
193
  {
194
    if (reqFeatureIndex == 0xffff)
B
Behdad Esfahbod 已提交
195
      return Index::NOT_FOUND_INDEX;
196 197 198
   return reqFeatureIndex;;
  }

199 200
  inline bool sanitize (hb_sanitize_context_t *c,
			const Record<LangSys>::sanitize_closure_t * = NULL) {
B
Behdad Esfahbod 已提交
201
    TRACE_SANITIZE (this);
202
    return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
B
Behdad Esfahbod 已提交
203 204
  }

205 206 207 208 209
  Offset	lookupOrder;	/* = Null (reserved for an offset to a
				 * reordering table) */
  USHORT	reqFeatureIndex;/* Index of a feature required for this
				 * language system--if no required features
				 * = 0xFFFF */
210
  IndexArray	featureIndex;	/* Array of indices into the FeatureList */
B
Behdad Esfahbod 已提交
211
  public:
212
  DEFINE_SIZE_ARRAY (6, featureIndex);
213
};
B
Behdad Esfahbod 已提交
214
DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
215 216


B
Behdad Esfahbod 已提交
217 218
struct Script
{
219 220 221 222
  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 已提交
223 224 225 226
  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 已提交
227 228
  inline const LangSys& get_lang_sys (unsigned int i) const
  {
B
Behdad Esfahbod 已提交
229
    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
230 231
    return this+langSys[i].offset;
  }
232 233
  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
  { return langSys.find_index (tag, index); }
234

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

238 239
  inline bool sanitize (hb_sanitize_context_t *c,
			const Record<Script>::sanitize_closure_t * = NULL) {
B
Behdad Esfahbod 已提交
240
    TRACE_SANITIZE (this);
241
    return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
B
Behdad Esfahbod 已提交
242 243
  }

244
  protected:
245 246 247
  OffsetTo<LangSys>
		defaultLangSys;	/* Offset to DefaultLangSys table--from
				 * beginning of Script table--may be Null */
B
Behdad Esfahbod 已提交
248
  RecordArrayOf<LangSys>
249 250
		langSys;	/* Array of LangSysRecords--listed
				 * alphabetically by LangSysTag */
251
  public:
252
  DEFINE_SIZE_ARRAY (4, langSys);
253 254 255 256
};

typedef RecordListOf<Script> ScriptList;

257 258

/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
259 260 261 262
struct FeatureParamsSize
{
  inline bool sanitize (hb_sanitize_context_t *c) {
    TRACE_SANITIZE (this);
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 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
    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);

    /* 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:
     * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
     *
     * 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,
     * and make the following value checks. If it fails, assume the the size
     * 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)
      return TRACE_RETURN (false);
    else if (subfamilyID == 0 &&
	     subfamilyNameID == 0 &&
	     rangeStart == 0 &&
	     rangeEnd == 0)
      return TRACE_RETURN (true);
    else if (designSize < rangeStart ||
	     designSize > rangeEnd ||
	     subfamilyNameID < 256 ||
	     subfamilyNameID > 32767)
      return TRACE_RETURN (false);
    else
      return TRACE_RETURN (true);
328 329
  }

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
  USHORT	designSize;	/* Represents the design size in 720/inch
				 * 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. */
  USHORT	subfamilyID;	/* Has no independent meaning, but serves
				 * 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. */
  USHORT	subfamilyNameID;/* If the preceding value is non-zero, this
				 * 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. */
  USHORT	rangeStart;	/* Large end of the recommended usage range
				 * (inclusive), stored in 720/inch units
				 * (decipoints). */
  USHORT	rangeEnd;	/* Small end of the recommended usage range
				   (exclusive), stored in 720/inch units
				 * (decipoints). */
365 366 367 368
  public:
  DEFINE_SIZE_STATIC (10);
};

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
struct FeatureParamsStylisticSet
{
  inline bool sanitize (hb_sanitize_context_t *c) {
    TRACE_SANITIZE (this);
    /* Right now minorVersion is at zero.  Which means, any table supports
     * the uiNameID field. */
    return TRACE_RETURN (c->check_struct (this));
  }

  USHORT	minorVersion;	/* (set to 0): This corresponds to a “minor”
				 * version number. Additional data may be
				 * added to the end of this Feature Parameters
				 * table in the future. */

  USHORT	uiNameID;	/* The 'name' table name ID that specifies a
				 * 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);
};

402 403 404 405 406 407 408
struct FeatureParamsCharacterVariants
{
  inline bool sanitize (hb_sanitize_context_t *c) {
    TRACE_SANITIZE (this);
    return TRACE_RETURN (c->check_struct (this) &&
			 characters.sanitize (c));
  }
409

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
  USHORT	format;			/* Format number is set to 0. */
  USHORT	featUILableNameID;	/* The ‘name’ table name ID that
					 * specifies a string (or strings,
					 * for multiple languages) for a
					 * user-interface label for this
					 * feature. (May be NULL.) */
  USHORT	featUITooltipTextNameID;/* The ‘name’ table name ID that
					 * specifies a string (or strings,
					 * for multiple languages) that an
					 * application can use for tooltip
					 * text for this feature. (May be
					 * NULL.) */
  USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
					 * specifies sample text that
					 * illustrates the effect of this
					 * feature. (May be NULL.) */
  USHORT	numNamedParameters;	/* Number of named parameters. (May
					 * be zero.) */
  USHORT	firstParamUILabelNameID;/* The first ‘name’ table name ID
					 * 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);
};

442 443
struct FeatureParams
{
444
  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
445
    TRACE_SANITIZE (this);
446 447 448 449 450 451 452
    if (tag == HB_TAG ('s','i','z','e'))
      return TRACE_RETURN (u.size.sanitize (c));
    if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */
      return TRACE_RETURN (u.stylisticSet.sanitize (c));
    if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */
      return TRACE_RETURN (u.characterVariants.sanitize (c));
    return TRACE_RETURN (true);
453 454
  }

455 456 457 458 459 460 461 462
  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:
463
  union {
464 465 466
  FeatureParamsSize			size;
  FeatureParamsStylisticSet		stylisticSet;
  FeatureParamsCharacterVariants	characterVariants;
467
  } u;
468
  DEFINE_SIZE_STATIC (17);
469
};
470

B
Behdad Esfahbod 已提交
471 472
struct Feature
{
473 474 475 476
  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 已提交
477 478 479 480
  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); }
481

482 483 484
  inline const FeatureParams &get_feature_params (void) const
  { return this+featureParams; }

485 486
  inline bool sanitize (hb_sanitize_context_t *c,
			const Record<Feature>::sanitize_closure_t *closure) {
B
Behdad Esfahbod 已提交
487
    TRACE_SANITIZE (this);
488 489 490
    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
      return TRACE_RETURN (false);

491 492 493 494 495 496
    /* 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.
497 498 499
     *
     * Only do this for the 'size' feature, since at the time of the faulty
     * Adobe tools, only the 'size' feature had FeatureParams defined.
500 501
     */

502
    Offset orig_offset = featureParams;
503 504 505 506
    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
      return TRACE_RETURN (false);

    if (likely (!orig_offset))
507 508
      return TRACE_RETURN (true);

509 510 511
    if (featureParams == 0 && closure &&
	closure->tag == HB_TAG ('s','i','z','e') &&
	closure->list_base && closure->list_base < this)
512
    {
513 514 515
      unsigned int new_offset_int = (unsigned int) orig_offset -
				    ((char *) this - (char *) closure->list_base);

516 517
      Offset new_offset;
      /* Check that it did not overflow. */
518 519 520 521
      new_offset.set (new_offset_int);
      if (new_offset == new_offset_int &&
	  featureParams.try_set (c, new_offset) &&
	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
522 523 524
	return TRACE_RETURN (false);
    }

525
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
526 527
  }

528 529
  OffsetTo<FeatureParams>
		 featureParams;	/* Offset to Feature Parameters table (if one
530 531 532
				 * has been defined for the feature), relative
				 * to the beginning of the Feature Table; = Null
				 * if not required */
533
  IndexArray	 lookupIndex;	/* Array of LookupList indices */
534
  public:
535
  DEFINE_SIZE_ARRAY (4, lookupIndex);
536 537 538 539 540
};

typedef RecordListOf<Feature> FeatureList;


B
Behdad Esfahbod 已提交
541 542
struct LookupFlag : USHORT
{
B
Behdad Esfahbod 已提交
543
  enum Flags {
B
Behdad Esfahbod 已提交
544 545 546 547
    RightToLeft		= 0x0001u,
    IgnoreBaseGlyphs	= 0x0002u,
    IgnoreLigatures	= 0x0004u,
    IgnoreMarks		= 0x0008u,
B
Behdad Esfahbod 已提交
548
    IgnoreFlags		= 0x000Eu,
549 550
    UseMarkFilteringSet	= 0x0010u,
    Reserved		= 0x00E0u,
551
    MarkAttachmentType	= 0xFF00u
B
Behdad Esfahbod 已提交
552
  };
553 554
  public:
  DEFINE_SIZE_STATIC (2);
555 556
};

B
Behdad Esfahbod 已提交
557 558 559
struct Lookup
{
  inline unsigned int get_subtable_count (void) const { return subTable.len; }
560 561

  inline unsigned int get_type (void) const { return lookupType; }
562 563 564 565 566

  /* 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
567 568
  {
    unsigned int flag = lookupFlag;
569
    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
570
    {
571
      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
B
Behdad Esfahbod 已提交
572
      flag += (markFilteringSet << 16);
573 574 575
    }
    return flag;
  }
576

577 578 579 580 581
  inline bool serialize (hb_serialize_context_t *c,
			 unsigned int lookup_type,
			 uint32_t lookup_props,
			 unsigned int num_subtables)
  {
B
Behdad Esfahbod 已提交
582
    TRACE_SERIALIZE (this);
583 584 585 586
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    lookupType.set (lookup_type);
    lookupFlag.set (lookup_props & 0xFFFF);
    if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
587
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
588 589 590 591 592 593 594
    {
      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
      markFilteringSet.set (lookup_props >> 16);
    }
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
595
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
596
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
597
    /* Real sanitize of the subtables is done by GSUB/GPOS/... */
598
    if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
599
    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
B
Behdad Esfahbod 已提交
600
    {
601
      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
602
      if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
603
    }
604
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
605 606
  }

607 608
  USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
  USHORT	lookupFlag;		/* Lookup qualifiers */
B
Behdad Esfahbod 已提交
609
  ArrayOf<Offset>
610
		subTable;		/* Array of SubTables */
B
Behdad Esfahbod 已提交
611
  USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
612 613
					 * structure. This field is only present if bit
					 * UseMarkFilteringSet of lookup flags is set. */
B
Behdad Esfahbod 已提交
614
  public:
615
  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
616 617 618 619 620 621 622 623 624
};

typedef OffsetListOf<Lookup> LookupList;


/*
 * Coverage Table
 */

B
Behdad Esfahbod 已提交
625 626
struct CoverageFormat1
{
627 628 629
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
630 631
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
B
Behdad Esfahbod 已提交
632
    int i = glyphArray.search (glyph_id);
B
Minor  
Behdad Esfahbod 已提交
633 634
    ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
    return i;
635 636
  }

637
  inline bool serialize (hb_serialize_context_t *c,
638
			 Supplier<GlyphID> &glyphs,
639
			 unsigned int num_glyphs)
640
  {
B
Behdad Esfahbod 已提交
641
    TRACE_SERIALIZE (this);
642 643 644
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    glyphArray.len.set (num_glyphs);
    if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
645
    for (unsigned int i = 0; i < num_glyphs; i++)
646
      glyphArray[i] = glyphs[i];
647
    glyphs.advance (num_glyphs);
648 649 650
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
651
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
652
    TRACE_SANITIZE (this);
653
    return TRACE_RETURN (glyphArray.sanitize (c));
B
Behdad Esfahbod 已提交
654 655
  }

656
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
657 658 659
    return glyphs->has (glyphArray[index]);
  }

660 661
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const {
662 663 664 665 666
    unsigned int count = glyphArray.len;
    for (unsigned int i = 0; i < count; i++)
      glyphs->add (glyphArray[i]);
  }

B
Behdad Esfahbod 已提交
667 668
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
669
  struct Iter {
B
Behdad Esfahbod 已提交
670 671 672 673 674
    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++; }
    inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
    inline uint16_t get_coverage (void) { return i; }
B
Behdad Esfahbod 已提交
675 676 677 678 679

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

682
  protected:
683
  USHORT	coverageFormat;	/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
684
  SortedArrayOf<GlyphID>
685
		glyphArray;	/* Array of GlyphIDs--in numerical order */
686
  public:
687
  DEFINE_SIZE_ARRAY (4, glyphArray);
688 689
};

B
Behdad Esfahbod 已提交
690 691
struct CoverageFormat2
{
692 693 694
  friend struct Coverage;

  private:
B
Behdad Esfahbod 已提交
695 696
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
  {
B
Behdad Esfahbod 已提交
697 698 699 700
    int i = rangeRecord.search (glyph_id);
    if (i != -1) {
      const RangeRecord &range = rangeRecord[i];
      return (unsigned int) range.value + (glyph_id - range.start);
701 702 703 704
    }
    return NOT_COVERED;
  }

705
  inline bool serialize (hb_serialize_context_t *c,
706
			 Supplier<GlyphID> &glyphs,
707
			 unsigned int num_glyphs)
708
  {
B
Behdad Esfahbod 已提交
709
    TRACE_SERIALIZE (this);
710 711 712 713
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);

    if (unlikely (!num_glyphs)) return TRACE_RETURN (true);

714 715 716 717
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
718 719 720
    rangeRecord.len.set (num_ranges);
    if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);

721
    unsigned int range = 0;
722
    rangeRecord[range].start = glyphs[0];
723
    rangeRecord[range].value.set (0);
724 725 726
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i]) {
	range++;
727 728 729
	rangeRecord[range].start = glyphs[i];
	rangeRecord[range].value.set (i);
        rangeRecord[range].end = glyphs[i];
730
      } else {
731
        rangeRecord[range].end = glyphs[i];
732
      }
733
    glyphs.advance (num_glyphs);
734 735 736
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
737
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
738
    TRACE_SANITIZE (this);
739
    return TRACE_RETURN (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
740 741
  }

742
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
743 744 745 746 747
    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 已提交
748
	  index < (unsigned int) range.value + (range.end - range.start) &&
749 750 751 752 753 754 755 756
	  range.intersects (glyphs))
        return true;
      else if (index < range.value)
        return false;
    }
    return false;
  }

757 758
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const {
759 760 761 762 763
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      rangeRecord[i].add_coverage (glyphs);
  }

B
Behdad Esfahbod 已提交
764 765
  public:
  /* Older compilers need this to be public. */
B
Behdad Esfahbod 已提交
766
  struct Iter {
B
Behdad Esfahbod 已提交
767 768 769 770 771 772 773 774 775
    inline void init (const CoverageFormat2 &c_) {
      c = &c_;
      coverage = 0;
      i = 0;
      j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
    }
    inline bool more (void) { return i < c->rangeRecord.len; }
    inline void next (void) {
      coverage++;
B
Behdad Esfahbod 已提交
776 777
      if (j == c->rangeRecord[i].end) {
        i++;
B
Behdad Esfahbod 已提交
778 779 780
	if (more ())
	  j = c->rangeRecord[i].start;
	return;
B
Behdad Esfahbod 已提交
781
      }
B
Behdad Esfahbod 已提交
782 783
      j++;
    }
B
Behdad Esfahbod 已提交
784 785
    inline uint16_t get_glyph (void) { return j; }
    inline uint16_t get_coverage (void) { return coverage; }
B
Behdad Esfahbod 已提交
786 787 788

    private:
    const struct CoverageFormat2 *c;
B
Behdad Esfahbod 已提交
789
    unsigned int i, j, coverage;
B
Behdad Esfahbod 已提交
790
  };
B
Behdad Esfahbod 已提交
791
  private:
B
Behdad Esfahbod 已提交
792

793
  protected:
794
  USHORT	coverageFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
795
  SortedArrayOf<RangeRecord>
796 797 798
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID. rangeCount entries
				 * long */
799
  public:
800
  DEFINE_SIZE_ARRAY (4, rangeRecord);
801 802
};

B
Behdad Esfahbod 已提交
803 804
struct Coverage
{
B
Behdad Esfahbod 已提交
805
  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
806
  {
807
    switch (u.format) {
B
Behdad Esfahbod 已提交
808 809
    case 1: return u.format1.get_coverage(glyph_id);
    case 2: return u.format2.get_coverage(glyph_id);
810 811 812 813
    default:return NOT_COVERED;
    }
  }

814
  inline bool serialize (hb_serialize_context_t *c,
815
			 Supplier<GlyphID> &glyphs,
816
			 unsigned int num_glyphs)
817
  {
B
Behdad Esfahbod 已提交
818
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
819
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
820 821 822 823
    unsigned int num_ranges = 1;
    for (unsigned int i = 1; i < num_glyphs; i++)
      if (glyphs[i - 1] + 1 != glyphs[i])
        num_ranges++;
824 825 826 827
    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
828 829 830 831
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
832
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
833
    TRACE_SANITIZE (this);
834
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
835
    switch (u.format) {
836 837 838
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
839 840
    }
  }
841

842
  inline bool intersects (const hb_set_t *glyphs) const {
B
Behdad Esfahbod 已提交
843 844 845 846 847 848 849
    /* 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;
850
  }
B
Behdad Esfahbod 已提交
851

852
  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
853 854 855 856 857
    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 已提交
858 859
  }

860 861
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const {
862 863 864 865 866 867 868
    switch (u.format) {
    case 1: u.format1.add_coverage (glyphs); break;
    case 2: u.format2.add_coverage (glyphs); break;
    default:                                 break;
    }
  }

B
Behdad Esfahbod 已提交
869
  struct Iter {
B
Behdad Esfahbod 已提交
870 871
    Iter (void) : format (0) {};
    inline void init (const Coverage &c_) {
B
Behdad Esfahbod 已提交
872 873
      format = c_.u.format;
      switch (format) {
B
Minor  
Behdad Esfahbod 已提交
874 875 876
      case 1: u.format1.init (c_.u.format1); return;
      case 2: u.format2.init (c_.u.format2); return;
      default:                               return;
B
Behdad Esfahbod 已提交
877 878
      }
    }
B
Behdad Esfahbod 已提交
879
    inline bool more (void) {
B
Behdad Esfahbod 已提交
880 881 882
      switch (format) {
      case 1: return u.format1.more ();
      case 2: return u.format2.more ();
B
Minor  
Behdad Esfahbod 已提交
883
      default:return false;
B
Behdad Esfahbod 已提交
884 885
      }
    }
B
Behdad Esfahbod 已提交
886
    inline void next (void) {
B
Behdad Esfahbod 已提交
887 888 889 890 891 892
      switch (format) {
      case 1: u.format1.next (); break;
      case 2: u.format2.next (); break;
      default:                   break;
      }
    }
B
Behdad Esfahbod 已提交
893 894 895 896
    inline uint16_t get_glyph (void) {
      switch (format) {
      case 1: return u.format1.get_glyph ();
      case 2: return u.format2.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
897
      default:return 0;
B
Behdad Esfahbod 已提交
898 899 900
      }
    }
    inline uint16_t get_coverage (void) {
B
Behdad Esfahbod 已提交
901
      switch (format) {
B
Behdad Esfahbod 已提交
902 903
      case 1: return u.format1.get_coverage ();
      case 2: return u.format2.get_coverage ();
B
Minor  
Behdad Esfahbod 已提交
904
      default:return -1;
B
Behdad Esfahbod 已提交
905 906 907 908
      }
    }

    private:
B
Behdad Esfahbod 已提交
909
    unsigned int format;
B
Behdad Esfahbod 已提交
910 911 912 913 914 915
    union {
    CoverageFormat1::Iter	format1;
    CoverageFormat2::Iter	format2;
    } u;
  };

916
  protected:
917 918
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
919 920
  CoverageFormat1	format1;
  CoverageFormat2	format2;
921
  } u;
B
Behdad Esfahbod 已提交
922
  public:
B
Behdad Esfahbod 已提交
923
  DEFINE_SIZE_UNION (2, format);
924 925 926 927 928 929 930
};


/*
 * Class Definition Table
 */

B
Behdad Esfahbod 已提交
931 932
struct ClassDefFormat1
{
933 934 935
  friend struct ClassDef;

  private:
936
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
937
  {
B
Minor  
Behdad Esfahbod 已提交
938
    if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
939 940 941 942
      return classValue[glyph_id - startGlyph];
    return 0;
  }

B
Behdad Esfahbod 已提交
943
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
944
    TRACE_SANITIZE (this);
945
    return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
B
Behdad Esfahbod 已提交
946 947
  }

948 949 950 951 952 953 954 955
  template <typename set_t>
  inline void add_class (set_t *glyphs, unsigned int klass) const {
    unsigned int count = classValue.len;
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass)
        glyphs->add (startGlyph + i);
  }

956
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
957
    unsigned int count = classValue.len;
958 959 960 961 962 963 964 965 966 967 968 969 970
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
      hb_codepoint_t g = -1;
      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. */
    }
971 972 973 974 975 976
    for (unsigned int i = 0; i < count; i++)
      if (classValue[i] == klass && glyphs->has (startGlyph + i))
        return true;
    return false;
  }

977
  protected:
978 979 980 981
  USHORT	classFormat;		/* Format identifier--format = 1 */
  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
  ArrayOf<USHORT>
		classValue;		/* Array of Class Values--one per GlyphID */
982
  public:
983
  DEFINE_SIZE_ARRAY (6, classValue);
984 985
};

B
Behdad Esfahbod 已提交
986 987
struct ClassDefFormat2
{
988 989 990
  friend struct ClassDef;

  private:
991
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
992
  {
B
Behdad Esfahbod 已提交
993 994 995
    int i = rangeRecord.search (glyph_id);
    if (i != -1)
      return rangeRecord[i].value;
996 997 998
    return 0;
  }

B
Behdad Esfahbod 已提交
999
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1000
    TRACE_SANITIZE (this);
1001
    return TRACE_RETURN (rangeRecord.sanitize (c));
B
Behdad Esfahbod 已提交
1002 1003
  }

1004 1005 1006 1007 1008 1009 1010 1011
  template <typename set_t>
  inline void add_class (set_t *glyphs, unsigned int klass) const {
    unsigned int count = rangeRecord.len;
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass)
        rangeRecord[i].add_coverage (glyphs);
  }

1012
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1013
    unsigned int count = rangeRecord.len;
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
    if (klass == 0)
    {
      /* Match if there's any glyph that is not listed! */
      hb_codepoint_t g = -1;
      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;
      }
      if (g != -1 && hb_set_next (glyphs, &g))
        return true;
      /* Fall through. */
    }
1030 1031 1032 1033 1034 1035
    for (unsigned int i = 0; i < count; i++)
      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
        return true;
    return false;
  }

1036
  protected:
1037
  USHORT	classFormat;	/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
1038
  SortedArrayOf<RangeRecord>
1039 1040
		rangeRecord;	/* Array of glyph ranges--ordered by
				 * Start GlyphID */
1041
  public:
1042
  DEFINE_SIZE_ARRAY (4, rangeRecord);
1043 1044
};

B
Behdad Esfahbod 已提交
1045 1046
struct ClassDef
{
1047
  inline unsigned int get_class (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
1048
  {
1049
    switch (u.format) {
B
Behdad Esfahbod 已提交
1050 1051
    case 1: return u.format1.get_class(glyph_id);
    case 2: return u.format2.get_class(glyph_id);
1052 1053 1054 1055
    default:return 0;
    }
  }

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

1066 1067 1068 1069 1070 1071 1072 1073
  inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
    switch (u.format) {
    case 1: u.format1.add_class (glyphs, klass); return;
    case 2: u.format2.add_class (glyphs, klass); return;
    default:return;
    }
  }

1074
  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1075 1076 1077 1078 1079 1080 1081
    switch (u.format) {
    case 1: return u.format1.intersects_class (glyphs, klass);
    case 2: return u.format2.intersects_class (glyphs, klass);
    default:return false;
    }
  }

1082
  protected:
1083 1084
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1085 1086
  ClassDefFormat1	format1;
  ClassDefFormat2	format2;
1087
  } u;
B
Behdad Esfahbod 已提交
1088
  public:
B
Behdad Esfahbod 已提交
1089
  DEFINE_SIZE_UNION (2, format);
1090 1091 1092 1093 1094 1095 1096
};


/*
 * Device Tables
 */

B
Behdad Esfahbod 已提交
1097 1098
struct Device
{
B
Behdad Esfahbod 已提交
1099

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

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

1106
  inline int get_delta (unsigned int ppem, int scale) const
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
  {
    if (!ppem) return 0;

    int pixels = get_delta_pixels (ppem);

    if (!pixels) return 0;

    return pixels * (int64_t) scale / ppem;
  }


  inline int get_delta_pixels (unsigned int ppem_size) const
B
Behdad Esfahbod 已提交
1119
  {
1120
    unsigned int f = deltaFormat;
1121
    if (unlikely (f < 1 || f > 3))
1122
      return 0;
1123

1124 1125
    if (ppem_size < startSize || ppem_size > endSize)
      return 0;
1126

1127
    unsigned int s = ppem_size - startSize;
1128

1129
    unsigned int byte = deltaValue[s >> (4 - f)];
B
Behdad Esfahbod 已提交
1130 1131
    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
    unsigned int mask = (0xFFFF >> (16 - (1 << f)));
1132 1133 1134

    int delta = bits & mask;

B
Behdad Esfahbod 已提交
1135
    if ((unsigned int) delta >= ((mask + 1) >> 1))
1136 1137 1138 1139 1140
      delta -= mask + 1;

    return delta;
  }

B
Behdad Esfahbod 已提交
1141
  inline unsigned int get_size (void) const
B
Behdad Esfahbod 已提交
1142 1143
  {
    unsigned int f = deltaFormat;
B
Behdad Esfahbod 已提交
1144 1145
    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
B
Behdad Esfahbod 已提交
1146 1147
  }

B
Behdad Esfahbod 已提交
1148
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1149
    TRACE_SANITIZE (this);
1150
    return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
B
Behdad Esfahbod 已提交
1151
  }
1152

1153
  protected:
B
Behdad Esfahbod 已提交
1154 1155
  USHORT	startSize;		/* Smallest size to correct--in ppem */
  USHORT	endSize;		/* Largest size to correct--in ppem */
1156 1157 1158 1159 1160
  USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
					 * 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 已提交
1161
  USHORT	deltaValue[VAR];	/* Array of compressed data */
B
Behdad Esfahbod 已提交
1162
  public:
1163
  DEFINE_SIZE_ARRAY (6, deltaValue);
1164 1165 1166
};


B
Behdad Esfahbod 已提交
1167
} /* namespace OT */
1168

B
Behdad Esfahbod 已提交
1169

1170
#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */