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 (at) 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)) return_trace (true); 774 775 unsigned int num_ranges = 1; 776 for (unsigned int i = 1; i < num_glyphs; i++) 777 if (glyphs[i - 1] + 1 != glyphs[i]) 778 num_ranges++; 779 rangeRecord.len.set (num_ranges); 780 if (unlikely (!c->extend (rangeRecord))) return_trace (false); 781 782 unsigned int range = 0; 783 rangeRecord[range].start = glyphs[0]; 784 rangeRecord[range].value.set (0); 785 for (unsigned int i = 1; i < num_glyphs; i++) 786 if (glyphs[i - 1] + 1 != glyphs[i]) { 787 range++; 788 rangeRecord[range].start = glyphs[i]; 789 rangeRecord[range].value.set (i); 790 rangeRecord[range].end = glyphs[i]; 791 } else { 792 rangeRecord[range].end = glyphs[i]; 793 } 794 glyphs.advance (num_glyphs); 795 return_trace (true); 796 } 797 798 inline bool sanitize (hb_sanitize_context_t *c) const 799 { 800 TRACE_SANITIZE (this); 801 return_trace (rangeRecord.sanitize (c)); 802 } 803 804 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 805 unsigned int i; 806 unsigned int count = rangeRecord.len; 807 for (i = 0; i < count; i++) { 808 const RangeRecord &range = rangeRecord[i]; 809 if (range.value <= index && 810 index < (unsigned int) range.value + (range.end - range.start) && 811 range.intersects (glyphs)) 812 return true; 813 else if (index < range.value) 814 return false; 815 } 816 return false; 817 } 818 819 template <typename set_t> 820 inline void add_coverage (set_t *glyphs) const { 821 unsigned int count = rangeRecord.len; 822 for (unsigned int i = 0; i < count; i++) 823 rangeRecord[i].add_coverage (glyphs); 824 } 825 826 public: 827 /* Older compilers need this to be public. */ 828 struct Iter { 829 inline void init (const CoverageFormat2 &c_) { 830 c = &c_; 831 coverage = 0; 832 i = 0; 833 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; 834 } 835 inline bool more (void) { return i < c->rangeRecord.len; } 836 inline void next (void) { 837 coverage++; 838 if (j == c->rangeRecord[i].end) { 839 i++; 840 if (more ()) 841 j = c->rangeRecord[i].start; 842 return; 843 } 844 j++; 845 } 846 inline uint16_t get_glyph (void) { return j; } 847 inline uint16_t get_coverage (void) { return coverage; } 848 849 private: 850 const struct CoverageFormat2 *c; 851 unsigned int i, j, coverage; 852 }; 853 private: 854 855 protected: 856 USHORT coverageFormat; /* Format identifier--format = 2 */ 857 SortedArrayOf<RangeRecord> 858 rangeRecord; /* Array of glyph ranges--ordered by 859 * Start GlyphID. rangeCount entries 860 * long */ 861 public: 862 DEFINE_SIZE_ARRAY (4, rangeRecord); 863 }; 864 865 struct Coverage 866 { 867 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 868 { 869 switch (u.format) { 870 case 1: return u.format1.get_coverage(glyph_id); 871 case 2: return u.format2.get_coverage(glyph_id); 872 default:return NOT_COVERED; 873 } 874 } 875 876 inline bool serialize (hb_serialize_context_t *c, 877 Supplier<GlyphID> &glyphs, 878 unsigned int num_glyphs) 879 { 880 TRACE_SERIALIZE (this); 881 if (unlikely (!c->extend_min (*this))) return_trace (false); 882 unsigned int num_ranges = 1; 883 for (unsigned int i = 1; i < num_glyphs; i++) 884 if (glyphs[i - 1] + 1 != glyphs[i]) 885 num_ranges++; 886 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); 887 switch (u.format) { 888 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); 889 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); 890 default:return_trace (false); 891 } 892 } 893 894 inline bool sanitize (hb_sanitize_context_t *c) const 895 { 896 TRACE_SANITIZE (this); 897 if (!u.format.sanitize (c)) return_trace (false); 898 switch (u.format) { 899 case 1: return_trace (u.format1.sanitize (c)); 900 case 2: return_trace (u.format2.sanitize (c)); 901 default:return_trace (true); 902 } 903 } 904 905 inline bool intersects (const hb_set_t *glyphs) const { 906 /* TODO speed this up */ 907 Coverage::Iter iter; 908 for (iter.init (*this); iter.more (); iter.next ()) { 909 if (glyphs->has (iter.get_glyph ())) 910 return true; 911 } 912 return false; 913 } 914 915 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 916 switch (u.format) { 917 case 1: return u.format1.intersects_coverage (glyphs, index); 918 case 2: return u.format2.intersects_coverage (glyphs, index); 919 default:return false; 920 } 921 } 922 923 template <typename set_t> 924 inline void add_coverage (set_t *glyphs) const { 925 switch (u.format) { 926 case 1: u.format1.add_coverage (glyphs); break; 927 case 2: u.format2.add_coverage (glyphs); break; 928 default: break; 929 } 930 } 931 932 struct Iter { 933 Iter (void) : format (0) {}; 934 inline void init (const Coverage &c_) { 935 format = c_.u.format; 936 switch (format) { 937 case 1: u.format1.init (c_.u.format1); return; 938 case 2: u.format2.init (c_.u.format2); return; 939 default: return; 940 } 941 } 942 inline bool more (void) { 943 switch (format) { 944 case 1: return u.format1.more (); 945 case 2: return u.format2.more (); 946 default:return false; 947 } 948 } 949 inline void next (void) { 950 switch (format) { 951 case 1: u.format1.next (); break; 952 case 2: u.format2.next (); break; 953 default: break; 954 } 955 } 956 inline uint16_t get_glyph (void) { 957 switch (format) { 958 case 1: return u.format1.get_glyph (); 959 case 2: return u.format2.get_glyph (); 960 default:return 0; 961 } 962 } 963 inline uint16_t get_coverage (void) { 964 switch (format) { 965 case 1: return u.format1.get_coverage (); 966 case 2: return u.format2.get_coverage (); 967 default:return -1; 968 } 969 } 970 971 private: 972 unsigned int format; 973 union { 974 CoverageFormat1::Iter format1; 975 CoverageFormat2::Iter format2; 976 } u; 977 }; 978 979 protected: 980 union { 981 USHORT format; /* Format identifier */ 982 CoverageFormat1 format1; 983 CoverageFormat2 format2; 984 } u; 985 public: 986 DEFINE_SIZE_UNION (2, format); 987 }; 988 989 990 /* 991 * Class Definition Table 992 */ 993 994 struct ClassDefFormat1 995 { 996 friend struct ClassDef; 997 998 private: 999 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1000 { 1001 unsigned int i = (unsigned int) (glyph_id - startGlyph); 1002 if (unlikely (i < classValue.len)) 1003 return classValue[i]; 1004 return 0; 1005 } 1006 1007 inline bool sanitize (hb_sanitize_context_t *c) const 1008 { 1009 TRACE_SANITIZE (this); 1010 return_trace (c->check_struct (this) && classValue.sanitize (c)); 1011 } 1012 1013 template <typename set_t> 1014 inline void add_class (set_t *glyphs, unsigned int klass) const { 1015 unsigned int count = classValue.len; 1016 for (unsigned int i = 0; i < count; i++) 1017 if (classValue[i] == klass) 1018 glyphs->add (startGlyph + i); 1019 } 1020 1021 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1022 unsigned int count = classValue.len; 1023 if (klass == 0) 1024 { 1025 /* Match if there's any glyph that is not listed! */ 1026 hb_codepoint_t g = -1; 1027 if (!hb_set_next (glyphs, &g)) 1028 return false; 1029 if (g < startGlyph) 1030 return true; 1031 g = startGlyph + count - 1; 1032 if (hb_set_next (glyphs, &g)) 1033 return true; 1034 /* Fall through. */ 1035 } 1036 for (unsigned int i = 0; i < count; i++) 1037 if (classValue[i] == klass && glyphs->has (startGlyph + i)) 1038 return true; 1039 return false; 1040 } 1041 1042 protected: 1043 USHORT classFormat; /* Format identifier--format = 1 */ 1044 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 1045 ArrayOf<USHORT> 1046 classValue; /* Array of Class Values--one per GlyphID */ 1047 public: 1048 DEFINE_SIZE_ARRAY (6, classValue); 1049 }; 1050 1051 struct ClassDefFormat2 1052 { 1053 friend struct ClassDef; 1054 1055 private: 1056 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1057 { 1058 int i = rangeRecord.bsearch (glyph_id); 1059 if (unlikely (i != -1)) 1060 return rangeRecord[i].value; 1061 return 0; 1062 } 1063 1064 inline bool sanitize (hb_sanitize_context_t *c) const 1065 { 1066 TRACE_SANITIZE (this); 1067 return_trace (rangeRecord.sanitize (c)); 1068 } 1069 1070 template <typename set_t> 1071 inline void add_class (set_t *glyphs, unsigned int klass) const { 1072 unsigned int count = rangeRecord.len; 1073 for (unsigned int i = 0; i < count; i++) 1074 if (rangeRecord[i].value == klass) 1075 rangeRecord[i].add_coverage (glyphs); 1076 } 1077 1078 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1079 unsigned int count = rangeRecord.len; 1080 if (klass == 0) 1081 { 1082 /* Match if there's any glyph that is not listed! */ 1083 hb_codepoint_t g = (hb_codepoint_t) -1; 1084 for (unsigned int i = 0; i < count; i++) 1085 { 1086 if (!hb_set_next (glyphs, &g)) 1087 break; 1088 if (g < rangeRecord[i].start) 1089 return true; 1090 g = rangeRecord[i].end; 1091 } 1092 if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g)) 1093 return true; 1094 /* Fall through. */ 1095 } 1096 for (unsigned int i = 0; i < count; i++) 1097 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) 1098 return true; 1099 return false; 1100 } 1101 1102 protected: 1103 USHORT classFormat; /* Format identifier--format = 2 */ 1104 SortedArrayOf<RangeRecord> 1105 rangeRecord; /* Array of glyph ranges--ordered by 1106 * Start GlyphID */ 1107 public: 1108 DEFINE_SIZE_ARRAY (4, rangeRecord); 1109 }; 1110 1111 struct ClassDef 1112 { 1113 inline unsigned int get_class (hb_codepoint_t glyph_id) const 1114 { 1115 switch (u.format) { 1116 case 1: return u.format1.get_class(glyph_id); 1117 case 2: return u.format2.get_class(glyph_id); 1118 default:return 0; 1119 } 1120 } 1121 1122 inline bool sanitize (hb_sanitize_context_t *c) const 1123 { 1124 TRACE_SANITIZE (this); 1125 if (!u.format.sanitize (c)) return_trace (false); 1126 switch (u.format) { 1127 case 1: return_trace (u.format1.sanitize (c)); 1128 case 2: return_trace (u.format2.sanitize (c)); 1129 default:return_trace (true); 1130 } 1131 } 1132 1133 inline void add_class (hb_set_t *glyphs, unsigned int klass) const { 1134 switch (u.format) { 1135 case 1: u.format1.add_class (glyphs, klass); return; 1136 case 2: u.format2.add_class (glyphs, klass); return; 1137 default:return; 1138 } 1139 } 1140 1141 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1142 switch (u.format) { 1143 case 1: return u.format1.intersects_class (glyphs, klass); 1144 case 2: return u.format2.intersects_class (glyphs, klass); 1145 default:return false; 1146 } 1147 } 1148 1149 protected: 1150 union { 1151 USHORT format; /* Format identifier */ 1152 ClassDefFormat1 format1; 1153 ClassDefFormat2 format2; 1154 } u; 1155 public: 1156 DEFINE_SIZE_UNION (2, format); 1157 }; 1158 1159 1160 /* 1161 * Device Tables 1162 */ 1163 1164 struct Device 1165 { 1166 1167 inline hb_position_t get_x_delta (hb_font_t *font) const 1168 { return get_delta (font->x_ppem, font->x_scale); } 1169 1170 inline hb_position_t get_y_delta (hb_font_t *font) const 1171 { return get_delta (font->y_ppem, font->y_scale); } 1172 1173 inline unsigned int get_size (void) const 1174 { 1175 unsigned int f = deltaFormat; 1176 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; 1177 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); 1178 } 1179 1180 inline bool sanitize (hb_sanitize_context_t *c) const 1181 { 1182 TRACE_SANITIZE (this); 1183 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); 1184 } 1185 1186 private: 1187 1188 inline int get_delta (unsigned int ppem, int scale) const 1189 { 1190 if (!ppem) return 0; 1191 1192 int pixels = get_delta_pixels (ppem); 1193 1194 if (!pixels) return 0; 1195 1196 return (int) (pixels * (int64_t) scale / ppem); 1197 } 1198 inline int get_delta_pixels (unsigned int ppem_size) const 1199 { 1200 unsigned int f = deltaFormat; 1201 if (unlikely (f < 1 || f > 3)) 1202 return 0; 1203 1204 if (ppem_size < startSize || ppem_size > endSize) 1205 return 0; 1206 1207 unsigned int s = ppem_size - startSize; 1208 1209 unsigned int byte = deltaValue[s >> (4 - f)]; 1210 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 1211 unsigned int mask = (0xFFFFu >> (16 - (1 << f))); 1212 1213 int delta = bits & mask; 1214 1215 if ((unsigned int) delta >= ((mask + 1) >> 1)) 1216 delta -= mask + 1; 1217 1218 return delta; 1219 } 1220 1221 protected: 1222 USHORT startSize; /* Smallest size to correct--in ppem */ 1223 USHORT endSize; /* Largest size to correct--in ppem */ 1224 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 1225 * 1 Signed 2-bit value, 8 values per uint16 1226 * 2 Signed 4-bit value, 4 values per uint16 1227 * 3 Signed 8-bit value, 2 values per uint16 1228 */ 1229 USHORT deltaValue[VAR]; /* Array of compressed data */ 1230 public: 1231 DEFINE_SIZE_ARRAY (6, deltaValue); 1232 }; 1233 1234 1235 } /* namespace OT */ 1236 1237 1238 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 1239