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