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