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 45 namespace 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 69 template <typename Type> 70 struct 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 95 template <typename Type> 96 struct 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 131 template <typename Type> 132 struct 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 145 struct 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 }; 172 DEFINE_NULL_DATA (RangeRecord, "\000\001"); 173 174 175 struct 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 192 struct Script; 193 struct LangSys; 194 struct Feature; 195 196 197 struct 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 }; 232 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); 233 234 235 struct 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 274 typedef RecordListOf<Script> ScriptList; 275 276 277 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ 278 struct 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 (at) 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 */ 390 struct 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 */ 424 struct 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 465 struct 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 495 struct 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 = NULL) 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 566 typedef RecordListOf<Feature> FeatureList; 567 568 569 struct 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. */ 587 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags); 588 namespace OT { 589 590 struct 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 678 typedef OffsetListOf<Lookup> LookupList; 679 680 681 /* 682 * Coverage Table 683 */ 684 685 struct 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 hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; } 735 inline unsigned int 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 751 struct 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 { 834 inline void init (const CoverageFormat2 &c_) 835 { 836 c = &c_; 837 coverage = 0; 838 i = 0; 839 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; 840 } 841 inline bool more (void) { return i < c->rangeRecord.len; } 842 inline void next (void) 843 { 844 if (j >= c->rangeRecord[i].end) 845 { 846 i++; 847 if (more ()) 848 { 849 j = c->rangeRecord[i].start; 850 coverage = c->rangeRecord[i].value; 851 } 852 return; 853 } 854 coverage++; 855 j++; 856 } 857 inline hb_codepoint_t get_glyph (void) { return j; } 858 inline unsigned int get_coverage (void) { return coverage; } 859 860 private: 861 const struct CoverageFormat2 *c; 862 unsigned int i, j, coverage; 863 }; 864 private: 865 866 protected: 867 USHORT coverageFormat; /* Format identifier--format = 2 */ 868 SortedArrayOf<RangeRecord> 869 rangeRecord; /* Array of glyph ranges--ordered by 870 * Start GlyphID. rangeCount entries 871 * long */ 872 public: 873 DEFINE_SIZE_ARRAY (4, rangeRecord); 874 }; 875 876 struct Coverage 877 { 878 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 879 { 880 switch (u.format) { 881 case 1: return u.format1.get_coverage(glyph_id); 882 case 2: return u.format2.get_coverage(glyph_id); 883 default:return NOT_COVERED; 884 } 885 } 886 887 inline bool serialize (hb_serialize_context_t *c, 888 Supplier<GlyphID> &glyphs, 889 unsigned int num_glyphs) 890 { 891 TRACE_SERIALIZE (this); 892 if (unlikely (!c->extend_min (*this))) return_trace (false); 893 unsigned int num_ranges = 1; 894 for (unsigned int i = 1; i < num_glyphs; i++) 895 if (glyphs[i - 1] + 1 != glyphs[i]) 896 num_ranges++; 897 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); 898 switch (u.format) { 899 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); 900 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); 901 default:return_trace (false); 902 } 903 } 904 905 inline bool sanitize (hb_sanitize_context_t *c) const 906 { 907 TRACE_SANITIZE (this); 908 if (!u.format.sanitize (c)) return_trace (false); 909 switch (u.format) { 910 case 1: return_trace (u.format1.sanitize (c)); 911 case 2: return_trace (u.format2.sanitize (c)); 912 default:return_trace (true); 913 } 914 } 915 916 inline bool intersects (const hb_set_t *glyphs) const { 917 /* TODO speed this up */ 918 Coverage::Iter iter; 919 for (iter.init (*this); iter.more (); iter.next ()) { 920 if (glyphs->has (iter.get_glyph ())) 921 return true; 922 } 923 return false; 924 } 925 926 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 927 switch (u.format) { 928 case 1: return u.format1.intersects_coverage (glyphs, index); 929 case 2: return u.format2.intersects_coverage (glyphs, index); 930 default:return false; 931 } 932 } 933 934 template <typename set_t> 935 inline void add_coverage (set_t *glyphs) const { 936 switch (u.format) { 937 case 1: u.format1.add_coverage (glyphs); break; 938 case 2: u.format2.add_coverage (glyphs); break; 939 default: break; 940 } 941 } 942 943 struct Iter { 944 Iter (void) : format (0) {}; 945 inline void init (const Coverage &c_) { 946 format = c_.u.format; 947 switch (format) { 948 case 1: u.format1.init (c_.u.format1); return; 949 case 2: u.format2.init (c_.u.format2); return; 950 default: return; 951 } 952 } 953 inline bool more (void) { 954 switch (format) { 955 case 1: return u.format1.more (); 956 case 2: return u.format2.more (); 957 default:return false; 958 } 959 } 960 inline void next (void) { 961 switch (format) { 962 case 1: u.format1.next (); break; 963 case 2: u.format2.next (); break; 964 default: break; 965 } 966 } 967 inline hb_codepoint_t get_glyph (void) { 968 switch (format) { 969 case 1: return u.format1.get_glyph (); 970 case 2: return u.format2.get_glyph (); 971 default:return 0; 972 } 973 } 974 inline unsigned int get_coverage (void) { 975 switch (format) { 976 case 1: return u.format1.get_coverage (); 977 case 2: return u.format2.get_coverage (); 978 default:return -1; 979 } 980 } 981 982 private: 983 unsigned int format; 984 union { 985 CoverageFormat1::Iter format1; 986 CoverageFormat2::Iter format2; 987 } u; 988 }; 989 990 protected: 991 union { 992 USHORT format; /* Format identifier */ 993 CoverageFormat1 format1; 994 CoverageFormat2 format2; 995 } u; 996 public: 997 DEFINE_SIZE_UNION (2, format); 998 }; 999 1000 1001 /* 1002 * Class Definition Table 1003 */ 1004 1005 struct ClassDefFormat1 1006 { 1007 friend struct ClassDef; 1008 1009 private: 1010 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1011 { 1012 unsigned int i = (unsigned int) (glyph_id - startGlyph); 1013 if (unlikely (i < classValue.len)) 1014 return classValue[i]; 1015 return 0; 1016 } 1017 1018 inline bool sanitize (hb_sanitize_context_t *c) const 1019 { 1020 TRACE_SANITIZE (this); 1021 return_trace (c->check_struct (this) && classValue.sanitize (c)); 1022 } 1023 1024 template <typename set_t> 1025 inline void add_class (set_t *glyphs, unsigned int klass) const { 1026 unsigned int count = classValue.len; 1027 for (unsigned int i = 0; i < count; i++) 1028 if (classValue[i] == klass) 1029 glyphs->add (startGlyph + i); 1030 } 1031 1032 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1033 unsigned int count = classValue.len; 1034 if (klass == 0) 1035 { 1036 /* Match if there's any glyph that is not listed! */ 1037 hb_codepoint_t g = -1; 1038 if (!hb_set_next (glyphs, &g)) 1039 return false; 1040 if (g < startGlyph) 1041 return true; 1042 g = startGlyph + count - 1; 1043 if (hb_set_next (glyphs, &g)) 1044 return true; 1045 /* Fall through. */ 1046 } 1047 for (unsigned int i = 0; i < count; i++) 1048 if (classValue[i] == klass && glyphs->has (startGlyph + i)) 1049 return true; 1050 return false; 1051 } 1052 1053 protected: 1054 USHORT classFormat; /* Format identifier--format = 1 */ 1055 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 1056 ArrayOf<USHORT> 1057 classValue; /* Array of Class Values--one per GlyphID */ 1058 public: 1059 DEFINE_SIZE_ARRAY (6, classValue); 1060 }; 1061 1062 struct ClassDefFormat2 1063 { 1064 friend struct ClassDef; 1065 1066 private: 1067 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1068 { 1069 int i = rangeRecord.bsearch (glyph_id); 1070 if (unlikely (i != -1)) 1071 return rangeRecord[i].value; 1072 return 0; 1073 } 1074 1075 inline bool sanitize (hb_sanitize_context_t *c) const 1076 { 1077 TRACE_SANITIZE (this); 1078 return_trace (rangeRecord.sanitize (c)); 1079 } 1080 1081 template <typename set_t> 1082 inline void add_class (set_t *glyphs, unsigned int klass) const { 1083 unsigned int count = rangeRecord.len; 1084 for (unsigned int i = 0; i < count; i++) 1085 if (rangeRecord[i].value == klass) 1086 rangeRecord[i].add_coverage (glyphs); 1087 } 1088 1089 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1090 unsigned int count = rangeRecord.len; 1091 if (klass == 0) 1092 { 1093 /* Match if there's any glyph that is not listed! */ 1094 hb_codepoint_t g = (hb_codepoint_t) -1; 1095 for (unsigned int i = 0; i < count; i++) 1096 { 1097 if (!hb_set_next (glyphs, &g)) 1098 break; 1099 if (g < rangeRecord[i].start) 1100 return true; 1101 g = rangeRecord[i].end; 1102 } 1103 if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g)) 1104 return true; 1105 /* Fall through. */ 1106 } 1107 for (unsigned int i = 0; i < count; i++) 1108 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) 1109 return true; 1110 return false; 1111 } 1112 1113 protected: 1114 USHORT classFormat; /* Format identifier--format = 2 */ 1115 SortedArrayOf<RangeRecord> 1116 rangeRecord; /* Array of glyph ranges--ordered by 1117 * Start GlyphID */ 1118 public: 1119 DEFINE_SIZE_ARRAY (4, rangeRecord); 1120 }; 1121 1122 struct ClassDef 1123 { 1124 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1125 { 1126 switch (u.format) { 1127 case 1: return u.format1.get_class(glyph_id); 1128 case 2: return u.format2.get_class(glyph_id); 1129 default:return 0; 1130 } 1131 } 1132 1133 inline bool sanitize (hb_sanitize_context_t *c) const 1134 { 1135 TRACE_SANITIZE (this); 1136 if (!u.format.sanitize (c)) return_trace (false); 1137 switch (u.format) { 1138 case 1: return_trace (u.format1.sanitize (c)); 1139 case 2: return_trace (u.format2.sanitize (c)); 1140 default:return_trace (true); 1141 } 1142 } 1143 1144 inline void add_class (hb_set_t *glyphs, unsigned int klass) const { 1145 switch (u.format) { 1146 case 1: u.format1.add_class (glyphs, klass); return; 1147 case 2: u.format2.add_class (glyphs, klass); return; 1148 default:return; 1149 } 1150 } 1151 1152 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1153 switch (u.format) { 1154 case 1: return u.format1.intersects_class (glyphs, klass); 1155 case 2: return u.format2.intersects_class (glyphs, klass); 1156 default:return false; 1157 } 1158 } 1159 1160 protected: 1161 union { 1162 USHORT format; /* Format identifier */ 1163 ClassDefFormat1 format1; 1164 ClassDefFormat2 format2; 1165 } u; 1166 public: 1167 DEFINE_SIZE_UNION (2, format); 1168 }; 1169 1170 1171 /* 1172 * Item Variation Store 1173 */ 1174 1175 struct VarRegionAxis 1176 { 1177 inline float evaluate (int coord) const 1178 { 1179 int start = startCoord, peak = peakCoord, end = endCoord; 1180 1181 /* TODO Move these to sanitize(). */ 1182 if (unlikely (start > peak || peak > end)) 1183 return 1.; 1184 if (unlikely (start < 0 && end > 0 && peak != 0)) 1185 return 1.; 1186 1187 if (peak == 0 || coord == peak) 1188 return 1.; 1189 1190 if (coord <= start || end <= coord) 1191 return 0.; 1192 1193 /* Interpolate */ 1194 if (coord < peak) 1195 return float (coord - start) / (peak - start); 1196 else 1197 return float (end - coord) / (end - peak); 1198 } 1199 1200 inline bool sanitize (hb_sanitize_context_t *c) const 1201 { 1202 TRACE_SANITIZE (this); 1203 return_trace (c->check_struct (this)); 1204 /* TODO Handle invalid start/peak/end configs, so we don't 1205 * have to do that at runtime. */ 1206 } 1207 1208 public: 1209 F2DOT14 startCoord; 1210 F2DOT14 peakCoord; 1211 F2DOT14 endCoord; 1212 public: 1213 DEFINE_SIZE_STATIC (6); 1214 }; 1215 1216 struct VarRegionList 1217 { 1218 inline float evaluate (unsigned int region_index, 1219 int *coords, unsigned int coord_len) const 1220 { 1221 if (unlikely (region_index >= regionCount)) 1222 return 0.; 1223 1224 const VarRegionAxis *axes = axesZ + (region_index * axisCount); 1225 1226 float v = 1.; 1227 unsigned int count = MIN (coord_len, (unsigned int) axisCount); 1228 for (unsigned int i = 0; i < count; i++) 1229 { 1230 float factor = axes[i].evaluate (coords[i]); 1231 if (factor == 0.) 1232 return 0.; 1233 v *= factor; 1234 } 1235 return v; 1236 } 1237 1238 inline bool sanitize (hb_sanitize_context_t *c) const 1239 { 1240 TRACE_SANITIZE (this); 1241 return_trace (c->check_struct (this) && 1242 c->check_array (axesZ, axesZ[0].static_size, 1243 (unsigned int) axisCount * (unsigned int) regionCount)); 1244 } 1245 1246 protected: 1247 USHORT axisCount; 1248 USHORT regionCount; 1249 VarRegionAxis axesZ[VAR]; 1250 public: 1251 DEFINE_SIZE_ARRAY (4, axesZ); 1252 }; 1253 1254 struct VarData 1255 { 1256 inline unsigned int get_row_size (void) const 1257 { return shortCount + regionIndices.len; } 1258 1259 inline unsigned int get_size (void) const 1260 { return itemCount * get_row_size (); } 1261 1262 inline float get_delta (unsigned int inner, 1263 int *coords, unsigned int coord_count, 1264 const VarRegionList ®ions) const 1265 { 1266 if (unlikely (inner >= itemCount)) 1267 return 0.; 1268 1269 unsigned int count = regionIndices.len; 1270 unsigned int scount = shortCount; 1271 1272 const BYTE *bytes = &StructAfter<BYTE> (regionIndices); 1273 const BYTE *row = bytes + inner * (scount + count); 1274 1275 float delta = 0.; 1276 unsigned int i = 0; 1277 1278 const SHORT *scursor = reinterpret_cast<const SHORT *> (row); 1279 for (; i < scount; i++) 1280 { 1281 float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count); 1282 delta += scalar * *scursor++; 1283 } 1284 const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor); 1285 for (; i < count; i++) 1286 { 1287 float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count); 1288 delta += scalar * *bcursor++; 1289 } 1290 1291 return delta; 1292 } 1293 1294 inline bool sanitize (hb_sanitize_context_t *c) const 1295 { 1296 TRACE_SANITIZE (this); 1297 return_trace (c->check_struct (this) && 1298 regionIndices.sanitize(c) && 1299 shortCount <= regionIndices.len && 1300 c->check_array (&StructAfter<BYTE> (regionIndices), 1301 get_row_size (), itemCount)); 1302 } 1303 1304 protected: 1305 USHORT itemCount; 1306 USHORT shortCount; 1307 ArrayOf<USHORT> regionIndices; 1308 BYTE bytesX[VAR]; 1309 public: 1310 DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX); 1311 }; 1312 1313 struct VariationStore 1314 { 1315 inline float get_delta (unsigned int outer, unsigned int inner, 1316 int *coords, unsigned int coord_count) const 1317 { 1318 if (unlikely (outer >= dataSets.len)) 1319 return 0.; 1320 1321 return (this+dataSets[outer]).get_delta (inner, 1322 coords, coord_count, 1323 this+regions); 1324 } 1325 1326 inline float get_delta (unsigned int index, 1327 int *coords, unsigned int coord_count) const 1328 { 1329 unsigned int outer = index >> 16; 1330 unsigned int inner = index & 0xFFFF; 1331 return get_delta (outer, inner, coords, coord_count); 1332 } 1333 1334 inline bool sanitize (hb_sanitize_context_t *c) const 1335 { 1336 TRACE_SANITIZE (this); 1337 return_trace (c->check_struct (this) && 1338 format == 1 && 1339 regions.sanitize (c, this) && 1340 dataSets.sanitize (c, this)); 1341 } 1342 1343 protected: 1344 USHORT format; 1345 LOffsetTo<VarRegionList> regions; 1346 OffsetArrayOf<VarData, ULONG> dataSets; 1347 public: 1348 DEFINE_SIZE_ARRAY (8, dataSets); 1349 }; 1350 1351 /* 1352 * Feature Variations 1353 */ 1354 1355 struct ConditionFormat1 1356 { 1357 friend struct Condition; 1358 1359 private: 1360 inline bool evaluate (const int *coords, unsigned int coord_len) const 1361 { 1362 int coord = axisIndex < coord_len ? coords[axisIndex] : 0; 1363 return filterRangeMinValue <= coord && coord <= filterRangeMaxValue; 1364 } 1365 1366 inline bool sanitize (hb_sanitize_context_t *c) const 1367 { 1368 TRACE_SANITIZE (this); 1369 return_trace (c->check_struct (this)); 1370 } 1371 1372 protected: 1373 USHORT format; /* Format identifier--format = 1 */ 1374 USHORT axisIndex; 1375 F2DOT14 filterRangeMinValue; 1376 F2DOT14 filterRangeMaxValue; 1377 public: 1378 DEFINE_SIZE_STATIC (8); 1379 }; 1380 1381 struct Condition 1382 { 1383 inline bool evaluate (const int *coords, unsigned int coord_len) const 1384 { 1385 switch (u.format) { 1386 case 1: return u.format1.evaluate (coords, coord_len); 1387 default:return false; 1388 } 1389 } 1390 1391 inline bool sanitize (hb_sanitize_context_t *c) const 1392 { 1393 TRACE_SANITIZE (this); 1394 if (!u.format.sanitize (c)) return_trace (false); 1395 switch (u.format) { 1396 case 1: return_trace (u.format1.sanitize (c)); 1397 default:return_trace (true); 1398 } 1399 } 1400 1401 protected: 1402 union { 1403 USHORT format; /* Format identifier */ 1404 ConditionFormat1 format1; 1405 } u; 1406 public: 1407 DEFINE_SIZE_UNION (2, format); 1408 }; 1409 1410 struct ConditionSet 1411 { 1412 inline bool evaluate (const int *coords, unsigned int coord_len) const 1413 { 1414 unsigned int count = conditions.len; 1415 for (unsigned int i = 0; i < count; i++) 1416 if (!(this+conditions.array[i]).evaluate (coords, coord_len)) 1417 return false; 1418 return true; 1419 } 1420 1421 inline bool sanitize (hb_sanitize_context_t *c) const 1422 { 1423 TRACE_SANITIZE (this); 1424 return_trace (conditions.sanitize (c, this)); 1425 } 1426 1427 protected: 1428 OffsetArrayOf<Condition, ULONG> conditions; 1429 public: 1430 DEFINE_SIZE_ARRAY (2, conditions); 1431 }; 1432 1433 struct FeatureTableSubstitutionRecord 1434 { 1435 friend struct FeatureTableSubstitution; 1436 1437 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 1438 { 1439 TRACE_SANITIZE (this); 1440 return_trace (c->check_struct (this) && feature.sanitize (c, base)); 1441 } 1442 1443 protected: 1444 USHORT featureIndex; 1445 LOffsetTo<Feature> feature; 1446 public: 1447 DEFINE_SIZE_STATIC (6); 1448 }; 1449 1450 struct FeatureTableSubstitution 1451 { 1452 inline const Feature *find_substitute (unsigned int feature_index) const 1453 { 1454 unsigned int count = substitutions.len; 1455 for (unsigned int i = 0; i < count; i++) 1456 { 1457 const FeatureTableSubstitutionRecord &record = substitutions.array[i]; 1458 if (record.featureIndex == feature_index) 1459 return &(this+record.feature); 1460 } 1461 return NULL; 1462 } 1463 1464 inline bool sanitize (hb_sanitize_context_t *c) const 1465 { 1466 TRACE_SANITIZE (this); 1467 return_trace (version.sanitize (c) && 1468 likely (version.major == 1) && 1469 substitutions.sanitize (c, this)); 1470 } 1471 1472 protected: 1473 FixedVersion<> version; /* Version--0x00010000u */ 1474 ArrayOf<FeatureTableSubstitutionRecord> 1475 substitutions; 1476 public: 1477 DEFINE_SIZE_ARRAY (6, substitutions); 1478 }; 1479 1480 struct FeatureVariationRecord 1481 { 1482 friend struct FeatureVariations; 1483 1484 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const 1485 { 1486 TRACE_SANITIZE (this); 1487 return_trace (conditions.sanitize (c, base) && 1488 substitutions.sanitize (c, base)); 1489 } 1490 1491 protected: 1492 LOffsetTo<ConditionSet> 1493 conditions; 1494 LOffsetTo<FeatureTableSubstitution> 1495 substitutions; 1496 public: 1497 DEFINE_SIZE_STATIC (8); 1498 }; 1499 1500 struct FeatureVariations 1501 { 1502 static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu; 1503 1504 inline bool find_index (const int *coords, unsigned int coord_len, 1505 unsigned int *index) const 1506 { 1507 unsigned int count = varRecords.len; 1508 for (unsigned int i = 0; i < count; i++) 1509 { 1510 const FeatureVariationRecord &record = varRecords.array[i]; 1511 if ((this+record.conditions).evaluate (coords, coord_len)) 1512 { 1513 *index = i; 1514 return true; 1515 } 1516 } 1517 *index = NOT_FOUND_INDEX; 1518 return false; 1519 } 1520 1521 inline const Feature *find_substitute (unsigned int variations_index, 1522 unsigned int feature_index) const 1523 { 1524 const FeatureVariationRecord &record = varRecords[variations_index]; 1525 return (this+record.substitutions).find_substitute (feature_index); 1526 } 1527 1528 inline bool sanitize (hb_sanitize_context_t *c) const 1529 { 1530 TRACE_SANITIZE (this); 1531 return_trace (version.sanitize (c) && 1532 likely (version.major == 1) && 1533 varRecords.sanitize (c, this)); 1534 } 1535 1536 protected: 1537 FixedVersion<> version; /* Version--0x00010000u */ 1538 LArrayOf<FeatureVariationRecord> 1539 varRecords; 1540 public: 1541 DEFINE_SIZE_ARRAY (8, varRecords); 1542 }; 1543 1544 1545 /* 1546 * Device Tables 1547 */ 1548 1549 struct HintingDevice 1550 { 1551 friend struct Device; 1552 1553 private: 1554 1555 inline hb_position_t get_x_delta (hb_font_t *font) const 1556 { return get_delta (font->x_ppem, font->x_scale); } 1557 1558 inline hb_position_t get_y_delta (hb_font_t *font) const 1559 { return get_delta (font->y_ppem, font->y_scale); } 1560 1561 inline unsigned int get_size (void) const 1562 { 1563 unsigned int f = deltaFormat; 1564 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; 1565 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); 1566 } 1567 1568 inline bool sanitize (hb_sanitize_context_t *c) const 1569 { 1570 TRACE_SANITIZE (this); 1571 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); 1572 } 1573 1574 private: 1575 1576 inline int get_delta (unsigned int ppem, int scale) const 1577 { 1578 if (!ppem) return 0; 1579 1580 int pixels = get_delta_pixels (ppem); 1581 1582 if (!pixels) return 0; 1583 1584 return (int) (pixels * (int64_t) scale / ppem); 1585 } 1586 inline int get_delta_pixels (unsigned int ppem_size) const 1587 { 1588 unsigned int f = deltaFormat; 1589 if (unlikely (f < 1 || f > 3)) 1590 return 0; 1591 1592 if (ppem_size < startSize || ppem_size > endSize) 1593 return 0; 1594 1595 unsigned int s = ppem_size - startSize; 1596 1597 unsigned int byte = deltaValue[s >> (4 - f)]; 1598 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 1599 unsigned int mask = (0xFFFFu >> (16 - (1 << f))); 1600 1601 int delta = bits & mask; 1602 1603 if ((unsigned int) delta >= ((mask + 1) >> 1)) 1604 delta -= mask + 1; 1605 1606 return delta; 1607 } 1608 1609 protected: 1610 USHORT startSize; /* Smallest size to correct--in ppem */ 1611 USHORT endSize; /* Largest size to correct--in ppem */ 1612 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 1613 * 1 Signed 2-bit value, 8 values per uint16 1614 * 2 Signed 4-bit value, 4 values per uint16 1615 * 3 Signed 8-bit value, 2 values per uint16 1616 */ 1617 USHORT deltaValue[VAR]; /* Array of compressed data */ 1618 public: 1619 DEFINE_SIZE_ARRAY (6, deltaValue); 1620 }; 1621 1622 struct VariationDevice 1623 { 1624 friend struct Device; 1625 1626 private: 1627 1628 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const 1629 { return font->em_scalef_x (get_delta (font, store)); } 1630 1631 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const 1632 { return font->em_scalef_y (get_delta (font, store)); } 1633 1634 inline bool sanitize (hb_sanitize_context_t *c) const 1635 { 1636 TRACE_SANITIZE (this); 1637 return_trace (c->check_struct (this)); 1638 } 1639 1640 private: 1641 1642 inline float get_delta (hb_font_t *font, const VariationStore &store) const 1643 { 1644 return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords); 1645 } 1646 1647 protected: 1648 USHORT outerIndex; 1649 USHORT innerIndex; 1650 USHORT deltaFormat; /* Format identifier for this table: 0x0x8000 */ 1651 public: 1652 DEFINE_SIZE_STATIC (6); 1653 }; 1654 1655 struct DeviceHeader 1656 { 1657 protected: 1658 USHORT reserved1; 1659 USHORT reserved2; 1660 public: 1661 USHORT format; /* Format identifier */ 1662 public: 1663 DEFINE_SIZE_STATIC (6); 1664 }; 1665 1666 struct Device 1667 { 1668 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const 1669 { 1670 switch (u.b.format) 1671 { 1672 case 1: case 2: case 3: 1673 return u.hinting.get_x_delta (font); 1674 case 0x8000: 1675 return u.variation.get_x_delta (font, store); 1676 default: 1677 return 0; 1678 } 1679 } 1680 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const 1681 { 1682 switch (u.b.format) 1683 { 1684 case 1: case 2: case 3: 1685 return u.hinting.get_y_delta (font); 1686 case 0x8000: 1687 return u.variation.get_y_delta (font, store); 1688 default: 1689 return 0; 1690 } 1691 } 1692 1693 inline bool sanitize (hb_sanitize_context_t *c) const 1694 { 1695 TRACE_SANITIZE (this); 1696 if (!u.b.format.sanitize (c)) return_trace (false); 1697 switch (u.b.format) { 1698 case 1: case 2: case 3: 1699 return_trace (u.hinting.sanitize (c)); 1700 case 0x8000: 1701 return_trace (u.variation.sanitize (c)); 1702 default: 1703 return_trace (true); 1704 } 1705 } 1706 1707 protected: 1708 union { 1709 DeviceHeader b; 1710 HintingDevice hinting; 1711 VariationDevice variation; 1712 } u; 1713 public: 1714 DEFINE_SIZE_UNION (6, b); 1715 }; 1716 1717 1718 } /* namespace OT */ 1719 1720 1721 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 1722