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