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