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