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