hb-ot-layout-common-private.hh revision 5bd1e95236320aed60fb29ca1e93b9595d4aeeec
1/* 2 * Copyright (C) 2007,2008,2009 Red Hat, Inc. 3 * Copyright (C) 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 b) const { 60 hb_tag_t a = tag; 61 return b < a ? -1 : b == a ? 0 : -1; 62 } 63 64 inline bool sanitize (hb_sanitize_context_t *c, void *base) { 65 TRACE_SANITIZE (); 66 return c->check_struct (this) 67 && offset.sanitize (c, base); 68 } 69 70 Tag tag; /* 4-byte Tag identifier */ 71 OffsetTo<Type> 72 offset; /* Offset from beginning of object holding 73 * the Record */ 74 public: 75 DEFINE_SIZE_STATIC (6); 76}; 77 78template <typename Type> 79struct RecordArrayOf : SortedArrayOf<Record<Type> > { 80 inline const Tag& get_tag (unsigned int i) const 81 { 82 if (unlikely (i >= this->len)) return Null(Tag); 83 return (*this)[i].tag; 84 } 85 inline unsigned int get_tags (unsigned int start_offset, 86 unsigned int *record_count /* IN/OUT */, 87 hb_tag_t *record_tags /* OUT */) const 88 { 89 if (record_count) { 90 const Record<Type> *array = this->sub_array (start_offset, record_count); 91 unsigned int count = *record_count; 92 for (unsigned int i = 0; i < count; i++) 93 record_tags[i] = array[i].tag; 94 } 95 return this->len; 96 } 97 inline bool find_index (hb_tag_t tag, unsigned int *index) const 98 { 99 int i = this->search (tag); 100 if (i != -1) { 101 if (index) *index = i; 102 return true; 103 } else { 104 if (index) *index = Index::NOT_FOUND_INDEX; 105 return false; 106 } 107 } 108}; 109 110template <typename Type> 111struct RecordListOf : RecordArrayOf<Type> 112{ 113 inline const Type& operator [] (unsigned int i) const 114 { return this+RecordArrayOf<Type>::operator [](i).offset; } 115 116 inline bool sanitize (hb_sanitize_context_t *c) { 117 TRACE_SANITIZE (); 118 return RecordArrayOf<Type>::sanitize (c, this); 119 } 120}; 121 122 123struct RangeRecord 124{ 125 inline int cmp (hb_codepoint_t g) const { 126 hb_codepoint_t a = start, b = end; 127 return g < a ? -1 : g <= b ? 0 : +1 ; 128 } 129 130 inline bool sanitize (hb_sanitize_context_t *c) { 131 TRACE_SANITIZE (); 132 return c->check_struct (this); 133 } 134 135 GlyphID start; /* First GlyphID in the range */ 136 GlyphID end; /* Last GlyphID in the range */ 137 USHORT value; /* Value */ 138 public: 139 DEFINE_SIZE_STATIC (6); 140}; 141DEFINE_NULL_DATA (RangeRecord, "\000\001"); 142 143 144struct IndexArray : ArrayOf<Index> 145{ 146 inline unsigned int get_indexes (unsigned int start_offset, 147 unsigned int *_count /* IN/OUT */, 148 unsigned int *_indexes /* OUT */) const 149 { 150 if (_count) { 151 const USHORT *array = this->sub_array (start_offset, _count); 152 unsigned int count = *_count; 153 for (unsigned int i = 0; i < count; i++) 154 _indexes[i] = array[i]; 155 } 156 return this->len; 157 } 158}; 159 160 161struct Script; 162struct LangSys; 163struct Feature; 164 165 166struct LangSys 167{ 168 inline unsigned int get_feature_count (void) const 169 { return featureIndex.len; } 170 inline hb_tag_t get_feature_index (unsigned int i) const 171 { return featureIndex[i]; } 172 inline unsigned int get_feature_indexes (unsigned int start_offset, 173 unsigned int *feature_count /* IN/OUT */, 174 unsigned int *feature_indexes /* OUT */) const 175 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } 176 177 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; } 178 inline unsigned int get_required_feature_index (void) const 179 { 180 if (reqFeatureIndex == 0xffff) 181 return Index::NOT_FOUND_INDEX; 182 return reqFeatureIndex;; 183 } 184 185 inline bool sanitize (hb_sanitize_context_t *c) { 186 TRACE_SANITIZE (); 187 return c->check_struct (this) 188 && featureIndex.sanitize (c); 189 } 190 191 Offset lookupOrder; /* = Null (reserved for an offset to a 192 * reordering table) */ 193 USHORT reqFeatureIndex;/* Index of a feature required for this 194 * language system--if no required features 195 * = 0xFFFF */ 196 IndexArray featureIndex; /* Array of indices into the FeatureList */ 197 public: 198 DEFINE_SIZE_ARRAY (6, featureIndex); 199}; 200DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); 201 202 203struct Script 204{ 205 inline unsigned int get_lang_sys_count (void) const 206 { return langSys.len; } 207 inline const Tag& get_lang_sys_tag (unsigned int i) const 208 { return langSys.get_tag (i); } 209 inline unsigned int get_lang_sys_tags (unsigned int start_offset, 210 unsigned int *lang_sys_count /* IN/OUT */, 211 hb_tag_t *lang_sys_tags /* OUT */) const 212 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } 213 inline const LangSys& get_lang_sys (unsigned int i) const 214 { 215 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); 216 return this+langSys[i].offset; 217 } 218 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const 219 { return langSys.find_index (tag, index); } 220 221 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } 222 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } 223 224 inline bool sanitize (hb_sanitize_context_t *c) { 225 TRACE_SANITIZE (); 226 return defaultLangSys.sanitize (c, this) 227 && langSys.sanitize (c, this); 228 } 229 230 private: 231 OffsetTo<LangSys> 232 defaultLangSys; /* Offset to DefaultLangSys table--from 233 * beginning of Script table--may be Null */ 234 RecordArrayOf<LangSys> 235 langSys; /* Array of LangSysRecords--listed 236 * alphabetically by LangSysTag */ 237 public: 238 DEFINE_SIZE_ARRAY (4, langSys); 239}; 240 241typedef RecordListOf<Script> ScriptList; 242 243 244struct Feature 245{ 246 inline unsigned int get_lookup_count (void) const 247 { return lookupIndex.len; } 248 inline hb_tag_t get_lookup_index (unsigned int i) const 249 { return lookupIndex[i]; } 250 inline unsigned int get_lookup_indexes (unsigned int start_index, 251 unsigned int *lookup_count /* IN/OUT */, 252 unsigned int *lookup_tags /* OUT */) const 253 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } 254 255 inline bool sanitize (hb_sanitize_context_t *c) { 256 TRACE_SANITIZE (); 257 return c->check_struct (this) 258 && lookupIndex.sanitize (c); 259 } 260 261 /* LONGTERMTODO: implement get_feature_parameters() */ 262 /* LONGTERMTODO: implement FeatureSize and other special features? */ 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 inline unsigned int get_flag (void) const 297 { 298 unsigned int flag = lookupFlag; 299 if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) 300 { 301 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 302 flag += (markFilteringSet << 16); 303 } 304 return flag; 305 } 306 307 inline bool sanitize (hb_sanitize_context_t *c) { 308 TRACE_SANITIZE (); 309 /* Real sanitize of the subtables is done by GSUB/GPOS/... */ 310 if (!(c->check_struct (this) 311 && subTable.sanitize (c))) return false; 312 if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet)) 313 { 314 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 315 if (!markFilteringSet.sanitize (c)) return false; 316 } 317 return true; 318 } 319 320 USHORT lookupType; /* Different enumerations for GSUB and GPOS */ 321 USHORT lookupFlag; /* Lookup qualifiers */ 322 ArrayOf<Offset> 323 subTable; /* Array of SubTables */ 324 USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets 325 * structure. This field is only present if bit 326 * UseMarkFilteringSet of lookup flags is set. */ 327 public: 328 DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); 329}; 330 331typedef OffsetListOf<Lookup> LookupList; 332 333 334/* 335 * Coverage Table 336 */ 337 338struct CoverageFormat1 339{ 340 friend struct Coverage; 341 342 private: 343 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 344 { 345 int i = glyphArray.search (glyph_id); 346 if (i != -1) 347 return i; 348 return NOT_COVERED; 349 } 350 351 inline bool sanitize (hb_sanitize_context_t *c) { 352 TRACE_SANITIZE (); 353 return glyphArray.sanitize (c); 354 } 355 356 private: 357 USHORT coverageFormat; /* Format identifier--format = 1 */ 358 SortedArrayOf<GlyphID> 359 glyphArray; /* Array of GlyphIDs--in numerical order */ 360 public: 361 DEFINE_SIZE_ARRAY (4, glyphArray); 362}; 363 364struct CoverageFormat2 365{ 366 friend struct Coverage; 367 368 private: 369 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 370 { 371 int i = rangeRecord.search (glyph_id); 372 if (i != -1) { 373 const RangeRecord &range = rangeRecord[i]; 374 return (unsigned int) range.value + (glyph_id - range.start); 375 } 376 return NOT_COVERED; 377 } 378 379 inline bool sanitize (hb_sanitize_context_t *c) { 380 TRACE_SANITIZE (); 381 return rangeRecord.sanitize (c); 382 } 383 384 private: 385 USHORT coverageFormat; /* Format identifier--format = 2 */ 386 SortedArrayOf<RangeRecord> 387 rangeRecord; /* Array of glyph ranges--ordered by 388 * Start GlyphID. rangeCount entries 389 * long */ 390 public: 391 DEFINE_SIZE_ARRAY (4, rangeRecord); 392}; 393 394struct Coverage 395{ 396 inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); } 397 398 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 399 { 400 switch (u.format) { 401 case 1: return u.format1.get_coverage(glyph_id); 402 case 2: return u.format2.get_coverage(glyph_id); 403 default:return NOT_COVERED; 404 } 405 } 406 407 inline bool sanitize (hb_sanitize_context_t *c) { 408 TRACE_SANITIZE (); 409 if (!u.format.sanitize (c)) return false; 410 switch (u.format) { 411 case 1: return u.format1.sanitize (c); 412 case 2: return u.format2.sanitize (c); 413 default:return true; 414 } 415 } 416 417 private: 418 union { 419 USHORT format; /* Format identifier */ 420 CoverageFormat1 format1; 421 CoverageFormat2 format2; 422 } u; 423 public: 424 DEFINE_SIZE_UNION (2, format); 425}; 426 427 428/* 429 * Class Definition Table 430 */ 431 432struct ClassDefFormat1 433{ 434 friend struct ClassDef; 435 436 private: 437 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 438 { 439 if ((unsigned int) (glyph_id - startGlyph) < classValue.len) 440 return classValue[glyph_id - startGlyph]; 441 return 0; 442 } 443 444 inline bool sanitize (hb_sanitize_context_t *c) { 445 TRACE_SANITIZE (); 446 return c->check_struct (this) 447 && classValue.sanitize (c); 448 } 449 450 USHORT classFormat; /* Format identifier--format = 1 */ 451 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 452 ArrayOf<USHORT> 453 classValue; /* Array of Class Values--one per GlyphID */ 454 public: 455 DEFINE_SIZE_ARRAY (6, classValue); 456}; 457 458struct ClassDefFormat2 459{ 460 friend struct ClassDef; 461 462 private: 463 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 464 { 465 int i = rangeRecord.search (glyph_id); 466 if (i != -1) 467 return rangeRecord[i].value; 468 return 0; 469 } 470 471 inline bool sanitize (hb_sanitize_context_t *c) { 472 TRACE_SANITIZE (); 473 return rangeRecord.sanitize (c); 474 } 475 476 USHORT classFormat; /* Format identifier--format = 2 */ 477 SortedArrayOf<RangeRecord> 478 rangeRecord; /* Array of glyph ranges--ordered by 479 * Start GlyphID */ 480 public: 481 DEFINE_SIZE_ARRAY (4, rangeRecord); 482}; 483 484struct ClassDef 485{ 486 inline hb_ot_layout_class_t operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); } 487 488 inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const 489 { 490 switch (u.format) { 491 case 1: return u.format1.get_class(glyph_id); 492 case 2: return u.format2.get_class(glyph_id); 493 default:return 0; 494 } 495 } 496 497 inline bool sanitize (hb_sanitize_context_t *c) { 498 TRACE_SANITIZE (); 499 if (!u.format.sanitize (c)) return false; 500 switch (u.format) { 501 case 1: return u.format1.sanitize (c); 502 case 2: return u.format2.sanitize (c); 503 default:return true; 504 } 505 } 506 507 private: 508 union { 509 USHORT format; /* Format identifier */ 510 ClassDefFormat1 format1; 511 ClassDefFormat2 format2; 512 } u; 513 public: 514 DEFINE_SIZE_UNION (2, format); 515}; 516 517 518/* 519 * Device Tables 520 */ 521 522struct Device 523{ 524 525 inline hb_position_t get_x_delta (hb_ot_layout_context_t *c) const 526 { return get_delta (c->font->x_ppem, c->font->x_scale); } 527 528 inline hb_position_t get_y_delta (hb_ot_layout_context_t *c) const 529 { return get_delta (c->font->y_ppem, c->font->y_scale); } 530 531 inline int get_delta (unsigned int ppem, unsigned int scale) const 532 { 533 if (!ppem) return 0; 534 535 int pixels = get_delta_pixels (ppem); 536 537 if (!pixels) return 0; 538 539 /* pixels is at most in the -8..7 range. So 64-bit arithmetic is 540 * not really necessary here. A simple cast to int may just work 541 * as well. But since this code is not reached that often and 542 * for the sake of correctness, we do a 64bit operation. */ 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 () 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