hb-ot-layout-common-private.hh revision dc9f2297998b4cbc4f9e4c2591fc2bb5f92986d1
1/* 2 * Copyright © 2007,2008,2009 Red Hat, Inc. 3 * Copyright © 2010,2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH 30#define HB_OT_LAYOUT_COMMON_PRIVATE_HH 31 32#include "hb-ot-layout-private.hh" 33#include "hb-open-type-private.hh" 34#include "hb-set-private.hh" 35 36 37#ifndef HB_MAX_NESTING_LEVEL 38#define HB_MAX_NESTING_LEVEL 6 39#endif 40#ifndef HB_MAX_CONTEXT_LENGTH 41#define HB_MAX_CONTEXT_LENGTH 64 42#endif 43 44 45namespace OT { 46 47 48#define TRACE_DISPATCH(this, format) \ 49 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ 50 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 51 "format %d", (int) format); 52 53 54#define NOT_COVERED ((unsigned int) -1) 55 56 57 58/* 59 * 60 * OpenType Layout Common Table Formats 61 * 62 */ 63 64 65/* 66 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList 67 */ 68 69template <typename Type> 70struct Record 71{ 72 inline int cmp (hb_tag_t a) const { 73 return tag.cmp (a); 74 } 75 76 struct sanitize_closure_t { 77 hb_tag_t tag; 78 const void *list_base; 79 }; 80 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 81 { 82 TRACE_SANITIZE (this); 83 const sanitize_closure_t closure = {tag, base}; 84 return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); 85 } 86 87 Tag tag; /* 4-byte Tag identifier */ 88 OffsetTo<Type> 89 offset; /* Offset from beginning of object holding 90 * the Record */ 91 public: 92 DEFINE_SIZE_STATIC (6); 93}; 94 95template <typename Type> 96struct RecordArrayOf : SortedArrayOf<Record<Type> > { 97 inline const Tag& get_tag (unsigned int i) const 98 { 99 /* We cheat slightly and don't define separate Null objects 100 * for Record types. Instead, we return the correct Null(Tag) 101 * here. */ 102 if (unlikely (i >= this->len)) return Null(Tag); 103 return (*this)[i].tag; 104 } 105 inline unsigned int get_tags (unsigned int start_offset, 106 unsigned int *record_count /* IN/OUT */, 107 hb_tag_t *record_tags /* OUT */) const 108 { 109 if (record_count) { 110 const Record<Type> *arr = this->sub_array (start_offset, record_count); 111 unsigned int count = *record_count; 112 for (unsigned int i = 0; i < count; i++) 113 record_tags[i] = arr[i].tag; 114 } 115 return this->len; 116 } 117 inline bool find_index (hb_tag_t tag, unsigned int *index) const 118 { 119 /* If we want to allow non-sorted data, we can lsearch(). */ 120 int i = this->/*lsearch*/bsearch (tag); 121 if (i != -1) { 122 if (index) *index = i; 123 return true; 124 } else { 125 if (index) *index = Index::NOT_FOUND_INDEX; 126 return false; 127 } 128 } 129}; 130 131template <typename Type> 132struct RecordListOf : RecordArrayOf<Type> 133{ 134 inline const Type& operator [] (unsigned int i) const 135 { return this+RecordArrayOf<Type>::operator [](i).offset; } 136 137 inline bool sanitize (hb_sanitize_context_t *c) const 138 { 139 TRACE_SANITIZE (this); 140 return_trace (RecordArrayOf<Type>::sanitize (c, this)); 141 } 142}; 143 144 145struct RangeRecord 146{ 147 inline int cmp (hb_codepoint_t g) const { 148 return g < start ? -1 : g <= end ? 0 : +1 ; 149 } 150 151 inline bool sanitize (hb_sanitize_context_t *c) const 152 { 153 TRACE_SANITIZE (this); 154 return_trace (c->check_struct (this)); 155 } 156 157 inline bool intersects (const hb_set_t *glyphs) const { 158 return glyphs->intersects (start, end); 159 } 160 161 template <typename set_t> 162 inline void add_coverage (set_t *glyphs) const { 163 glyphs->add_range (start, end); 164 } 165 166 GlyphID start; /* First GlyphID in the range */ 167 GlyphID end; /* Last GlyphID in the range */ 168 USHORT value; /* Value */ 169 public: 170 DEFINE_SIZE_STATIC (6); 171}; 172DEFINE_NULL_DATA (RangeRecord, "\000\001"); 173 174 175struct IndexArray : ArrayOf<Index> 176{ 177 inline unsigned int get_indexes (unsigned int start_offset, 178 unsigned int *_count /* IN/OUT */, 179 unsigned int *_indexes /* OUT */) const 180 { 181 if (_count) { 182 const USHORT *arr = this->sub_array (start_offset, _count); 183 unsigned int count = *_count; 184 for (unsigned int i = 0; i < count; i++) 185 _indexes[i] = arr[i]; 186 } 187 return this->len; 188 } 189}; 190 191 192struct Script; 193struct LangSys; 194struct Feature; 195 196 197struct LangSys 198{ 199 inline unsigned int get_feature_count (void) const 200 { return featureIndex.len; } 201 inline hb_tag_t get_feature_index (unsigned int i) const 202 { return featureIndex[i]; } 203 inline unsigned int get_feature_indexes (unsigned int start_offset, 204 unsigned int *feature_count /* IN/OUT */, 205 unsigned int *feature_indexes /* OUT */) const 206 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } 207 208 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; } 209 inline unsigned int get_required_feature_index (void) const 210 { 211 if (reqFeatureIndex == 0xFFFFu) 212 return Index::NOT_FOUND_INDEX; 213 return reqFeatureIndex;; 214 } 215 216 inline bool sanitize (hb_sanitize_context_t *c, 217 const Record<LangSys>::sanitize_closure_t * = NULL) const 218 { 219 TRACE_SANITIZE (this); 220 return_trace (c->check_struct (this) && featureIndex.sanitize (c)); 221 } 222 223 Offset<> lookupOrderZ; /* = Null (reserved for an offset to a 224 * reordering table) */ 225 USHORT reqFeatureIndex;/* Index of a feature required for this 226 * language system--if no required features 227 * = 0xFFFFu */ 228 IndexArray featureIndex; /* Array of indices into the FeatureList */ 229 public: 230 DEFINE_SIZE_ARRAY (6, featureIndex); 231}; 232DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); 233 234 235struct Script 236{ 237 inline unsigned int get_lang_sys_count (void) const 238 { return langSys.len; } 239 inline const Tag& get_lang_sys_tag (unsigned int i) const 240 { return langSys.get_tag (i); } 241 inline unsigned int get_lang_sys_tags (unsigned int start_offset, 242 unsigned int *lang_sys_count /* IN/OUT */, 243 hb_tag_t *lang_sys_tags /* OUT */) const 244 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } 245 inline const LangSys& get_lang_sys (unsigned int i) const 246 { 247 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); 248 return this+langSys[i].offset; 249 } 250 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const 251 { return langSys.find_index (tag, index); } 252 253 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } 254 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } 255 256 inline bool sanitize (hb_sanitize_context_t *c, 257 const Record<Script>::sanitize_closure_t * = NULL) const 258 { 259 TRACE_SANITIZE (this); 260 return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); 261 } 262 263 protected: 264 OffsetTo<LangSys> 265 defaultLangSys; /* Offset to DefaultLangSys table--from 266 * beginning of Script table--may be Null */ 267 RecordArrayOf<LangSys> 268 langSys; /* Array of LangSysRecords--listed 269 * alphabetically by LangSysTag */ 270 public: 271 DEFINE_SIZE_ARRAY (4, langSys); 272}; 273 274typedef RecordListOf<Script> ScriptList; 275 276 277/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ 278struct FeatureParamsSize 279{ 280 inline bool sanitize (hb_sanitize_context_t *c) const 281 { 282 TRACE_SANITIZE (this); 283 if (unlikely (!c->check_struct (this))) return_trace (false); 284 285 /* This subtable has some "history", if you will. Some earlier versions of 286 * Adobe tools calculated the offset of the FeatureParams sutable from the 287 * beginning of the FeatureList table! Now, that is dealt with in the 288 * Feature implementation. But we still need to be able to tell junk from 289 * real data. Note: We don't check that the nameID actually exists. 290 * 291 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : 292 * 293 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be 294 * coming out soon, and that the makeotf program will build a font with a 295 * 'size' feature that is correct by the specification. 296 * 297 * The specification for this feature tag is in the "OpenType Layout Tag 298 * Registry". You can see a copy of this at: 299 * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size 300 * 301 * Here is one set of rules to determine if the 'size' feature is built 302 * correctly, or as by the older versions of MakeOTF. You may be able to do 303 * better. 304 * 305 * Assume that the offset to the size feature is according to specification, 306 * and make the following value checks. If it fails, assume the the size 307 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. 308 * If this fails, reject the 'size' feature. The older makeOTF's calculated the 309 * offset from the beginning of the FeatureList table, rather than from the 310 * beginning of the 'size' Feature table. 311 * 312 * If "design size" == 0: 313 * fails check 314 * 315 * Else if ("subfamily identifier" == 0 and 316 * "range start" == 0 and 317 * "range end" == 0 and 318 * "range start" == 0 and 319 * "menu name ID" == 0) 320 * passes check: this is the format used when there is a design size 321 * specified, but there is no recommended size range. 322 * 323 * Else if ("design size" < "range start" or 324 * "design size" > "range end" or 325 * "range end" <= "range start" or 326 * "menu name ID" < 256 or 327 * "menu name ID" > 32767 or 328 * menu name ID is not a name ID which is actually in the name table) 329 * fails test 330 * Else 331 * passes test. 332 */ 333 334 if (!designSize) 335 return_trace (false); 336 else if (subfamilyID == 0 && 337 subfamilyNameID == 0 && 338 rangeStart == 0 && 339 rangeEnd == 0) 340 return_trace (true); 341 else if (designSize < rangeStart || 342 designSize > rangeEnd || 343 subfamilyNameID < 256 || 344 subfamilyNameID > 32767) 345 return_trace (false); 346 else 347 return_trace (true); 348 } 349 350 USHORT designSize; /* Represents the design size in 720/inch 351 * units (decipoints). The design size entry 352 * must be non-zero. When there is a design 353 * size but no recommended size range, the 354 * rest of the array will consist of zeros. */ 355 USHORT subfamilyID; /* Has no independent meaning, but serves 356 * as an identifier that associates fonts 357 * in a subfamily. All fonts which share a 358 * Preferred or Font Family name and which 359 * differ only by size range shall have the 360 * same subfamily value, and no fonts which 361 * differ in weight or style shall have the 362 * same subfamily value. If this value is 363 * zero, the remaining fields in the array 364 * will be ignored. */ 365 USHORT subfamilyNameID;/* If the preceding value is non-zero, this 366 * value must be set in the range 256 - 32767 367 * (inclusive). It records the value of a 368 * field in the name table, which must 369 * contain English-language strings encoded 370 * in Windows Unicode and Macintosh Roman, 371 * and may contain additional strings 372 * localized to other scripts and languages. 373 * Each of these strings is the name an 374 * application should use, in combination 375 * with the family name, to represent the 376 * subfamily in a menu. Applications will 377 * choose the appropriate version based on 378 * their selection criteria. */ 379 USHORT rangeStart; /* Large end of the recommended usage range 380 * (inclusive), stored in 720/inch units 381 * (decipoints). */ 382 USHORT rangeEnd; /* Small end of the recommended usage range 383 (exclusive), stored in 720/inch units 384 * (decipoints). */ 385 public: 386 DEFINE_SIZE_STATIC (10); 387}; 388 389/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ 390struct FeatureParamsStylisticSet 391{ 392 inline bool sanitize (hb_sanitize_context_t *c) const 393 { 394 TRACE_SANITIZE (this); 395 /* Right now minorVersion is at zero. Which means, any table supports 396 * the uiNameID field. */ 397 return_trace (c->check_struct (this)); 398 } 399 400 USHORT version; /* (set to 0): This corresponds to a “minor” 401 * version number. Additional data may be 402 * added to the end of this Feature Parameters 403 * table in the future. */ 404 405 USHORT uiNameID; /* The 'name' table name ID that specifies a 406 * string (or strings, for multiple languages) 407 * for a user-interface label for this 408 * feature. The values of uiLabelNameId and 409 * sampleTextNameId are expected to be in the 410 * font-specific name ID range (256-32767), 411 * though that is not a requirement in this 412 * Feature Parameters specification. The 413 * user-interface label for the feature can 414 * be provided in multiple languages. An 415 * English string should be included as a 416 * fallback. The string should be kept to a 417 * minimal length to fit comfortably with 418 * different application interfaces. */ 419 public: 420 DEFINE_SIZE_STATIC (4); 421}; 422 423/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */ 424struct FeatureParamsCharacterVariants 425{ 426 inline bool sanitize (hb_sanitize_context_t *c) const 427 { 428 TRACE_SANITIZE (this); 429 return_trace (c->check_struct (this) && 430 characters.sanitize (c)); 431 } 432 433 USHORT format; /* Format number is set to 0. */ 434 USHORT featUILableNameID; /* The ‘name’ table name ID that 435 * specifies a string (or strings, 436 * for multiple languages) for a 437 * user-interface label for this 438 * feature. (May be NULL.) */ 439 USHORT featUITooltipTextNameID;/* The ‘name’ table name ID that 440 * specifies a string (or strings, 441 * for multiple languages) that an 442 * application can use for tooltip 443 * text for this feature. (May be 444 * NULL.) */ 445 USHORT sampleTextNameID; /* The ‘name’ table name ID that 446 * specifies sample text that 447 * illustrates the effect of this 448 * feature. (May be NULL.) */ 449 USHORT numNamedParameters; /* Number of named parameters. (May 450 * be zero.) */ 451 USHORT firstParamUILabelNameID;/* The first ‘name’ table name ID 452 * used to specify strings for 453 * user-interface labels for the 454 * feature parameters. (Must be zero 455 * if numParameters is zero.) */ 456 ArrayOf<UINT24> 457 characters; /* Array of the Unicode Scalar Value 458 * of the characters for which this 459 * feature provides glyph variants. 460 * (May be zero.) */ 461 public: 462 DEFINE_SIZE_ARRAY (14, characters); 463}; 464 465struct FeatureParams 466{ 467 inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const 468 { 469 TRACE_SANITIZE (this); 470 if (tag == HB_TAG ('s','i','z','e')) 471 return_trace (u.size.sanitize (c)); 472 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ 473 return_trace (u.stylisticSet.sanitize (c)); 474 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ 475 return_trace (u.characterVariants.sanitize (c)); 476 return_trace (true); 477 } 478 479 inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const 480 { 481 if (tag == HB_TAG ('s','i','z','e')) 482 return u.size; 483 return Null(FeatureParamsSize); 484 } 485 486 private: 487 union { 488 FeatureParamsSize size; 489 FeatureParamsStylisticSet stylisticSet; 490 FeatureParamsCharacterVariants characterVariants; 491 } u; 492 DEFINE_SIZE_STATIC (17); 493}; 494 495struct Feature 496{ 497 inline unsigned int get_lookup_count (void) const 498 { return lookupIndex.len; } 499 inline hb_tag_t get_lookup_index (unsigned int i) const 500 { return lookupIndex[i]; } 501 inline unsigned int get_lookup_indexes (unsigned int start_index, 502 unsigned int *lookup_count /* IN/OUT */, 503 unsigned int *lookup_tags /* OUT */) const 504 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } 505 506 inline const FeatureParams &get_feature_params (void) const 507 { return this+featureParams; } 508 509 inline bool sanitize (hb_sanitize_context_t *c, 510 const Record<Feature>::sanitize_closure_t *closure) const 511 { 512 TRACE_SANITIZE (this); 513 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) 514 return_trace (false); 515 516 /* Some earlier versions of Adobe tools calculated the offset of the 517 * FeatureParams subtable from the beginning of the FeatureList table! 518 * 519 * If sanitizing "failed" for the FeatureParams subtable, try it with the 520 * alternative location. We would know sanitize "failed" if old value 521 * of the offset was non-zero, but it's zeroed now. 522 * 523 * Only do this for the 'size' feature, since at the time of the faulty 524 * Adobe tools, only the 'size' feature had FeatureParams defined. 525 */ 526 527 OffsetTo<FeatureParams> orig_offset = featureParams; 528 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) 529 return_trace (false); 530 531 if (likely (orig_offset.is_null ())) 532 return_trace (true); 533 534 if (featureParams == 0 && closure && 535 closure->tag == HB_TAG ('s','i','z','e') && 536 closure->list_base && closure->list_base < this) 537 { 538 unsigned int new_offset_int = (unsigned int) orig_offset - 539 (((char *) this) - ((char *) closure->list_base)); 540 541 OffsetTo<FeatureParams> new_offset; 542 /* Check that it did not overflow. */ 543 new_offset.set (new_offset_int); 544 if (new_offset == new_offset_int && 545 c->try_set (&featureParams, new_offset) && 546 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) 547 return_trace (false); 548 549 if (c->edit_count > 1) 550 c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */ 551 } 552 553 return_trace (true); 554 } 555 556 OffsetTo<FeatureParams> 557 featureParams; /* Offset to Feature Parameters table (if one 558 * has been defined for the feature), relative 559 * to the beginning of the Feature Table; = Null 560 * if not required */ 561 IndexArray lookupIndex; /* Array of LookupList indices */ 562 public: 563 DEFINE_SIZE_ARRAY (4, lookupIndex); 564}; 565 566typedef RecordListOf<Feature> FeatureList; 567 568 569struct LookupFlag : USHORT 570{ 571 enum Flags { 572 RightToLeft = 0x0001u, 573 IgnoreBaseGlyphs = 0x0002u, 574 IgnoreLigatures = 0x0004u, 575 IgnoreMarks = 0x0008u, 576 IgnoreFlags = 0x000Eu, 577 UseMarkFilteringSet = 0x0010u, 578 Reserved = 0x00E0u, 579 MarkAttachmentType = 0xFF00u 580 }; 581 public: 582 DEFINE_SIZE_STATIC (2); 583}; 584 585} /* namespace OT */ 586/* This has to be outside the namespace. */ 587HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags); 588namespace OT { 589 590struct Lookup 591{ 592 inline unsigned int get_subtable_count (void) const { return subTable.len; } 593 594 template <typename SubTableType> 595 inline const SubTableType& get_subtable (unsigned int i) const 596 { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; } 597 598 template <typename SubTableType> 599 inline const OffsetArrayOf<SubTableType>& get_subtables (void) const 600 { return CastR<OffsetArrayOf<SubTableType> > (subTable); } 601 template <typename SubTableType> 602 inline OffsetArrayOf<SubTableType>& get_subtables (void) 603 { return CastR<OffsetArrayOf<SubTableType> > (subTable); } 604 605 inline unsigned int get_type (void) const { return lookupType; } 606 607 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and 608 * higher 16-bit is mark-filtering-set if the lookup uses one. 609 * Not to be confused with glyph_props which is very similar. */ 610 inline uint32_t get_props (void) const 611 { 612 unsigned int flag = lookupFlag; 613 if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) 614 { 615 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 616 flag += (markFilteringSet << 16); 617 } 618 return flag; 619 } 620 621 template <typename SubTableType, typename context_t> 622 inline typename context_t::return_t dispatch (context_t *c) const 623 { 624 unsigned int lookup_type = get_type (); 625 TRACE_DISPATCH (this, lookup_type); 626 unsigned int count = get_subtable_count (); 627 for (unsigned int i = 0; i < count; i++) { 628 typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type); 629 if (c->stop_sublookup_iteration (r)) 630 return_trace (r); 631 } 632 return_trace (c->default_return_value ()); 633 } 634 635 inline bool serialize (hb_serialize_context_t *c, 636 unsigned int lookup_type, 637 uint32_t lookup_props, 638 unsigned int num_subtables) 639 { 640 TRACE_SERIALIZE (this); 641 if (unlikely (!c->extend_min (*this))) return_trace (false); 642 lookupType.set (lookup_type); 643 lookupFlag.set (lookup_props & 0xFFFFu); 644 if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); 645 if (lookupFlag & LookupFlag::UseMarkFilteringSet) 646 { 647 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 648 markFilteringSet.set (lookup_props >> 16); 649 } 650 return_trace (true); 651 } 652 653 inline bool sanitize (hb_sanitize_context_t *c) const 654 { 655 TRACE_SANITIZE (this); 656 /* Real sanitize of the subtables is done by GSUB/GPOS/... */ 657 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); 658 if (lookupFlag & LookupFlag::UseMarkFilteringSet) 659 { 660 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 661 if (!markFilteringSet.sanitize (c)) return_trace (false); 662 } 663 return_trace (true); 664 } 665 666 private: 667 USHORT lookupType; /* Different enumerations for GSUB and GPOS */ 668 USHORT lookupFlag; /* Lookup qualifiers */ 669 ArrayOf<Offset<> > 670 subTable; /* Array of SubTables */ 671 USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets 672 * structure. This field is only present if bit 673 * UseMarkFilteringSet of lookup flags is set. */ 674 public: 675 DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); 676}; 677 678typedef OffsetListOf<Lookup> LookupList; 679 680 681/* 682 * Coverage Table 683 */ 684 685struct CoverageFormat1 686{ 687 friend struct Coverage; 688 689 private: 690 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 691 { 692 int i = glyphArray.bsearch (glyph_id); 693 ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED); 694 return i; 695 } 696 697 inline bool serialize (hb_serialize_context_t *c, 698 Supplier<GlyphID> &glyphs, 699 unsigned int num_glyphs) 700 { 701 TRACE_SERIALIZE (this); 702 if (unlikely (!c->extend_min (*this))) return_trace (false); 703 glyphArray.len.set (num_glyphs); 704 if (unlikely (!c->extend (glyphArray))) return_trace (false); 705 for (unsigned int i = 0; i < num_glyphs; i++) 706 glyphArray[i] = glyphs[i]; 707 glyphs.advance (num_glyphs); 708 return_trace (true); 709 } 710 711 inline bool sanitize (hb_sanitize_context_t *c) const 712 { 713 TRACE_SANITIZE (this); 714 return_trace (glyphArray.sanitize (c)); 715 } 716 717 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 718 return glyphs->has (glyphArray[index]); 719 } 720 721 template <typename set_t> 722 inline void add_coverage (set_t *glyphs) const { 723 unsigned int count = glyphArray.len; 724 for (unsigned int i = 0; i < count; i++) 725 glyphs->add (glyphArray[i]); 726 } 727 728 public: 729 /* Older compilers need this to be public. */ 730 struct Iter { 731 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; 732 inline bool more (void) { return i < c->glyphArray.len; } 733 inline void next (void) { i++; } 734 inline uint16_t get_glyph (void) { return c->glyphArray[i]; } 735 inline uint16_t get_coverage (void) { return i; } 736 737 private: 738 const struct CoverageFormat1 *c; 739 unsigned int i; 740 }; 741 private: 742 743 protected: 744 USHORT coverageFormat; /* Format identifier--format = 1 */ 745 SortedArrayOf<GlyphID> 746 glyphArray; /* Array of GlyphIDs--in numerical order */ 747 public: 748 DEFINE_SIZE_ARRAY (4, glyphArray); 749}; 750 751struct CoverageFormat2 752{ 753 friend struct Coverage; 754 755 private: 756 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 757 { 758 int i = rangeRecord.bsearch (glyph_id); 759 if (i != -1) { 760 const RangeRecord &range = rangeRecord[i]; 761 return (unsigned int) range.value + (glyph_id - range.start); 762 } 763 return NOT_COVERED; 764 } 765 766 inline bool serialize (hb_serialize_context_t *c, 767 Supplier<GlyphID> &glyphs, 768 unsigned int num_glyphs) 769 { 770 TRACE_SERIALIZE (this); 771 if (unlikely (!c->extend_min (*this))) return_trace (false); 772 773 if (unlikely (!num_glyphs)) 774 { 775 rangeRecord.len.set (0); 776 return_trace (true); 777 } 778 779 unsigned int num_ranges = 1; 780 for (unsigned int i = 1; i < num_glyphs; i++) 781 if (glyphs[i - 1] + 1 != glyphs[i]) 782 num_ranges++; 783 rangeRecord.len.set (num_ranges); 784 if (unlikely (!c->extend (rangeRecord))) return_trace (false); 785 786 unsigned int range = 0; 787 rangeRecord[range].start = glyphs[0]; 788 rangeRecord[range].value.set (0); 789 for (unsigned int i = 1; i < num_glyphs; i++) 790 if (glyphs[i - 1] + 1 != glyphs[i]) { 791 range++; 792 rangeRecord[range].start = glyphs[i]; 793 rangeRecord[range].value.set (i); 794 rangeRecord[range].end = glyphs[i]; 795 } else { 796 rangeRecord[range].end = glyphs[i]; 797 } 798 glyphs.advance (num_glyphs); 799 return_trace (true); 800 } 801 802 inline bool sanitize (hb_sanitize_context_t *c) const 803 { 804 TRACE_SANITIZE (this); 805 return_trace (rangeRecord.sanitize (c)); 806 } 807 808 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 809 unsigned int i; 810 unsigned int count = rangeRecord.len; 811 for (i = 0; i < count; i++) { 812 const RangeRecord &range = rangeRecord[i]; 813 if (range.value <= index && 814 index < (unsigned int) range.value + (range.end - range.start) && 815 range.intersects (glyphs)) 816 return true; 817 else if (index < range.value) 818 return false; 819 } 820 return false; 821 } 822 823 template <typename set_t> 824 inline void add_coverage (set_t *glyphs) const { 825 unsigned int count = rangeRecord.len; 826 for (unsigned int i = 0; i < count; i++) 827 rangeRecord[i].add_coverage (glyphs); 828 } 829 830 public: 831 /* Older compilers need this to be public. */ 832 struct Iter { 833 inline void init (const CoverageFormat2 &c_) { 834 c = &c_; 835 coverage = 0; 836 i = 0; 837 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; 838 } 839 inline bool more (void) { return i < c->rangeRecord.len; } 840 inline void next (void) { 841 coverage++; 842 if (j == c->rangeRecord[i].end) { 843 i++; 844 if (more ()) 845 j = c->rangeRecord[i].start; 846 return; 847 } 848 j++; 849 } 850 inline uint16_t get_glyph (void) { return j; } 851 inline uint16_t get_coverage (void) { return coverage; } 852 853 private: 854 const struct CoverageFormat2 *c; 855 unsigned int i, j, coverage; 856 }; 857 private: 858 859 protected: 860 USHORT coverageFormat; /* Format identifier--format = 2 */ 861 SortedArrayOf<RangeRecord> 862 rangeRecord; /* Array of glyph ranges--ordered by 863 * Start GlyphID. rangeCount entries 864 * long */ 865 public: 866 DEFINE_SIZE_ARRAY (4, rangeRecord); 867}; 868 869struct Coverage 870{ 871 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 872 { 873 switch (u.format) { 874 case 1: return u.format1.get_coverage(glyph_id); 875 case 2: return u.format2.get_coverage(glyph_id); 876 default:return NOT_COVERED; 877 } 878 } 879 880 inline bool serialize (hb_serialize_context_t *c, 881 Supplier<GlyphID> &glyphs, 882 unsigned int num_glyphs) 883 { 884 TRACE_SERIALIZE (this); 885 if (unlikely (!c->extend_min (*this))) return_trace (false); 886 unsigned int num_ranges = 1; 887 for (unsigned int i = 1; i < num_glyphs; i++) 888 if (glyphs[i - 1] + 1 != glyphs[i]) 889 num_ranges++; 890 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); 891 switch (u.format) { 892 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); 893 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); 894 default:return_trace (false); 895 } 896 } 897 898 inline bool sanitize (hb_sanitize_context_t *c) const 899 { 900 TRACE_SANITIZE (this); 901 if (!u.format.sanitize (c)) return_trace (false); 902 switch (u.format) { 903 case 1: return_trace (u.format1.sanitize (c)); 904 case 2: return_trace (u.format2.sanitize (c)); 905 default:return_trace (true); 906 } 907 } 908 909 inline bool intersects (const hb_set_t *glyphs) const { 910 /* TODO speed this up */ 911 Coverage::Iter iter; 912 for (iter.init (*this); iter.more (); iter.next ()) { 913 if (glyphs->has (iter.get_glyph ())) 914 return true; 915 } 916 return false; 917 } 918 919 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 920 switch (u.format) { 921 case 1: return u.format1.intersects_coverage (glyphs, index); 922 case 2: return u.format2.intersects_coverage (glyphs, index); 923 default:return false; 924 } 925 } 926 927 template <typename set_t> 928 inline void add_coverage (set_t *glyphs) const { 929 switch (u.format) { 930 case 1: u.format1.add_coverage (glyphs); break; 931 case 2: u.format2.add_coverage (glyphs); break; 932 default: break; 933 } 934 } 935 936 struct Iter { 937 Iter (void) : format (0) {}; 938 inline void init (const Coverage &c_) { 939 format = c_.u.format; 940 switch (format) { 941 case 1: u.format1.init (c_.u.format1); return; 942 case 2: u.format2.init (c_.u.format2); return; 943 default: return; 944 } 945 } 946 inline bool more (void) { 947 switch (format) { 948 case 1: return u.format1.more (); 949 case 2: return u.format2.more (); 950 default:return false; 951 } 952 } 953 inline void next (void) { 954 switch (format) { 955 case 1: u.format1.next (); break; 956 case 2: u.format2.next (); break; 957 default: break; 958 } 959 } 960 inline uint16_t get_glyph (void) { 961 switch (format) { 962 case 1: return u.format1.get_glyph (); 963 case 2: return u.format2.get_glyph (); 964 default:return 0; 965 } 966 } 967 inline uint16_t get_coverage (void) { 968 switch (format) { 969 case 1: return u.format1.get_coverage (); 970 case 2: return u.format2.get_coverage (); 971 default:return -1; 972 } 973 } 974 975 private: 976 unsigned int format; 977 union { 978 CoverageFormat1::Iter format1; 979 CoverageFormat2::Iter format2; 980 } u; 981 }; 982 983 protected: 984 union { 985 USHORT format; /* Format identifier */ 986 CoverageFormat1 format1; 987 CoverageFormat2 format2; 988 } u; 989 public: 990 DEFINE_SIZE_UNION (2, format); 991}; 992 993 994/* 995 * Class Definition Table 996 */ 997 998struct ClassDefFormat1 999{ 1000 friend struct ClassDef; 1001 1002 private: 1003 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1004 { 1005 unsigned int i = (unsigned int) (glyph_id - startGlyph); 1006 if (unlikely (i < classValue.len)) 1007 return classValue[i]; 1008 return 0; 1009 } 1010 1011 inline bool sanitize (hb_sanitize_context_t *c) const 1012 { 1013 TRACE_SANITIZE (this); 1014 return_trace (c->check_struct (this) && classValue.sanitize (c)); 1015 } 1016 1017 template <typename set_t> 1018 inline void add_class (set_t *glyphs, unsigned int klass) const { 1019 unsigned int count = classValue.len; 1020 for (unsigned int i = 0; i < count; i++) 1021 if (classValue[i] == klass) 1022 glyphs->add (startGlyph + i); 1023 } 1024 1025 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1026 unsigned int count = classValue.len; 1027 if (klass == 0) 1028 { 1029 /* Match if there's any glyph that is not listed! */ 1030 hb_codepoint_t g = -1; 1031 if (!hb_set_next (glyphs, &g)) 1032 return false; 1033 if (g < startGlyph) 1034 return true; 1035 g = startGlyph + count - 1; 1036 if (hb_set_next (glyphs, &g)) 1037 return true; 1038 /* Fall through. */ 1039 } 1040 for (unsigned int i = 0; i < count; i++) 1041 if (classValue[i] == klass && glyphs->has (startGlyph + i)) 1042 return true; 1043 return false; 1044 } 1045 1046 protected: 1047 USHORT classFormat; /* Format identifier--format = 1 */ 1048 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 1049 ArrayOf<USHORT> 1050 classValue; /* Array of Class Values--one per GlyphID */ 1051 public: 1052 DEFINE_SIZE_ARRAY (6, classValue); 1053}; 1054 1055struct ClassDefFormat2 1056{ 1057 friend struct ClassDef; 1058 1059 private: 1060 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1061 { 1062 int i = rangeRecord.bsearch (glyph_id); 1063 if (unlikely (i != -1)) 1064 return rangeRecord[i].value; 1065 return 0; 1066 } 1067 1068 inline bool sanitize (hb_sanitize_context_t *c) const 1069 { 1070 TRACE_SANITIZE (this); 1071 return_trace (rangeRecord.sanitize (c)); 1072 } 1073 1074 template <typename set_t> 1075 inline void add_class (set_t *glyphs, unsigned int klass) const { 1076 unsigned int count = rangeRecord.len; 1077 for (unsigned int i = 0; i < count; i++) 1078 if (rangeRecord[i].value == klass) 1079 rangeRecord[i].add_coverage (glyphs); 1080 } 1081 1082 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1083 unsigned int count = rangeRecord.len; 1084 if (klass == 0) 1085 { 1086 /* Match if there's any glyph that is not listed! */ 1087 hb_codepoint_t g = (hb_codepoint_t) -1; 1088 for (unsigned int i = 0; i < count; i++) 1089 { 1090 if (!hb_set_next (glyphs, &g)) 1091 break; 1092 if (g < rangeRecord[i].start) 1093 return true; 1094 g = rangeRecord[i].end; 1095 } 1096 if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g)) 1097 return true; 1098 /* Fall through. */ 1099 } 1100 for (unsigned int i = 0; i < count; i++) 1101 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) 1102 return true; 1103 return false; 1104 } 1105 1106 protected: 1107 USHORT classFormat; /* Format identifier--format = 2 */ 1108 SortedArrayOf<RangeRecord> 1109 rangeRecord; /* Array of glyph ranges--ordered by 1110 * Start GlyphID */ 1111 public: 1112 DEFINE_SIZE_ARRAY (4, rangeRecord); 1113}; 1114 1115struct ClassDef 1116{ 1117 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1118 { 1119 switch (u.format) { 1120 case 1: return u.format1.get_class(glyph_id); 1121 case 2: return u.format2.get_class(glyph_id); 1122 default:return 0; 1123 } 1124 } 1125 1126 inline bool sanitize (hb_sanitize_context_t *c) const 1127 { 1128 TRACE_SANITIZE (this); 1129 if (!u.format.sanitize (c)) return_trace (false); 1130 switch (u.format) { 1131 case 1: return_trace (u.format1.sanitize (c)); 1132 case 2: return_trace (u.format2.sanitize (c)); 1133 default:return_trace (true); 1134 } 1135 } 1136 1137 inline void add_class (hb_set_t *glyphs, unsigned int klass) const { 1138 switch (u.format) { 1139 case 1: u.format1.add_class (glyphs, klass); return; 1140 case 2: u.format2.add_class (glyphs, klass); return; 1141 default:return; 1142 } 1143 } 1144 1145 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1146 switch (u.format) { 1147 case 1: return u.format1.intersects_class (glyphs, klass); 1148 case 2: return u.format2.intersects_class (glyphs, klass); 1149 default:return false; 1150 } 1151 } 1152 1153 protected: 1154 union { 1155 USHORT format; /* Format identifier */ 1156 ClassDefFormat1 format1; 1157 ClassDefFormat2 format2; 1158 } u; 1159 public: 1160 DEFINE_SIZE_UNION (2, format); 1161}; 1162 1163 1164/* 1165 * Item Variation Store 1166 */ 1167 1168struct VarRegionAxis 1169{ 1170 inline float evaluate (int coord) const 1171 { 1172 int start = startCoord, peak = peakCoord, end = endCoord; 1173 1174 /* TODO Move these to sanitize(). */ 1175 if (unlikely (start > peak || peak > end)) 1176 return 1.; 1177 if (unlikely (start < 0 && end > 0 && peak != 0)) 1178 return 1.; 1179 1180 if (peak == 0 || coord == peak) 1181 return 1.; 1182 1183 if (coord <= start || end <= coord) 1184 return 0.; 1185 1186 /* Interpolate */ 1187 if (coord < peak) 1188 return float (coord - start) / (peak - start); 1189 else 1190 return float (end - coord) / (end - peak); 1191 } 1192 1193 inline bool sanitize (hb_sanitize_context_t *c) const 1194 { 1195 TRACE_SANITIZE (this); 1196 return_trace (c->check_struct (this)); 1197 /* TODO Handle invalid start/peak/end configs, so we don't 1198 * have to do that at runtime. */ 1199 } 1200 1201 public: 1202 F2DOT14 startCoord; 1203 F2DOT14 peakCoord; 1204 F2DOT14 endCoord; 1205 public: 1206 DEFINE_SIZE_STATIC (6); 1207}; 1208 1209struct VarRegionList 1210{ 1211 inline float evaluate (unsigned int region_index, 1212 int *coords, unsigned int coord_len) const 1213 { 1214 if (unlikely (region_index >= regionCount)) 1215 return 0.; 1216 1217 const VarRegionAxis *axes = axesZ + (region_index * axisCount); 1218 1219 float v = 1.; 1220 unsigned int count = MIN (coord_len, (unsigned int) axisCount); 1221 for (unsigned int i = 0; i < count; i++) 1222 { 1223 float factor = axes[i].evaluate (coords[i]); 1224 if (factor == 0.) 1225 return 0.; 1226 v *= factor; 1227 } 1228 return v; 1229 } 1230 1231 inline bool sanitize (hb_sanitize_context_t *c) const 1232 { 1233 TRACE_SANITIZE (this); 1234 return_trace (c->check_struct (this) && 1235 c->check_array (axesZ, axesZ[0].static_size, 1236 (unsigned int) axisCount * (unsigned int) regionCount)); 1237 } 1238 1239 protected: 1240 USHORT axisCount; 1241 USHORT regionCount; 1242 VarRegionAxis axesZ[VAR]; 1243 public: 1244 DEFINE_SIZE_ARRAY (4, axesZ); 1245}; 1246 1247struct VarData 1248{ 1249 inline unsigned int get_row_size (void) const 1250 { return shortCount + regionIndices.len; } 1251 1252 inline unsigned int get_size (void) const 1253 { return itemCount * get_row_size (); } 1254 1255 inline float get_delta (unsigned int inner, 1256 int *coords, unsigned int coord_count, 1257 const VarRegionList ®ions) const 1258 { 1259 if (unlikely (inner >= itemCount)) 1260 return 0.; 1261 1262 unsigned int count = regionIndices.len; 1263 unsigned int scount = shortCount; 1264 1265 const BYTE *bytes = &StructAfter<BYTE> (regionIndices); 1266 const BYTE *row = bytes + inner * (scount + count); 1267 1268 1269 float delta = 0.; 1270 unsigned int i = 0; 1271 1272 const SHORT *scursor = reinterpret_cast<const SHORT *> (row); 1273 for (; i < scount; i++) 1274 { 1275 float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count); 1276 delta += scalar * *scursor++; 1277 } 1278 const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor); 1279 for (; i < count; i++) 1280 { 1281 float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count); 1282 delta += scalar * *bcursor++; 1283 } 1284 1285 return delta; 1286 } 1287 1288 inline bool sanitize (hb_sanitize_context_t *c) const 1289 { 1290 TRACE_SANITIZE (this); 1291 return_trace (c->check_struct (this) && 1292 regionIndices.sanitize(c) && 1293 shortCount <= regionIndices.len && 1294 c->check_array (&StructAfter<BYTE> (regionIndices), 1295 get_row_size (), itemCount)); 1296 } 1297 1298 protected: 1299 USHORT itemCount; 1300 USHORT shortCount; 1301 ArrayOf<USHORT> regionIndices; 1302 BYTE bytesX[VAR]; 1303 public: 1304 DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX); 1305}; 1306 1307struct VarStore 1308{ 1309 inline float get_delta (unsigned int outer, unsigned int inner, 1310 int *coords, unsigned int coord_count) const 1311 { 1312 if (unlikely (outer >= dataSets.len)) 1313 return 0.; 1314 1315 return (this+dataSets[outer]).get_delta (inner, 1316 coords, coord_count, 1317 this+regions); 1318 } 1319 1320 inline bool sanitize (hb_sanitize_context_t *c) const 1321 { 1322 TRACE_SANITIZE (this); 1323 return_trace (c->check_struct (this) && 1324 format == 1 && 1325 regions.sanitize (c, this) && 1326 dataSets.sanitize (c, this)); 1327 } 1328 1329 protected: 1330 USHORT format; 1331 OffsetTo<VarRegionList, ULONG> regions; 1332 OffsetArrayOf<VarData, ULONG> dataSets; 1333 public: 1334 DEFINE_SIZE_ARRAY (8, dataSets); 1335}; 1336 1337 1338/* 1339 * Device Tables 1340 */ 1341 1342struct HintingDevice 1343{ 1344 friend struct Device; 1345 1346 private: 1347 1348 inline hb_position_t get_x_delta (hb_font_t *font) const 1349 { return get_delta (font->x_ppem, font->x_scale); } 1350 1351 inline hb_position_t get_y_delta (hb_font_t *font) const 1352 { return get_delta (font->y_ppem, font->y_scale); } 1353 1354 inline unsigned int get_size (void) const 1355 { 1356 unsigned int f = deltaFormat; 1357 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; 1358 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); 1359 } 1360 1361 inline bool sanitize (hb_sanitize_context_t *c) const 1362 { 1363 TRACE_SANITIZE (this); 1364 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); 1365 } 1366 1367 private: 1368 1369 inline int get_delta (unsigned int ppem, int scale) const 1370 { 1371 if (!ppem) return 0; 1372 1373 int pixels = get_delta_pixels (ppem); 1374 1375 if (!pixels) return 0; 1376 1377 return (int) (pixels * (int64_t) scale / ppem); 1378 } 1379 inline int get_delta_pixels (unsigned int ppem_size) const 1380 { 1381 unsigned int f = deltaFormat; 1382 if (unlikely (f < 1 || f > 3)) 1383 return 0; 1384 1385 if (ppem_size < startSize || ppem_size > endSize) 1386 return 0; 1387 1388 unsigned int s = ppem_size - startSize; 1389 1390 unsigned int byte = deltaValue[s >> (4 - f)]; 1391 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 1392 unsigned int mask = (0xFFFFu >> (16 - (1 << f))); 1393 1394 int delta = bits & mask; 1395 1396 if ((unsigned int) delta >= ((mask + 1) >> 1)) 1397 delta -= mask + 1; 1398 1399 return delta; 1400 } 1401 1402 protected: 1403 USHORT startSize; /* Smallest size to correct--in ppem */ 1404 USHORT endSize; /* Largest size to correct--in ppem */ 1405 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 1406 * 1 Signed 2-bit value, 8 values per uint16 1407 * 2 Signed 4-bit value, 4 values per uint16 1408 * 3 Signed 8-bit value, 2 values per uint16 1409 */ 1410 USHORT deltaValue[VAR]; /* Array of compressed data */ 1411 public: 1412 DEFINE_SIZE_ARRAY (6, deltaValue); 1413}; 1414 1415struct VariationDevice 1416{ 1417 friend struct Device; 1418 1419 private: 1420 1421 inline hb_position_t get_x_delta (hb_font_t *font) const 1422 { return font->em_scalef_x (get_delta (font->x_coords, font->num_coords)); } 1423 1424 inline hb_position_t get_y_delta (hb_font_t *font) const 1425 { return font->em_scalef_y (get_delta (font->y_coords, font->num_coords)); } 1426 1427 inline bool sanitize (hb_sanitize_context_t *c) const 1428 { 1429 TRACE_SANITIZE (this); 1430 return_trace (c->check_struct (this)); 1431 } 1432 1433 private: 1434 1435 inline float get_delta (int *coords, unsigned int coord_count) const 1436 { 1437 float v = 0; 1438 /* XXXXXXXXXXXXXXX call into GDEF. */ 1439 return v; 1440 } 1441 1442 protected: 1443 USHORT outerIndex; 1444 USHORT innerIndex; 1445 USHORT deltaFormat; /* Format identifier for this table: 0x0x8000 */ 1446 public: 1447 DEFINE_SIZE_STATIC (6); 1448}; 1449 1450struct Device 1451{ 1452 inline hb_position_t get_x_delta (hb_font_t *font) const 1453 { 1454 switch (u.b.format) 1455 { 1456 case 1: case 2: case 3: 1457 return u.hinting.get_x_delta (font); 1458 case 0x8000: 1459 return u.variation.get_x_delta (font); 1460 default: 1461 return 0; 1462 } 1463 } 1464 inline hb_position_t get_y_delta (hb_font_t *font) const 1465 { 1466 switch (u.b.format) 1467 { 1468 case 1: case 2: case 3: 1469 return u.hinting.get_x_delta (font); 1470 case 0x8000: 1471 default: 1472 return 0; 1473 } 1474 } 1475 1476 inline bool sanitize (hb_sanitize_context_t *c) const 1477 { 1478 TRACE_SANITIZE (this); 1479 if (!u.b.format.sanitize (c)) return_trace (false); 1480 switch (u.b.format) { 1481 case 1: case 2: case 3: 1482 return_trace (u.hinting.sanitize (c)); 1483 case 0x8000: 1484 return_trace (u.variation.sanitize (c)); 1485 default: 1486 return_trace (true); 1487 } 1488 } 1489 1490 protected: 1491 union { 1492 struct { 1493 USHORT reserved1; 1494 USHORT reserved2; 1495 USHORT format; /* Format identifier */ 1496 public: 1497 DEFINE_SIZE_STATIC (6); 1498 } b; 1499 HintingDevice hinting; 1500 VariationDevice variation; 1501 } u; 1502 public: 1503 DEFINE_SIZE_UNION (6, b); 1504}; 1505 1506 1507} /* namespace OT */ 1508 1509 1510#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 1511