hb-ot-layout-common-private.hh revision e5546a4352c54311ac4a9ef138b187378155ebe1
1/* 2 * Copyright (C) 2007,2008,2009 Red Hat, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Red Hat Author(s): Behdad Esfahbod 25 */ 26 27#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH 28#define HB_OT_LAYOUT_COMMON_PRIVATE_HH 29 30#include "hb-ot-layout-private.h" 31 32#include "hb-open-type-private.hh" 33 34 35#define NO_CONTEXT ((unsigned int) 0x110000) 36#define NOT_COVERED ((unsigned int) 0x110000) 37#define MAX_NESTING_LEVEL 8 38 39 40/* 41 * 42 * OpenType Layout Common Table Formats 43 * 44 */ 45 46 47/* 48 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList 49 */ 50 51template <typename Type> 52struct Record 53{ 54 static inline unsigned int get_size () { return sizeof (Record<Type>); } 55 56 inline bool sanitize (SANITIZE_ARG_DEF, void *base) { 57 TRACE_SANITIZE (); 58 return SANITIZE (tag) && SANITIZE_BASE (offset, base); 59 } 60 61 Tag tag; /* 4-byte Tag identifier */ 62 OffsetTo<Type> 63 offset; /* Offset from beginning of object holding 64 * the Record */ 65}; 66 67template <typename Type> 68struct RecordArrayOf : ArrayOf<Record<Type> > { 69 inline const Tag& get_tag (unsigned int i) const 70 { 71 if (HB_UNLIKELY (i >= this->len)) return Null(Tag); 72 return (*this)[i].tag; 73 } 74 inline unsigned int get_tags (unsigned int start_offset, 75 unsigned int *record_count /* IN/OUT */, 76 hb_tag_t *record_tags /* OUT */) const 77 { 78 if (record_count) { 79 const Record<Type> *array = this->sub_array (start_offset, record_count); 80 unsigned int count = *record_count; 81 for (unsigned int i = 0; i < count; i++) 82 record_tags[i] = array[i].tag; 83 } 84 return this->len; 85 } 86 inline bool find_index (hb_tag_t tag, unsigned int *index) const 87 { 88 Tag t; 89 t.set (tag); 90 // TODO bsearch 91 const Record<Type> *a = this->array(); 92 unsigned int count = this->len; 93 for (unsigned int i = 0; i < count; i++) 94 { 95 if (t == a[i].tag) 96 { 97 if (index) *index = i; 98 return true; 99 } 100 } 101 if (index) *index = NO_INDEX; 102 return false; 103 } 104}; 105 106template <typename Type> 107struct RecordListOf : RecordArrayOf<Type> 108{ 109 inline const Type& operator [] (unsigned int i) const 110 { return this+RecordArrayOf<Type>::operator [](i).offset; } 111 112 inline bool sanitize (SANITIZE_ARG_DEF) { 113 TRACE_SANITIZE (); 114 return RecordArrayOf<Type>::sanitize (SANITIZE_ARG, CharP(this)); 115 } 116}; 117 118 119struct IndexArray : ArrayOf<USHORT> 120{ 121 inline unsigned int operator [] (unsigned int i) const 122 { 123 if (HB_UNLIKELY (i >= this->len)) 124 return NO_INDEX; 125 return this->array()[i]; 126 } 127 inline unsigned int get_indexes (unsigned int start_offset, 128 unsigned int *_count /* IN/OUT */, 129 unsigned int *_indexes /* OUT */) const 130 { 131 if (_count) { 132 const USHORT *array = this->sub_array (start_offset, _count); 133 unsigned int count = *_count; 134 for (unsigned int i = 0; i < count; i++) 135 _indexes[i] = array[i]; 136 } 137 return this->len; 138 } 139}; 140 141 142struct Script; 143struct LangSys; 144struct Feature; 145 146 147struct LangSys 148{ 149 inline unsigned int get_feature_count (void) const 150 { return featureIndex.len; } 151 inline hb_tag_t get_feature_index (unsigned int i) const 152 { return featureIndex[i]; } 153 inline unsigned int get_feature_indexes (unsigned int start_offset, 154 unsigned int *feature_count /* IN/OUT */, 155 unsigned int *feature_indexes /* OUT */) const 156 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } 157 158 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; } 159 inline int get_required_feature_index (void) const 160 { 161 if (reqFeatureIndex == 0xffff) 162 return NO_INDEX; 163 return reqFeatureIndex;; 164 } 165 166 inline bool sanitize (SANITIZE_ARG_DEF) { 167 TRACE_SANITIZE (); 168 return SANITIZE_SELF () && SANITIZE (featureIndex); 169 } 170 171 Offset lookupOrder; /* = Null (reserved for an offset to a 172 * reordering table) */ 173 USHORT reqFeatureIndex;/* Index of a feature required for this 174 * language system--if no required features 175 * = 0xFFFF */ 176 IndexArray featureIndex; /* Array of indices into the FeatureList */ 177}; 178ASSERT_SIZE (LangSys, 6); 179DEFINE_NULL_DATA (LangSys, 6, "\0\0\xFF\xFF"); 180 181 182struct Script 183{ 184 inline unsigned int get_lang_sys_count (void) const 185 { return langSys.len; } 186 inline const Tag& get_lang_sys_tag (unsigned int i) const 187 { return langSys.get_tag (i); } 188 inline unsigned int get_lang_sys_tags (unsigned int start_offset, 189 unsigned int *lang_sys_count /* IN/OUT */, 190 hb_tag_t *lang_sys_tags /* OUT */) const 191 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } 192 inline const LangSys& get_lang_sys (unsigned int i) const 193 { 194 if (i == NO_INDEX) return get_default_lang_sys (); 195 return this+langSys[i].offset; 196 } 197 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const 198 { return langSys.find_index (tag, index); } 199 200 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } 201 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } 202 203 inline bool sanitize (SANITIZE_ARG_DEF) { 204 TRACE_SANITIZE (); 205 return SANITIZE_THIS (defaultLangSys) && SANITIZE_THIS (langSys); 206 } 207 208 private: 209 OffsetTo<LangSys> 210 defaultLangSys; /* Offset to DefaultLangSys table--from 211 * beginning of Script table--may be Null */ 212 RecordArrayOf<LangSys> 213 langSys; /* Array of LangSysRecords--listed 214 * alphabetically by LangSysTag */ 215}; 216ASSERT_SIZE (Script, 4); 217 218typedef RecordListOf<Script> ScriptList; 219ASSERT_SIZE (ScriptList, 2); 220 221 222struct Feature 223{ 224 inline unsigned int get_lookup_count (void) const 225 { return lookupIndex.len; } 226 inline hb_tag_t get_lookup_index (unsigned int i) const 227 { return lookupIndex[i]; } 228 inline unsigned int get_lookup_indexes (unsigned int start_index, 229 unsigned int *lookup_count /* IN/OUT */, 230 unsigned int *lookup_tags /* OUT */) const 231 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } 232 233 inline bool sanitize (SANITIZE_ARG_DEF) { 234 TRACE_SANITIZE (); 235 return SANITIZE_SELF () && SANITIZE (lookupIndex); 236 } 237 238 /* TODO: implement get_feature_parameters() */ 239 /* TODO: implement FeatureSize and other special features? */ 240 Offset featureParams; /* Offset to Feature Parameters table (if one 241 * has been defined for the feature), relative 242 * to the beginning of the Feature Table; = Null 243 * if not required */ 244 IndexArray lookupIndex; /* Array of LookupList indices */ 245}; 246ASSERT_SIZE (Feature, 4); 247 248typedef RecordListOf<Feature> FeatureList; 249ASSERT_SIZE (FeatureList, 2); 250 251 252struct LookupFlag : USHORT 253{ 254 enum { 255 RightToLeft = 0x0001u, 256 IgnoreBaseGlyphs = 0x0002u, 257 IgnoreLigatures = 0x0004u, 258 IgnoreMarks = 0x0008u, 259 IgnoreFlags = 0x000Eu, 260 UseMarkFilteringSet = 0x0010u, 261 Reserved = 0x00E0u, 262 MarkAttachmentType = 0xFF00u 263 }; 264}; 265ASSERT_SIZE (LookupFlag, 2); 266 267struct LookupSubTable 268{ 269 inline bool sanitize (SANITIZE_ARG_DEF) { 270 TRACE_SANITIZE (); 271 return SANITIZE_SELF (); 272 } 273 274 private: 275 USHORT format; /* Subtable format. Different for GSUB and GPOS */ 276}; 277ASSERT_SIZE (LookupSubTable, 2); 278 279struct Lookup 280{ 281 inline const LookupSubTable& get_subtable (unsigned int i) const { return this+subTable[i]; } 282 inline unsigned int get_subtable_count (void) const { return subTable.len; } 283 284 inline unsigned int get_type (void) const { return lookupType; } 285 inline unsigned int get_flag (void) const 286 { 287 unsigned int flag = lookupFlag; 288 if (HB_UNLIKELY (flag & LookupFlag::UseMarkFilteringSet)) 289 { 290 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 291 flag += (markFilteringSet << 16); 292 } 293 return flag; 294 } 295 296 inline bool sanitize (SANITIZE_ARG_DEF) { 297 TRACE_SANITIZE (); 298 if (!(SANITIZE_SELF () && SANITIZE_THIS (subTable))) return false; 299 if (HB_UNLIKELY (lookupFlag & LookupFlag::UseMarkFilteringSet)) 300 { 301 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 302 if (!SANITIZE (markFilteringSet)) return false; 303 } 304 return true; 305 } 306 307 USHORT lookupType; /* Different enumerations for GSUB and GPOS */ 308 USHORT lookupFlag; /* Lookup qualifiers */ 309 OffsetArrayOf<LookupSubTable> 310 subTable; /* Array of SubTables */ 311 USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets 312 * structure. This field is only present if bit 313 * UseMarkFilteringSet of lookup flags is set. */ 314}; 315ASSERT_SIZE_VAR (Lookup, 6, USHORT); 316 317typedef OffsetListOf<Lookup> LookupList; 318ASSERT_SIZE (LookupList, 2); 319 320 321/* 322 * Coverage Table 323 */ 324 325struct CoverageFormat1 326{ 327 friend struct Coverage; 328 329 private: 330 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 331 { 332 if (HB_UNLIKELY (glyph_id > 0xFFFF)) 333 return NOT_COVERED; 334 GlyphID gid; 335 gid.set (glyph_id); 336 // TODO: bsearch 337 unsigned int num_glyphs = glyphArray.len; 338 for (unsigned int i = 0; i < num_glyphs; i++) 339 if (gid == glyphArray[i]) 340 return i; 341 return NOT_COVERED; 342 } 343 344 inline bool sanitize (SANITIZE_ARG_DEF) { 345 TRACE_SANITIZE (); 346 return SANITIZE (glyphArray); 347 } 348 349 private: 350 USHORT coverageFormat; /* Format identifier--format = 1 */ 351 ArrayOf<GlyphID> 352 glyphArray; /* Array of GlyphIDs--in numerical order */ 353}; 354ASSERT_SIZE (CoverageFormat1, 4); 355 356struct CoverageRangeRecord 357{ 358 friend struct CoverageFormat2; 359 360 static inline unsigned int get_size () { return sizeof (CoverageRangeRecord); } 361 362 private: 363 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 364 { 365 if (glyph_id >= start && glyph_id <= end) 366 return (unsigned int) startCoverageIndex + (glyph_id - start); 367 return NOT_COVERED; 368 } 369 370 public: 371 inline bool sanitize (SANITIZE_ARG_DEF) { 372 TRACE_SANITIZE (); 373 return SANITIZE_SELF (); 374 } 375 376 private: 377 GlyphID start; /* First GlyphID in the range */ 378 GlyphID end; /* Last GlyphID in the range */ 379 USHORT startCoverageIndex; /* Coverage Index of first GlyphID in 380 * range */ 381}; 382ASSERT_SIZE (CoverageRangeRecord, 6); 383DEFINE_NULL_DATA (CoverageRangeRecord, 6, "\000\001"); 384 385struct CoverageFormat2 386{ 387 friend struct Coverage; 388 389 private: 390 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 391 { 392 // TODO: bsearch 393 unsigned int count = rangeRecord.len; 394 for (unsigned int i = 0; i < count; i++) 395 { 396 unsigned int coverage = rangeRecord[i].get_coverage (glyph_id); 397 if (coverage != NOT_COVERED) 398 return coverage; 399 } 400 return NOT_COVERED; 401 } 402 403 inline bool sanitize (SANITIZE_ARG_DEF) { 404 TRACE_SANITIZE (); 405 return SANITIZE (rangeRecord); 406 } 407 408 private: 409 USHORT coverageFormat; /* Format identifier--format = 2 */ 410 ArrayOf<CoverageRangeRecord> 411 rangeRecord; /* Array of glyph ranges--ordered by 412 * Start GlyphID. rangeCount entries 413 * long */ 414}; 415ASSERT_SIZE (CoverageFormat2, 4); 416 417struct Coverage 418{ 419 inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); } 420 421 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 422 { 423 switch (u.format) { 424 case 1: return u.format1->get_coverage(glyph_id); 425 case 2: return u.format2->get_coverage(glyph_id); 426 default:return NOT_COVERED; 427 } 428 } 429 430 inline bool sanitize (SANITIZE_ARG_DEF) { 431 TRACE_SANITIZE (); 432 if (!SANITIZE (u.format)) return false; 433 switch (u.format) { 434 case 1: return u.format1->sanitize (SANITIZE_ARG); 435 case 2: return u.format2->sanitize (SANITIZE_ARG); 436 default:return true; 437 } 438 } 439 440 private: 441 union { 442 USHORT format; /* Format identifier */ 443 CoverageFormat1 format1[VAR]; 444 CoverageFormat2 format2[VAR]; 445 } u; 446}; 447 448 449/* 450 * Class Definition Table 451 */ 452 453struct ClassDefFormat1 454{ 455 friend struct ClassDef; 456 457 private: 458 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 459 { 460 if ((unsigned int) (glyph_id - startGlyph) < classValue.len) 461 return classValue[glyph_id - startGlyph]; 462 return 0; 463 } 464 465 inline bool sanitize (SANITIZE_ARG_DEF) { 466 TRACE_SANITIZE (); 467 return SANITIZE_SELF () && SANITIZE (classValue); 468 } 469 470 USHORT classFormat; /* Format identifier--format = 1 */ 471 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 472 ArrayOf<USHORT> 473 classValue; /* Array of Class Values--one per GlyphID */ 474}; 475ASSERT_SIZE (ClassDefFormat1, 6); 476 477struct ClassRangeRecord 478{ 479 friend struct ClassDefFormat2; 480 481 static inline unsigned int get_size () { return sizeof (ClassRangeRecord); } 482 483 private: 484 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 485 { 486 if (glyph_id >= start && glyph_id <= end) 487 return classValue; 488 return 0; 489 } 490 491 public: 492 inline bool sanitize (SANITIZE_ARG_DEF) { 493 TRACE_SANITIZE (); 494 return SANITIZE_SELF (); 495 } 496 497 private: 498 GlyphID start; /* First GlyphID in the range */ 499 GlyphID end; /* Last GlyphID in the range */ 500 USHORT classValue; /* Applied to all glyphs in the range */ 501}; 502ASSERT_SIZE (ClassRangeRecord, 6); 503DEFINE_NULL_DATA (ClassRangeRecord, 6, "\000\001"); 504 505struct ClassDefFormat2 506{ 507 friend struct ClassDef; 508 509 private: 510 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 511 { 512 // TODO: bsearch 513 unsigned int count = rangeRecord.len; 514 for (unsigned int i = 0; i < count; i++) 515 { 516 int classValue = rangeRecord[i].get_class (glyph_id); 517 if (classValue > 0) 518 return classValue; 519 } 520 return 0; 521 } 522 523 inline bool sanitize (SANITIZE_ARG_DEF) { 524 TRACE_SANITIZE (); 525 return SANITIZE (rangeRecord); 526 } 527 528 USHORT classFormat; /* Format identifier--format = 2 */ 529 ArrayOf<ClassRangeRecord> 530 rangeRecord; /* Array of glyph ranges--ordered by 531 * Start GlyphID */ 532}; 533ASSERT_SIZE (ClassDefFormat2, 4); 534 535struct ClassDef 536{ 537 inline hb_ot_layout_class_t operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); } 538 539 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 540 { 541 switch (u.format) { 542 case 1: return u.format1->get_class(glyph_id); 543 case 2: return u.format2->get_class(glyph_id); 544 default:return 0; 545 } 546 } 547 548 inline bool sanitize (SANITIZE_ARG_DEF) { 549 TRACE_SANITIZE (); 550 if (!SANITIZE (u.format)) return false; 551 switch (u.format) { 552 case 1: return u.format1->sanitize (SANITIZE_ARG); 553 case 2: return u.format2->sanitize (SANITIZE_ARG); 554 default:return true; 555 } 556 } 557 558 private: 559 union { 560 USHORT format; /* Format identifier */ 561 ClassDefFormat1 format1[VAR]; 562 ClassDefFormat2 format2[VAR]; 563 } u; 564}; 565 566 567/* 568 * Device Tables 569 */ 570 571struct Device 572{ 573 inline int operator () (unsigned int ppem_size) const { return get_delta (ppem_size); } 574 575 inline int get_delta (unsigned int ppem_size) const 576 { 577 unsigned int f = deltaFormat; 578 if (HB_UNLIKELY (f < 1 || f > 3)) 579 return 0; 580 581 if (ppem_size < startSize || ppem_size > endSize) 582 return 0; 583 584 unsigned int s = ppem_size - startSize; 585 586 unsigned int byte = deltaValue[s >> (4 - f)]; 587 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 588 unsigned int mask = (0xFFFF >> (16 - (1 << f))); 589 590 int delta = bits & mask; 591 592 if ((unsigned int) delta >= ((mask + 1) >> 1)) 593 delta -= mask + 1; 594 595 return delta; 596 } 597 598 inline unsigned int get_size () const 599 { 600 unsigned int f = deltaFormat; 601 if (HB_UNLIKELY (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::get_size (); 602 return 3 * USHORT::get_size () + ((endSize - startSize + (1 << (4 - f)) - 1) >> (4 - f)); 603 } 604 605 inline bool sanitize (SANITIZE_ARG_DEF) { 606 TRACE_SANITIZE (); 607 return SANITIZE_SELF() && SANITIZE_MEM (this, this->get_size ()); 608 } 609 610 private: 611 USHORT startSize; /* Smallest size to correct--in ppem */ 612 USHORT endSize; /* Largest size to correct--in ppem */ 613 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 */ 614 USHORT deltaValue[VAR]; /* Array of compressed data */ 615}; 616ASSERT_SIZE_VAR (Device, 6, USHORT); 617 618 619#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 620