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