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