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