hb-ot-layout-common-private.hh revision 625678436c29100eef82d87e635b251030a18f60
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 37namespace OT { 38 39 40#define NOT_COVERED ((unsigned int) -1) 41#define MAX_NESTING_LEVEL 8 42 43 44 45/* 46 * 47 * OpenType Layout Common Table Formats 48 * 49 */ 50 51 52/* 53 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList 54 */ 55 56template <typename Type> 57struct Record 58{ 59 inline int cmp (hb_tag_t a) const { 60 return tag.cmp (a); 61 } 62 63 struct sanitize_closure_t { 64 hb_tag_t tag; 65 void *list_base; 66 }; 67 inline bool sanitize (hb_sanitize_context_t *c, void *base) { 68 TRACE_SANITIZE (this); 69 const sanitize_closure_t closure = {tag, base}; 70 return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure)); 71 } 72 73 Tag tag; /* 4-byte Tag identifier */ 74 OffsetTo<Type> 75 offset; /* Offset from beginning of object holding 76 * the Record */ 77 public: 78 DEFINE_SIZE_STATIC (6); 79}; 80 81template <typename Type> 82struct RecordArrayOf : SortedArrayOf<Record<Type> > { 83 inline const Tag& get_tag (unsigned int i) const 84 { 85 /* We cheat slightly and don't define separate Null objects 86 * for Record types. Instead, we return the correct Null(Tag) 87 * here. */ 88 if (unlikely (i >= this->len)) return Null(Tag); 89 return (*this)[i].tag; 90 } 91 inline unsigned int get_tags (unsigned int start_offset, 92 unsigned int *record_count /* IN/OUT */, 93 hb_tag_t *record_tags /* OUT */) const 94 { 95 if (record_count) { 96 const Record<Type> *arr = this->sub_array (start_offset, record_count); 97 unsigned int count = *record_count; 98 for (unsigned int i = 0; i < count; i++) 99 record_tags[i] = arr[i].tag; 100 } 101 return this->len; 102 } 103 inline bool find_index (hb_tag_t tag, unsigned int *index) const 104 { 105 int i = this->search (tag); 106 if (i != -1) { 107 if (index) *index = i; 108 return true; 109 } else { 110 if (index) *index = Index::NOT_FOUND_INDEX; 111 return false; 112 } 113 } 114}; 115 116template <typename Type> 117struct RecordListOf : RecordArrayOf<Type> 118{ 119 inline const Type& operator [] (unsigned int i) const 120 { return this+RecordArrayOf<Type>::operator [](i).offset; } 121 122 inline bool sanitize (hb_sanitize_context_t *c) { 123 TRACE_SANITIZE (this); 124 return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this)); 125 } 126}; 127 128 129struct RangeRecord 130{ 131 inline int cmp (hb_codepoint_t g) const { 132 return g < start ? -1 : g <= end ? 0 : +1 ; 133 } 134 135 inline bool sanitize (hb_sanitize_context_t *c) { 136 TRACE_SANITIZE (this); 137 return TRACE_RETURN (c->check_struct (this)); 138 } 139 140 inline bool intersects (const hb_set_t *glyphs) const { 141 return glyphs->intersects (start, end); 142 } 143 144 template <typename set_t> 145 inline void add_coverage (set_t *glyphs) const { 146 glyphs->add_range (start, end); 147 } 148 149 GlyphID start; /* First GlyphID in the range */ 150 GlyphID end; /* Last GlyphID in the range */ 151 USHORT value; /* Value */ 152 public: 153 DEFINE_SIZE_STATIC (6); 154}; 155DEFINE_NULL_DATA (RangeRecord, "\000\001"); 156 157 158struct IndexArray : ArrayOf<Index> 159{ 160 inline unsigned int get_indexes (unsigned int start_offset, 161 unsigned int *_count /* IN/OUT */, 162 unsigned int *_indexes /* OUT */) const 163 { 164 if (_count) { 165 const USHORT *arr = this->sub_array (start_offset, _count); 166 unsigned int count = *_count; 167 for (unsigned int i = 0; i < count; i++) 168 _indexes[i] = arr[i]; 169 } 170 return this->len; 171 } 172}; 173 174 175struct Script; 176struct LangSys; 177struct Feature; 178 179 180struct LangSys 181{ 182 inline unsigned int get_feature_count (void) const 183 { return featureIndex.len; } 184 inline hb_tag_t get_feature_index (unsigned int i) const 185 { return featureIndex[i]; } 186 inline unsigned int get_feature_indexes (unsigned int start_offset, 187 unsigned int *feature_count /* IN/OUT */, 188 unsigned int *feature_indexes /* OUT */) const 189 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } 190 191 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; } 192 inline unsigned int get_required_feature_index (void) const 193 { 194 if (reqFeatureIndex == 0xffff) 195 return Index::NOT_FOUND_INDEX; 196 return reqFeatureIndex;; 197 } 198 199 inline bool sanitize (hb_sanitize_context_t *c, 200 const Record<LangSys>::sanitize_closure_t * = NULL) { 201 TRACE_SANITIZE (this); 202 return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); 203 } 204 205 Offset lookupOrder; /* = Null (reserved for an offset to a 206 * reordering table) */ 207 USHORT reqFeatureIndex;/* Index of a feature required for this 208 * language system--if no required features 209 * = 0xFFFF */ 210 IndexArray featureIndex; /* Array of indices into the FeatureList */ 211 public: 212 DEFINE_SIZE_ARRAY (6, featureIndex); 213}; 214DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); 215 216 217struct Script 218{ 219 inline unsigned int get_lang_sys_count (void) const 220 { return langSys.len; } 221 inline const Tag& get_lang_sys_tag (unsigned int i) const 222 { return langSys.get_tag (i); } 223 inline unsigned int get_lang_sys_tags (unsigned int start_offset, 224 unsigned int *lang_sys_count /* IN/OUT */, 225 hb_tag_t *lang_sys_tags /* OUT */) const 226 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } 227 inline const LangSys& get_lang_sys (unsigned int i) const 228 { 229 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); 230 return this+langSys[i].offset; 231 } 232 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const 233 { return langSys.find_index (tag, index); } 234 235 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } 236 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } 237 238 inline bool sanitize (hb_sanitize_context_t *c, 239 const Record<Script>::sanitize_closure_t * = NULL) { 240 TRACE_SANITIZE (this); 241 return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); 242 } 243 244 protected: 245 OffsetTo<LangSys> 246 defaultLangSys; /* Offset to DefaultLangSys table--from 247 * beginning of Script table--may be Null */ 248 RecordArrayOf<LangSys> 249 langSys; /* Array of LangSysRecords--listed 250 * alphabetically by LangSysTag */ 251 public: 252 DEFINE_SIZE_ARRAY (4, langSys); 253}; 254 255typedef RecordListOf<Script> ScriptList; 256 257 258/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ 259struct FeatureParamsSize 260{ 261 inline bool sanitize (hb_sanitize_context_t *c) { 262 TRACE_SANITIZE (this); 263 if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); 264 265 /* This subtable has some "history", if you will. Some earlier versions of 266 * Adobe tools calculated the offset of the FeatureParams sutable from the 267 * beginning of the FeatureList table! Now, that is dealt with in the 268 * Feature implementation. But we still need to be able to tell junk from 269 * real data. Note: We don't check that the nameID actually exists. 270 * 271 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : 272 * 273 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be 274 * coming out soon, and that the makeotf program will build a font with a 275 * 'size' feature that is correct by the specification. 276 * 277 * The specification for this feature tag is in the "OpenType Layout Tag 278 * Registry". You can see a copy of this at: 279 * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size 280 * 281 * Here is one set of rules to determine if the 'size' feature is built 282 * correctly, or as by the older versions of MakeOTF. You may be able to do 283 * better. 284 * 285 * Assume that the offset to the size feature is according to specification, 286 * and make the following value checks. If it fails, assume the the size 287 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. 288 * If this fails, reject the 'size' feature. The older makeOTF's calculated the 289 * offset from the beginning of the FeatureList table, rather than from the 290 * beginning of the 'size' Feature table. 291 * 292 * If "design size" == 0: 293 * fails check 294 * 295 * Else if ("subfamily identifier" == 0 and 296 * "range start" == 0 and 297 * "range end" == 0 and 298 * "range start" == 0 and 299 * "menu name ID" == 0) 300 * passes check: this is the format used when there is a design size 301 * specified, but there is no recommended size range. 302 * 303 * Else if ("design size" < "range start" or 304 * "design size" > "range end" or 305 * "range end" <= "range start" or 306 * "menu name ID" < 256 or 307 * "menu name ID" > 32767 or 308 * menu name ID is not a name ID which is actually in the name table) 309 * fails test 310 * Else 311 * passes test. 312 */ 313 314 if (!designSize) 315 return TRACE_RETURN (false); 316 else if (subfamilyID == 0 && 317 subfamilyNameID == 0 && 318 rangeStart == 0 && 319 rangeEnd == 0) 320 return TRACE_RETURN (true); 321 else if (designSize < rangeStart || 322 designSize > rangeEnd || 323 subfamilyNameID < 256 || 324 subfamilyNameID > 32767) 325 return TRACE_RETURN (false); 326 else 327 return TRACE_RETURN (true); 328 } 329 330 USHORT designSize; /* Represents the design size in 720/inch 331 * units (decipoints). The design size entry 332 * must be non-zero. When there is a design 333 * size but no recommended size range, the 334 * rest of the array will consist of zeros. */ 335 USHORT subfamilyID; /* Has no independent meaning, but serves 336 * as an identifier that associates fonts 337 * in a subfamily. All fonts which share a 338 * Preferred or Font Family name and which 339 * differ only by size range shall have the 340 * same subfamily value, and no fonts which 341 * differ in weight or style shall have the 342 * same subfamily value. If this value is 343 * zero, the remaining fields in the array 344 * will be ignored. */ 345 USHORT subfamilyNameID;/* If the preceding value is non-zero, this 346 * value must be set in the range 256 - 32767 347 * (inclusive). It records the value of a 348 * field in the name table, which must 349 * contain English-language strings encoded 350 * in Windows Unicode and Macintosh Roman, 351 * and may contain additional strings 352 * localized to other scripts and languages. 353 * Each of these strings is the name an 354 * application should use, in combination 355 * with the family name, to represent the 356 * subfamily in a menu. Applications will 357 * choose the appropriate version based on 358 * their selection criteria. */ 359 USHORT rangeStart; /* Large end of the recommended usage range 360 * (inclusive), stored in 720/inch units 361 * (decipoints). */ 362 USHORT rangeEnd; /* Small end of the recommended usage range 363 (exclusive), stored in 720/inch units 364 * (decipoints). */ 365 public: 366 DEFINE_SIZE_STATIC (10); 367}; 368 369/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ 370struct FeatureParamsStylisticSet 371{ 372 inline bool sanitize (hb_sanitize_context_t *c) { 373 TRACE_SANITIZE (this); 374 /* Right now minorVersion is at zero. Which means, any table supports 375 * the uiNameID field. */ 376 return TRACE_RETURN (c->check_struct (this)); 377 } 378 379 USHORT minorVersion; /* (set to 0): This corresponds to a “minor” 380 * version number. Additional data may be 381 * added to the end of this Feature Parameters 382 * table in the future. */ 383 384 USHORT uiNameID; /* The 'name' table name ID that specifies a 385 * string (or strings, for multiple languages) 386 * for a user-interface label for this 387 * feature. The values of uiLabelNameId and 388 * sampleTextNameId are expected to be in the 389 * font-specific name ID range (256-32767), 390 * though that is not a requirement in this 391 * Feature Parameters specification. The 392 * user-interface label for the feature can 393 * be provided in multiple languages. An 394 * English string should be included as a 395 * fallback. The string should be kept to a 396 * minimal length to fit comfortably with 397 * different application interfaces. */ 398 public: 399 DEFINE_SIZE_STATIC (4); 400}; 401 402struct FeatureParamsCharacterVariants 403{ 404 inline bool sanitize (hb_sanitize_context_t *c) { 405 TRACE_SANITIZE (this); 406 return TRACE_RETURN (c->check_struct (this) && 407 characters.sanitize (c)); 408 } 409 410 USHORT format; /* Format number is set to 0. */ 411 USHORT featUILableNameID; /* The ‘name’ table name ID that 412 * specifies a string (or strings, 413 * for multiple languages) for a 414 * user-interface label for this 415 * feature. (May be NULL.) */ 416 USHORT featUITooltipTextNameID;/* The ‘name’ table name ID that 417 * specifies a string (or strings, 418 * for multiple languages) that an 419 * application can use for tooltip 420 * text for this feature. (May be 421 * NULL.) */ 422 USHORT sampleTextNameID; /* The ‘name’ table name ID that 423 * specifies sample text that 424 * illustrates the effect of this 425 * feature. (May be NULL.) */ 426 USHORT numNamedParameters; /* Number of named parameters. (May 427 * be zero.) */ 428 USHORT firstParamUILabelNameID;/* The first ‘name’ table name ID 429 * used to specify strings for 430 * user-interface labels for the 431 * feature parameters. (Must be zero 432 * if numParameters is zero.) */ 433 ArrayOf<UINT24> 434 characters; /* Array of the Unicode Scalar Value 435 * of the characters for which this 436 * feature provides glyph variants. 437 * (May be zero.) */ 438 public: 439 DEFINE_SIZE_ARRAY (14, characters); 440}; 441 442struct FeatureParams 443{ 444 inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) { 445 TRACE_SANITIZE (this); 446 if (tag == HB_TAG ('s','i','z','e')) 447 return TRACE_RETURN (u.size.sanitize (c)); 448 if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */ 449 return TRACE_RETURN (u.stylisticSet.sanitize (c)); 450 if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */ 451 return TRACE_RETURN (u.characterVariants.sanitize (c)); 452 return TRACE_RETURN (true); 453 } 454 455 inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const 456 { 457 if (tag == HB_TAG ('s','i','z','e')) 458 return u.size; 459 return Null(FeatureParamsSize); 460 } 461 462 private: 463 union { 464 FeatureParamsSize size; 465 FeatureParamsStylisticSet stylisticSet; 466 FeatureParamsCharacterVariants characterVariants; 467 } u; 468 DEFINE_SIZE_STATIC (17); 469}; 470 471struct Feature 472{ 473 inline unsigned int get_lookup_count (void) const 474 { return lookupIndex.len; } 475 inline hb_tag_t get_lookup_index (unsigned int i) const 476 { return lookupIndex[i]; } 477 inline unsigned int get_lookup_indexes (unsigned int start_index, 478 unsigned int *lookup_count /* IN/OUT */, 479 unsigned int *lookup_tags /* OUT */) const 480 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } 481 482 inline const FeatureParams &get_feature_params (void) const 483 { return this+featureParams; } 484 485 inline bool sanitize (hb_sanitize_context_t *c, 486 const Record<Feature>::sanitize_closure_t *closure) { 487 TRACE_SANITIZE (this); 488 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) 489 return TRACE_RETURN (false); 490 491 /* Some earlier versions of Adobe tools calculated the offset of the 492 * FeatureParams subtable from the beginning of the FeatureList table! 493 * 494 * If sanitizing "failed" for the FeatureParams subtable, try it with the 495 * alternative location. We would know sanitize "failed" if old value 496 * of the offset was non-zero, but it's zeroed now. 497 * 498 * Only do this for the 'size' feature, since at the time of the faulty 499 * Adobe tools, only the 'size' feature had FeatureParams defined. 500 */ 501 502 Offset orig_offset = featureParams; 503 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) 504 return TRACE_RETURN (false); 505 506 if (likely (!orig_offset)) 507 return TRACE_RETURN (true); 508 509 if (featureParams == 0 && closure && 510 closure->tag == HB_TAG ('s','i','z','e') && 511 closure->list_base && closure->list_base < this) 512 { 513 unsigned int new_offset_int = (unsigned int) orig_offset - 514 ((char *) this - (char *) closure->list_base); 515 516 Offset new_offset; 517 /* Check that it did not overflow. */ 518 new_offset.set (new_offset_int); 519 if (new_offset == new_offset_int && 520 featureParams.try_set (c, new_offset) && 521 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) 522 return TRACE_RETURN (false); 523 } 524 525 return TRACE_RETURN (true); 526 } 527 528 OffsetTo<FeatureParams> 529 featureParams; /* Offset to Feature Parameters table (if one 530 * has been defined for the feature), relative 531 * to the beginning of the Feature Table; = Null 532 * if not required */ 533 IndexArray lookupIndex; /* Array of LookupList indices */ 534 public: 535 DEFINE_SIZE_ARRAY (4, lookupIndex); 536}; 537 538typedef RecordListOf<Feature> FeatureList; 539 540 541struct LookupFlag : USHORT 542{ 543 enum Flags { 544 RightToLeft = 0x0001u, 545 IgnoreBaseGlyphs = 0x0002u, 546 IgnoreLigatures = 0x0004u, 547 IgnoreMarks = 0x0008u, 548 IgnoreFlags = 0x000Eu, 549 UseMarkFilteringSet = 0x0010u, 550 Reserved = 0x00E0u, 551 MarkAttachmentType = 0xFF00u 552 }; 553 public: 554 DEFINE_SIZE_STATIC (2); 555}; 556 557struct Lookup 558{ 559 inline unsigned int get_subtable_count (void) const { return subTable.len; } 560 561 inline unsigned int get_type (void) const { return lookupType; } 562 563 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and 564 * higher 16-bit is mark-filtering-set if the lookup uses one. 565 * Not to be confused with glyph_props which is very similar. */ 566 inline uint32_t get_props (void) const 567 { 568 unsigned int flag = lookupFlag; 569 if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) 570 { 571 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 572 flag += (markFilteringSet << 16); 573 } 574 return flag; 575 } 576 577 inline bool serialize (hb_serialize_context_t *c, 578 unsigned int lookup_type, 579 uint32_t lookup_props, 580 unsigned int num_subtables) 581 { 582 TRACE_SERIALIZE (this); 583 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 584 lookupType.set (lookup_type); 585 lookupFlag.set (lookup_props & 0xFFFF); 586 if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false); 587 if (lookupFlag & LookupFlag::UseMarkFilteringSet) 588 { 589 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 590 markFilteringSet.set (lookup_props >> 16); 591 } 592 return TRACE_RETURN (true); 593 } 594 595 inline bool sanitize (hb_sanitize_context_t *c) { 596 TRACE_SANITIZE (this); 597 /* Real sanitize of the subtables is done by GSUB/GPOS/... */ 598 if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false); 599 if (lookupFlag & LookupFlag::UseMarkFilteringSet) 600 { 601 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 602 if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false); 603 } 604 return TRACE_RETURN (true); 605 } 606 607 USHORT lookupType; /* Different enumerations for GSUB and GPOS */ 608 USHORT lookupFlag; /* Lookup qualifiers */ 609 ArrayOf<Offset> 610 subTable; /* Array of SubTables */ 611 USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets 612 * structure. This field is only present if bit 613 * UseMarkFilteringSet of lookup flags is set. */ 614 public: 615 DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); 616}; 617 618typedef OffsetListOf<Lookup> LookupList; 619 620 621/* 622 * Coverage Table 623 */ 624 625struct CoverageFormat1 626{ 627 friend struct Coverage; 628 629 private: 630 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 631 { 632 int i = glyphArray.search (glyph_id); 633 ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED); 634 return i; 635 } 636 637 inline bool serialize (hb_serialize_context_t *c, 638 Supplier<GlyphID> &glyphs, 639 unsigned int num_glyphs) 640 { 641 TRACE_SERIALIZE (this); 642 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 643 glyphArray.len.set (num_glyphs); 644 if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false); 645 for (unsigned int i = 0; i < num_glyphs; i++) 646 glyphArray[i] = glyphs[i]; 647 glyphs.advance (num_glyphs); 648 return TRACE_RETURN (true); 649 } 650 651 inline bool sanitize (hb_sanitize_context_t *c) { 652 TRACE_SANITIZE (this); 653 return TRACE_RETURN (glyphArray.sanitize (c)); 654 } 655 656 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 657 return glyphs->has (glyphArray[index]); 658 } 659 660 template <typename set_t> 661 inline void add_coverage (set_t *glyphs) const { 662 unsigned int count = glyphArray.len; 663 for (unsigned int i = 0; i < count; i++) 664 glyphs->add (glyphArray[i]); 665 } 666 667 public: 668 /* Older compilers need this to be public. */ 669 struct Iter { 670 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; 671 inline bool more (void) { return i < c->glyphArray.len; } 672 inline void next (void) { i++; } 673 inline uint16_t get_glyph (void) { return c->glyphArray[i]; } 674 inline uint16_t get_coverage (void) { return i; } 675 676 private: 677 const struct CoverageFormat1 *c; 678 unsigned int i; 679 }; 680 private: 681 682 protected: 683 USHORT coverageFormat; /* Format identifier--format = 1 */ 684 SortedArrayOf<GlyphID> 685 glyphArray; /* Array of GlyphIDs--in numerical order */ 686 public: 687 DEFINE_SIZE_ARRAY (4, glyphArray); 688}; 689 690struct CoverageFormat2 691{ 692 friend struct Coverage; 693 694 private: 695 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 696 { 697 int i = rangeRecord.search (glyph_id); 698 if (i != -1) { 699 const RangeRecord &range = rangeRecord[i]; 700 return (unsigned int) range.value + (glyph_id - range.start); 701 } 702 return NOT_COVERED; 703 } 704 705 inline bool serialize (hb_serialize_context_t *c, 706 Supplier<GlyphID> &glyphs, 707 unsigned int num_glyphs) 708 { 709 TRACE_SERIALIZE (this); 710 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 711 712 if (unlikely (!num_glyphs)) return TRACE_RETURN (true); 713 714 unsigned int num_ranges = 1; 715 for (unsigned int i = 1; i < num_glyphs; i++) 716 if (glyphs[i - 1] + 1 != glyphs[i]) 717 num_ranges++; 718 rangeRecord.len.set (num_ranges); 719 if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false); 720 721 unsigned int range = 0; 722 rangeRecord[range].start = glyphs[0]; 723 rangeRecord[range].value.set (0); 724 for (unsigned int i = 1; i < num_glyphs; i++) 725 if (glyphs[i - 1] + 1 != glyphs[i]) { 726 range++; 727 rangeRecord[range].start = glyphs[i]; 728 rangeRecord[range].value.set (i); 729 rangeRecord[range].end = glyphs[i]; 730 } else { 731 rangeRecord[range].end = glyphs[i]; 732 } 733 glyphs.advance (num_glyphs); 734 return TRACE_RETURN (true); 735 } 736 737 inline bool sanitize (hb_sanitize_context_t *c) { 738 TRACE_SANITIZE (this); 739 return TRACE_RETURN (rangeRecord.sanitize (c)); 740 } 741 742 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 743 unsigned int i; 744 unsigned int count = rangeRecord.len; 745 for (i = 0; i < count; i++) { 746 const RangeRecord &range = rangeRecord[i]; 747 if (range.value <= index && 748 index < (unsigned int) range.value + (range.end - range.start) && 749 range.intersects (glyphs)) 750 return true; 751 else if (index < range.value) 752 return false; 753 } 754 return false; 755 } 756 757 template <typename set_t> 758 inline void add_coverage (set_t *glyphs) const { 759 unsigned int count = rangeRecord.len; 760 for (unsigned int i = 0; i < count; i++) 761 rangeRecord[i].add_coverage (glyphs); 762 } 763 764 public: 765 /* Older compilers need this to be public. */ 766 struct Iter { 767 inline void init (const CoverageFormat2 &c_) { 768 c = &c_; 769 coverage = 0; 770 i = 0; 771 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; 772 } 773 inline bool more (void) { return i < c->rangeRecord.len; } 774 inline void next (void) { 775 coverage++; 776 if (j == c->rangeRecord[i].end) { 777 i++; 778 if (more ()) 779 j = c->rangeRecord[i].start; 780 return; 781 } 782 j++; 783 } 784 inline uint16_t get_glyph (void) { return j; } 785 inline uint16_t get_coverage (void) { return coverage; } 786 787 private: 788 const struct CoverageFormat2 *c; 789 unsigned int i, j, coverage; 790 }; 791 private: 792 793 protected: 794 USHORT coverageFormat; /* Format identifier--format = 2 */ 795 SortedArrayOf<RangeRecord> 796 rangeRecord; /* Array of glyph ranges--ordered by 797 * Start GlyphID. rangeCount entries 798 * long */ 799 public: 800 DEFINE_SIZE_ARRAY (4, rangeRecord); 801}; 802 803struct Coverage 804{ 805 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 806 { 807 switch (u.format) { 808 case 1: return u.format1.get_coverage(glyph_id); 809 case 2: return u.format2.get_coverage(glyph_id); 810 default:return NOT_COVERED; 811 } 812 } 813 814 inline bool serialize (hb_serialize_context_t *c, 815 Supplier<GlyphID> &glyphs, 816 unsigned int num_glyphs) 817 { 818 TRACE_SERIALIZE (this); 819 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 820 unsigned int num_ranges = 1; 821 for (unsigned int i = 1; i < num_glyphs; i++) 822 if (glyphs[i - 1] + 1 != glyphs[i]) 823 num_ranges++; 824 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); 825 switch (u.format) { 826 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs)); 827 case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs)); 828 default:return TRACE_RETURN (false); 829 } 830 } 831 832 inline bool sanitize (hb_sanitize_context_t *c) { 833 TRACE_SANITIZE (this); 834 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 835 switch (u.format) { 836 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 837 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 838 default:return TRACE_RETURN (true); 839 } 840 } 841 842 inline bool intersects (const hb_set_t *glyphs) const { 843 /* TODO speed this up */ 844 Coverage::Iter iter; 845 for (iter.init (*this); iter.more (); iter.next ()) { 846 if (glyphs->has (iter.get_glyph ())) 847 return true; 848 } 849 return false; 850 } 851 852 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 853 switch (u.format) { 854 case 1: return u.format1.intersects_coverage (glyphs, index); 855 case 2: return u.format2.intersects_coverage (glyphs, index); 856 default:return false; 857 } 858 } 859 860 template <typename set_t> 861 inline void add_coverage (set_t *glyphs) const { 862 switch (u.format) { 863 case 1: u.format1.add_coverage (glyphs); break; 864 case 2: u.format2.add_coverage (glyphs); break; 865 default: break; 866 } 867 } 868 869 struct Iter { 870 Iter (void) : format (0) {}; 871 inline void init (const Coverage &c_) { 872 format = c_.u.format; 873 switch (format) { 874 case 1: u.format1.init (c_.u.format1); return; 875 case 2: u.format2.init (c_.u.format2); return; 876 default: return; 877 } 878 } 879 inline bool more (void) { 880 switch (format) { 881 case 1: return u.format1.more (); 882 case 2: return u.format2.more (); 883 default:return false; 884 } 885 } 886 inline void next (void) { 887 switch (format) { 888 case 1: u.format1.next (); break; 889 case 2: u.format2.next (); break; 890 default: break; 891 } 892 } 893 inline uint16_t get_glyph (void) { 894 switch (format) { 895 case 1: return u.format1.get_glyph (); 896 case 2: return u.format2.get_glyph (); 897 default:return 0; 898 } 899 } 900 inline uint16_t get_coverage (void) { 901 switch (format) { 902 case 1: return u.format1.get_coverage (); 903 case 2: return u.format2.get_coverage (); 904 default:return -1; 905 } 906 } 907 908 private: 909 unsigned int format; 910 union { 911 CoverageFormat1::Iter format1; 912 CoverageFormat2::Iter format2; 913 } u; 914 }; 915 916 protected: 917 union { 918 USHORT format; /* Format identifier */ 919 CoverageFormat1 format1; 920 CoverageFormat2 format2; 921 } u; 922 public: 923 DEFINE_SIZE_UNION (2, format); 924}; 925 926 927/* 928 * Class Definition Table 929 */ 930 931struct ClassDefFormat1 932{ 933 friend struct ClassDef; 934 935 private: 936 inline unsigned int get_class (hb_codepoint_t glyph_id) const 937 { 938 if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len)) 939 return classValue[glyph_id - startGlyph]; 940 return 0; 941 } 942 943 inline bool sanitize (hb_sanitize_context_t *c) { 944 TRACE_SANITIZE (this); 945 return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c)); 946 } 947 948 template <typename set_t> 949 inline void add_class (set_t *glyphs, unsigned int klass) const { 950 unsigned int count = classValue.len; 951 for (unsigned int i = 0; i < count; i++) 952 if (classValue[i] == klass) 953 glyphs->add (startGlyph + i); 954 } 955 956 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 957 unsigned int count = classValue.len; 958 if (klass == 0) 959 { 960 /* Match if there's any glyph that is not listed! */ 961 hb_codepoint_t g = -1; 962 if (!hb_set_next (glyphs, &g)) 963 return false; 964 if (g < startGlyph) 965 return true; 966 g = startGlyph + count - 1; 967 if (hb_set_next (glyphs, &g)) 968 return true; 969 /* Fall through. */ 970 } 971 for (unsigned int i = 0; i < count; i++) 972 if (classValue[i] == klass && glyphs->has (startGlyph + i)) 973 return true; 974 return false; 975 } 976 977 protected: 978 USHORT classFormat; /* Format identifier--format = 1 */ 979 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 980 ArrayOf<USHORT> 981 classValue; /* Array of Class Values--one per GlyphID */ 982 public: 983 DEFINE_SIZE_ARRAY (6, classValue); 984}; 985 986struct ClassDefFormat2 987{ 988 friend struct ClassDef; 989 990 private: 991 inline unsigned int get_class (hb_codepoint_t glyph_id) const 992 { 993 int i = rangeRecord.search (glyph_id); 994 if (i != -1) 995 return rangeRecord[i].value; 996 return 0; 997 } 998 999 inline bool sanitize (hb_sanitize_context_t *c) { 1000 TRACE_SANITIZE (this); 1001 return TRACE_RETURN (rangeRecord.sanitize (c)); 1002 } 1003 1004 template <typename set_t> 1005 inline void add_class (set_t *glyphs, unsigned int klass) const { 1006 unsigned int count = rangeRecord.len; 1007 for (unsigned int i = 0; i < count; i++) 1008 if (rangeRecord[i].value == klass) 1009 rangeRecord[i].add_coverage (glyphs); 1010 } 1011 1012 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1013 unsigned int count = rangeRecord.len; 1014 if (klass == 0) 1015 { 1016 /* Match if there's any glyph that is not listed! */ 1017 hb_codepoint_t g = -1; 1018 for (unsigned int i = 0; i < count; i++) 1019 { 1020 if (!hb_set_next (glyphs, &g)) 1021 break; 1022 if (g < rangeRecord[i].start) 1023 return true; 1024 g = rangeRecord[i].end; 1025 } 1026 if (g != -1 && hb_set_next (glyphs, &g)) 1027 return true; 1028 /* Fall through. */ 1029 } 1030 for (unsigned int i = 0; i < count; i++) 1031 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) 1032 return true; 1033 return false; 1034 } 1035 1036 protected: 1037 USHORT classFormat; /* Format identifier--format = 2 */ 1038 SortedArrayOf<RangeRecord> 1039 rangeRecord; /* Array of glyph ranges--ordered by 1040 * Start GlyphID */ 1041 public: 1042 DEFINE_SIZE_ARRAY (4, rangeRecord); 1043}; 1044 1045struct ClassDef 1046{ 1047 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1048 { 1049 switch (u.format) { 1050 case 1: return u.format1.get_class(glyph_id); 1051 case 2: return u.format2.get_class(glyph_id); 1052 default:return 0; 1053 } 1054 } 1055 1056 inline bool sanitize (hb_sanitize_context_t *c) { 1057 TRACE_SANITIZE (this); 1058 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1059 switch (u.format) { 1060 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1061 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1062 default:return TRACE_RETURN (true); 1063 } 1064 } 1065 1066 inline void add_class (hb_set_t *glyphs, unsigned int klass) const { 1067 switch (u.format) { 1068 case 1: u.format1.add_class (glyphs, klass); return; 1069 case 2: u.format2.add_class (glyphs, klass); return; 1070 default:return; 1071 } 1072 } 1073 1074 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1075 switch (u.format) { 1076 case 1: return u.format1.intersects_class (glyphs, klass); 1077 case 2: return u.format2.intersects_class (glyphs, klass); 1078 default:return false; 1079 } 1080 } 1081 1082 protected: 1083 union { 1084 USHORT format; /* Format identifier */ 1085 ClassDefFormat1 format1; 1086 ClassDefFormat2 format2; 1087 } u; 1088 public: 1089 DEFINE_SIZE_UNION (2, format); 1090}; 1091 1092 1093/* 1094 * Device Tables 1095 */ 1096 1097struct Device 1098{ 1099 1100 inline hb_position_t get_x_delta (hb_font_t *font) const 1101 { return get_delta (font->x_ppem, font->x_scale); } 1102 1103 inline hb_position_t get_y_delta (hb_font_t *font) const 1104 { return get_delta (font->y_ppem, font->y_scale); } 1105 1106 inline int get_delta (unsigned int ppem, int scale) const 1107 { 1108 if (!ppem) return 0; 1109 1110 int pixels = get_delta_pixels (ppem); 1111 1112 if (!pixels) return 0; 1113 1114 return pixels * (int64_t) scale / ppem; 1115 } 1116 1117 1118 inline int get_delta_pixels (unsigned int ppem_size) const 1119 { 1120 unsigned int f = deltaFormat; 1121 if (unlikely (f < 1 || f > 3)) 1122 return 0; 1123 1124 if (ppem_size < startSize || ppem_size > endSize) 1125 return 0; 1126 1127 unsigned int s = ppem_size - startSize; 1128 1129 unsigned int byte = deltaValue[s >> (4 - f)]; 1130 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 1131 unsigned int mask = (0xFFFF >> (16 - (1 << f))); 1132 1133 int delta = bits & mask; 1134 1135 if ((unsigned int) delta >= ((mask + 1) >> 1)) 1136 delta -= mask + 1; 1137 1138 return delta; 1139 } 1140 1141 inline unsigned int get_size (void) const 1142 { 1143 unsigned int f = deltaFormat; 1144 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; 1145 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); 1146 } 1147 1148 inline bool sanitize (hb_sanitize_context_t *c) { 1149 TRACE_SANITIZE (this); 1150 return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ())); 1151 } 1152 1153 protected: 1154 USHORT startSize; /* Smallest size to correct--in ppem */ 1155 USHORT endSize; /* Largest size to correct--in ppem */ 1156 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 1157 * 1 Signed 2-bit value, 8 values per uint16 1158 * 2 Signed 4-bit value, 4 values per uint16 1159 * 3 Signed 8-bit value, 2 values per uint16 1160 */ 1161 USHORT deltaValue[VAR]; /* Array of compressed data */ 1162 public: 1163 DEFINE_SIZE_ARRAY (6, deltaValue); 1164}; 1165 1166 1167} /* namespace OT */ 1168 1169 1170#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 1171