hb-ot-layout-common-private.hh revision 67bb9e8cea49a44be6996515e1c7d8cdc95a77e6
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 private: 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 (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet)) 317 { 318 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 319 if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false); 320 } 321 return TRACE_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 TRACE_RETURN (glyphArray.sanitize (c)); 358 } 359 360 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 361 return glyphs->has (glyphArray[index]); 362 } 363 364 inline void add_coverage (hb_set_t *glyphs) const { 365 unsigned int count = glyphArray.len; 366 for (unsigned int i = 0; i < count; i++) 367 glyphs->add (glyphArray[i]); 368 } 369 370 struct Iter { 371 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; 372 inline bool more (void) { return i < c->glyphArray.len; } 373 inline void next (void) { i++; } 374 inline uint16_t get_glyph (void) { return c->glyphArray[i]; } 375 inline uint16_t get_coverage (void) { return i; } 376 377 private: 378 const struct CoverageFormat1 *c; 379 unsigned int i; 380 }; 381 382 private: 383 USHORT coverageFormat; /* Format identifier--format = 1 */ 384 SortedArrayOf<GlyphID> 385 glyphArray; /* Array of GlyphIDs--in numerical order */ 386 public: 387 DEFINE_SIZE_ARRAY (4, glyphArray); 388}; 389 390struct CoverageFormat2 391{ 392 friend struct Coverage; 393 394 private: 395 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 396 { 397 int i = rangeRecord.search (glyph_id); 398 if (i != -1) { 399 const RangeRecord &range = rangeRecord[i]; 400 return (unsigned int) range.value + (glyph_id - range.start); 401 } 402 return NOT_COVERED; 403 } 404 405 inline bool sanitize (hb_sanitize_context_t *c) { 406 TRACE_SANITIZE (); 407 return TRACE_RETURN (rangeRecord.sanitize (c)); 408 } 409 410 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 411 unsigned int i; 412 unsigned int count = rangeRecord.len; 413 for (i = 0; i < count; i++) { 414 const RangeRecord &range = rangeRecord[i]; 415 if (range.value <= index && 416 index < (unsigned int) range.value + (range.end - range.start) && 417 range.intersects (glyphs)) 418 return true; 419 else if (index < range.value) 420 return false; 421 } 422 return false; 423 } 424 425 inline void add_coverage (hb_set_t *glyphs) const { 426 unsigned int count = rangeRecord.len; 427 for (unsigned int i = 0; i < count; i++) 428 rangeRecord[i].add_coverage (glyphs); 429 } 430 431 struct Iter { 432 inline void init (const CoverageFormat2 &c_) { 433 c = &c_; 434 coverage = 0; 435 i = 0; 436 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; 437 } 438 inline bool more (void) { return i < c->rangeRecord.len; } 439 inline void next (void) { 440 coverage++; 441 if (j == c->rangeRecord[i].end) { 442 i++; 443 if (more ()) 444 j = c->rangeRecord[i].start; 445 return; 446 } 447 j++; 448 } 449 inline uint16_t get_glyph (void) { return j; } 450 inline uint16_t get_coverage (void) { return coverage; } 451 452 private: 453 const struct CoverageFormat2 *c; 454 unsigned int i, j, coverage; 455 }; 456 457 private: 458 USHORT coverageFormat; /* Format identifier--format = 2 */ 459 SortedArrayOf<RangeRecord> 460 rangeRecord; /* Array of glyph ranges--ordered by 461 * Start GlyphID. rangeCount entries 462 * long */ 463 public: 464 DEFINE_SIZE_ARRAY (4, rangeRecord); 465}; 466 467struct Coverage 468{ 469 inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); } 470 471 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 472 { 473 switch (u.format) { 474 case 1: return u.format1.get_coverage(glyph_id); 475 case 2: return u.format2.get_coverage(glyph_id); 476 default:return NOT_COVERED; 477 } 478 } 479 480 inline bool sanitize (hb_sanitize_context_t *c) { 481 TRACE_SANITIZE (); 482 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 483 switch (u.format) { 484 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 485 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 486 default:return TRACE_RETURN (true); 487 } 488 } 489 490 inline bool intersects (const hb_set_t *glyphs) const { 491 /* TODO speed this up */ 492 Coverage::Iter iter; 493 for (iter.init (*this); iter.more (); iter.next ()) { 494 if (glyphs->has (iter.get_glyph ())) 495 return true; 496 } 497 return false; 498 } 499 500 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 501 switch (u.format) { 502 case 1: return u.format1.intersects_coverage (glyphs, index); 503 case 2: return u.format2.intersects_coverage (glyphs, index); 504 default:return false; 505 } 506 } 507 508 inline void add_coverage (hb_set_t *glyphs) const { 509 switch (u.format) { 510 case 1: u.format1.add_coverage (glyphs); break; 511 case 2: u.format2.add_coverage (glyphs); break; 512 default: break; 513 } 514 } 515 516 struct Iter { 517 Iter (void) : format (0) {}; 518 inline void init (const Coverage &c_) { 519 format = c_.u.format; 520 switch (format) { 521 case 1: return u.format1.init (c_.u.format1); 522 case 2: return u.format2.init (c_.u.format2); 523 default:return; 524 } 525 } 526 inline bool more (void) { 527 switch (format) { 528 case 1: return u.format1.more (); 529 case 2: return u.format2.more (); 530 default:return true; 531 } 532 } 533 inline void next (void) { 534 switch (format) { 535 case 1: u.format1.next (); break; 536 case 2: u.format2.next (); break; 537 default: break; 538 } 539 } 540 inline uint16_t get_glyph (void) { 541 switch (format) { 542 case 1: return u.format1.get_glyph (); 543 case 2: return u.format2.get_glyph (); 544 default:return true; 545 } 546 } 547 inline uint16_t get_coverage (void) { 548 switch (format) { 549 case 1: return u.format1.get_coverage (); 550 case 2: return u.format2.get_coverage (); 551 default:return true; 552 } 553 } 554 555 private: 556 unsigned int format; 557 union { 558 CoverageFormat1::Iter format1; 559 CoverageFormat2::Iter format2; 560 } u; 561 }; 562 563 private: 564 union { 565 USHORT format; /* Format identifier */ 566 CoverageFormat1 format1; 567 CoverageFormat2 format2; 568 } u; 569 public: 570 DEFINE_SIZE_UNION (2, format); 571}; 572 573 574/* 575 * Class Definition Table 576 */ 577 578struct ClassDefFormat1 579{ 580 friend struct ClassDef; 581 582 private: 583 inline unsigned int get_class (hb_codepoint_t glyph_id) const 584 { 585 if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len)) 586 return classValue[glyph_id - startGlyph]; 587 return 0; 588 } 589 590 inline bool sanitize (hb_sanitize_context_t *c) { 591 TRACE_SANITIZE (); 592 return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c)); 593 } 594 595 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 596 unsigned int count = classValue.len; 597 for (unsigned int i = 0; i < count; i++) 598 if (classValue[i] == klass && glyphs->has (startGlyph + i)) 599 return true; 600 return false; 601 } 602 603 USHORT classFormat; /* Format identifier--format = 1 */ 604 GlyphID startGlyph; /* First GlyphID of the classValueArray */ 605 ArrayOf<USHORT> 606 classValue; /* Array of Class Values--one per GlyphID */ 607 public: 608 DEFINE_SIZE_ARRAY (6, classValue); 609}; 610 611struct ClassDefFormat2 612{ 613 friend struct ClassDef; 614 615 private: 616 inline unsigned int get_class (hb_codepoint_t glyph_id) const 617 { 618 int i = rangeRecord.search (glyph_id); 619 if (i != -1) 620 return rangeRecord[i].value; 621 return 0; 622 } 623 624 inline bool sanitize (hb_sanitize_context_t *c) { 625 TRACE_SANITIZE (); 626 return TRACE_RETURN (rangeRecord.sanitize (c)); 627 } 628 629 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 630 unsigned int count = rangeRecord.len; 631 for (unsigned int i = 0; i < count; i++) 632 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) 633 return true; 634 return false; 635 } 636 637 USHORT classFormat; /* Format identifier--format = 2 */ 638 SortedArrayOf<RangeRecord> 639 rangeRecord; /* Array of glyph ranges--ordered by 640 * Start GlyphID */ 641 public: 642 DEFINE_SIZE_ARRAY (4, rangeRecord); 643}; 644 645struct ClassDef 646{ 647 inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); } 648 649 inline unsigned int get_class (hb_codepoint_t glyph_id) const 650 { 651 switch (u.format) { 652 case 1: return u.format1.get_class(glyph_id); 653 case 2: return u.format2.get_class(glyph_id); 654 default:return 0; 655 } 656 } 657 658 inline bool sanitize (hb_sanitize_context_t *c) { 659 TRACE_SANITIZE (); 660 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 661 switch (u.format) { 662 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 663 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 664 default:return TRACE_RETURN (true); 665 } 666 } 667 668 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 669 switch (u.format) { 670 case 1: return u.format1.intersects_class (glyphs, klass); 671 case 2: return u.format2.intersects_class (glyphs, klass); 672 default:return false; 673 } 674 } 675 676 private: 677 union { 678 USHORT format; /* Format identifier */ 679 ClassDefFormat1 format1; 680 ClassDefFormat2 format2; 681 } u; 682 public: 683 DEFINE_SIZE_UNION (2, format); 684}; 685 686 687/* 688 * Device Tables 689 */ 690 691struct Device 692{ 693 694 inline hb_position_t get_x_delta (hb_font_t *font) const 695 { return get_delta (font->x_ppem, font->x_scale); } 696 697 inline hb_position_t get_y_delta (hb_font_t *font) const 698 { return get_delta (font->y_ppem, font->y_scale); } 699 700 inline int get_delta (unsigned int ppem, int scale) const 701 { 702 if (!ppem) return 0; 703 704 int pixels = get_delta_pixels (ppem); 705 706 if (!pixels) return 0; 707 708 return pixels * (int64_t) scale / ppem; 709 } 710 711 712 inline int get_delta_pixels (unsigned int ppem_size) const 713 { 714 unsigned int f = deltaFormat; 715 if (unlikely (f < 1 || f > 3)) 716 return 0; 717 718 if (ppem_size < startSize || ppem_size > endSize) 719 return 0; 720 721 unsigned int s = ppem_size - startSize; 722 723 unsigned int byte = deltaValue[s >> (4 - f)]; 724 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 725 unsigned int mask = (0xFFFF >> (16 - (1 << f))); 726 727 int delta = bits & mask; 728 729 if ((unsigned int) delta >= ((mask + 1) >> 1)) 730 delta -= mask + 1; 731 732 return delta; 733 } 734 735 inline unsigned int get_size (void) const 736 { 737 unsigned int f = deltaFormat; 738 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; 739 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); 740 } 741 742 inline bool sanitize (hb_sanitize_context_t *c) { 743 TRACE_SANITIZE (); 744 return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ())); 745 } 746 747 private: 748 USHORT startSize; /* Smallest size to correct--in ppem */ 749 USHORT endSize; /* Largest size to correct--in ppem */ 750 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 751 * 1 Signed 2-bit value, 8 values per uint16 752 * 2 Signed 4-bit value, 4 values per uint16 753 * 3 Signed 8-bit value, 2 values per uint16 754 */ 755 USHORT deltaValue[VAR]; /* Array of compressed data */ 756 public: 757 DEFINE_SIZE_ARRAY (6, deltaValue); 758}; 759 760 761 762#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 763