hb-ot-layout-gsubgpos-private.hh revision 4b7192125ffd295091d6b3a0bdfca7011947c2ca
1/* 2 * Copyright © 2007,2008,2009,2010 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_GSUBGPOS_PRIVATE_HH 30#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH 31 32#include "hb-buffer-private.hh" 33#include "hb-ot-layout-gdef-table.hh" 34 35 36 37/* unique ligature id */ 38/* component number in the ligature (0 = base) */ 39static inline void 40set_lig_props (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp) 41{ 42 info.lig_props() = (lig_id << 4) | (lig_comp & 0x0F); 43} 44static inline unsigned int 45get_lig_id (hb_glyph_info_t &info) 46{ 47 return info.lig_props() >> 4; 48} 49static inline unsigned int 50get_lig_comp (hb_glyph_info_t &info) 51{ 52 return info.lig_props() & 0x0F; 53} 54 55static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) { 56 uint8_t lig_id = buffer->next_serial () & 0x0F; 57 if (unlikely (!lig_id)) 58 lig_id = allocate_lig_id (buffer); /* in case of overflow */ 59 return lig_id; 60} 61 62 63 64#ifndef HB_DEBUG_CLOSURE 65#define HB_DEBUG_CLOSURE (HB_DEBUG+0) 66#endif 67 68#define TRACE_CLOSURE() \ 69 hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, ""); 70 71 72/* TODO Add TRACE_RETURN annotation for would_apply */ 73 74 75struct hb_closure_context_t 76{ 77 hb_face_t *face; 78 hb_set_t *glyphs; 79 unsigned int nesting_level_left; 80 unsigned int debug_depth; 81 82 83 hb_closure_context_t (hb_face_t *face_, 84 hb_set_t *glyphs_, 85 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 86 face (face_), glyphs (glyphs_), 87 nesting_level_left (nesting_level_left_), 88 debug_depth (0) {} 89}; 90 91 92 93#ifndef HB_DEBUG_APPLY 94#define HB_DEBUG_APPLY (HB_DEBUG+0) 95#endif 96 97#define TRACE_APPLY() \ 98 hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); 99 100 101 102struct hb_apply_context_t 103{ 104 hb_font_t *font; 105 hb_face_t *face; 106 hb_buffer_t *buffer; 107 hb_direction_t direction; 108 hb_mask_t lookup_mask; 109 unsigned int nesting_level_left; 110 unsigned int lookup_props; 111 unsigned int property; /* propety of first glyph */ 112 unsigned int debug_depth; 113 114 115 hb_apply_context_t (hb_font_t *font_, 116 hb_face_t *face_, 117 hb_buffer_t *buffer_, 118 hb_mask_t lookup_mask_) : 119 font (font_), face (face_), buffer (buffer_), 120 direction (buffer_->props.direction), 121 lookup_mask (lookup_mask_), 122 nesting_level_left (MAX_NESTING_LEVEL), 123 lookup_props (0), property (0), debug_depth (0) {} 124 125 void set_lookup (const Lookup &l) { 126 lookup_props = l.get_props (); 127 } 128 129 struct mark_skipping_forward_iterator_t 130 { 131 inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_, 132 unsigned int start_index_, 133 unsigned int num_items_, 134 bool context_match = false) 135 { 136 c = c_; 137 idx = start_index_; 138 num_items = num_items_; 139 mask = context_match ? -1 : c->lookup_mask; 140 syllable = context_match ? 0 : c->buffer->cur().syllable (); 141 end = c->buffer->len; 142 } 143 inline bool has_no_chance (void) const 144 { 145 return unlikely (num_items && idx + num_items >= end); 146 } 147 inline bool next (unsigned int *property_out, 148 unsigned int lookup_props) 149 { 150 assert (num_items > 0); 151 do 152 { 153 if (has_no_chance ()) 154 return false; 155 idx++; 156 } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out)); 157 num_items--; 158 return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ()); 159 } 160 inline bool next (unsigned int *property_out = NULL) 161 { 162 return next (property_out, c->lookup_props); 163 } 164 165 unsigned int idx; 166 private: 167 hb_apply_context_t *c; 168 unsigned int num_items; 169 hb_mask_t mask; 170 uint8_t syllable; 171 unsigned int end; 172 }; 173 174 struct mark_skipping_backward_iterator_t 175 { 176 inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_, 177 unsigned int start_index_, 178 unsigned int num_items_, 179 hb_mask_t mask_ = 0, 180 bool match_syllable_ = true) 181 { 182 c = c_; 183 idx = start_index_; 184 num_items = num_items_; 185 mask = mask_ ? mask_ : c->lookup_mask; 186 syllable = match_syllable_ ? c->buffer->cur().syllable () : 0; 187 } 188 inline bool has_no_chance (void) const 189 { 190 return unlikely (idx < num_items); 191 } 192 inline bool prev (unsigned int *property_out, 193 unsigned int lookup_props) 194 { 195 assert (num_items > 0); 196 do 197 { 198 if (has_no_chance ()) 199 return false; 200 idx--; 201 } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out)); 202 num_items--; 203 return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ()); 204 } 205 inline bool prev (unsigned int *property_out = NULL) 206 { 207 return prev (property_out, c->lookup_props); 208 } 209 210 unsigned int idx; 211 private: 212 hb_apply_context_t *c; 213 unsigned int num_items; 214 hb_mask_t mask; 215 uint8_t syllable; 216 }; 217 218 inline bool should_mark_skip_current_glyph (void) const 219 { 220 return _hb_ot_layout_skip_mark (face, &buffer->cur(), lookup_props, NULL); 221 } 222 223 224 225 inline void replace_glyph (hb_codepoint_t glyph_index, 226 unsigned int klass = 0) const 227 { 228 buffer->cur().props_cache() = klass; /*XXX if has gdef? */ 229 buffer->replace_glyph (glyph_index); 230 } 231 inline void replace_glyphs_be16 (unsigned int num_in, 232 unsigned int num_out, 233 const char *glyph_data_be, 234 unsigned int klass = 0) const 235 { 236 buffer->cur().props_cache() = klass; /* XXX if has gdef? */ 237 buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be); 238 } 239 inline void replace_glyphs (unsigned int num_in, 240 unsigned int num_out, 241 hb_codepoint_t *glyph_data, 242 unsigned int klass = 0) const 243 { 244 buffer->cur().props_cache() = klass; /* XXX if has gdef? */ 245 buffer->replace_glyphs (num_in, num_out, glyph_data); 246 } 247}; 248 249 250 251typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 252typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 253typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index); 254typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index); 255 256struct ContextClosureFuncs 257{ 258 intersects_func_t intersects; 259 closure_lookup_func_t closure; 260}; 261struct ContextApplyFuncs 262{ 263 match_func_t match; 264 apply_lookup_func_t apply; 265}; 266 267static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 268{ 269 return glyphs->has (value); 270} 271static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) 272{ 273 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 274 return class_def.intersects_class (glyphs, value); 275} 276static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 277{ 278 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 279 return (data+coverage).intersects (glyphs); 280} 281 282static inline bool intersects_array (hb_closure_context_t *c, 283 unsigned int count, 284 const USHORT values[], 285 intersects_func_t intersects_func, 286 const void *intersects_data) 287{ 288 for (unsigned int i = 0; i < count; i++) 289 if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) 290 return false; 291 return true; 292} 293 294 295static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) 296{ 297 return glyph_id == value; 298} 299static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 300{ 301 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 302 return class_def.get_class (glyph_id) == value; 303} 304static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 305{ 306 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 307 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; 308} 309 310 311static inline bool match_input (hb_apply_context_t *c, 312 unsigned int count, /* Including the first glyph (not matched) */ 313 const USHORT input[], /* Array of input values--start with second glyph */ 314 match_func_t match_func, 315 const void *match_data, 316 unsigned int *end_offset = NULL) 317{ 318 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); 319 if (skippy_iter.has_no_chance ()) 320 return false; 321 322 for (unsigned int i = 1; i < count; i++) 323 { 324 if (!skippy_iter.next ()) 325 return false; 326 327 if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) 328 return false; 329 } 330 331 if (end_offset) 332 *end_offset = skippy_iter.idx - c->buffer->idx + 1; 333 334 return true; 335} 336 337static inline bool match_backtrack (hb_apply_context_t *c, 338 unsigned int count, 339 const USHORT backtrack[], 340 match_func_t match_func, 341 const void *match_data) 342{ 343 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); 344 if (skippy_iter.has_no_chance ()) 345 return false; 346 347 for (unsigned int i = 0; i < count; i++) 348 { 349 if (!skippy_iter.prev ()) 350 return false; 351 352 if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data))) 353 return false; 354 } 355 356 return true; 357} 358 359static inline bool match_lookahead (hb_apply_context_t *c, 360 unsigned int count, 361 const USHORT lookahead[], 362 match_func_t match_func, 363 const void *match_data, 364 unsigned int offset) 365{ 366 hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); 367 if (skippy_iter.has_no_chance ()) 368 return false; 369 370 for (unsigned int i = 0; i < count; i++) 371 { 372 if (!skippy_iter.next ()) 373 return false; 374 375 if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data))) 376 return false; 377 } 378 379 return true; 380} 381 382 383 384struct LookupRecord 385{ 386 inline bool sanitize (hb_sanitize_context_t *c) { 387 TRACE_SANITIZE (); 388 return TRACE_RETURN (c->check_struct (this)); 389 } 390 391 USHORT sequenceIndex; /* Index into current glyph 392 * sequence--first glyph = 0 */ 393 USHORT lookupListIndex; /* Lookup to apply to that 394 * position--zero--based */ 395 public: 396 DEFINE_SIZE_STATIC (4); 397}; 398 399 400static inline void closure_lookup (hb_closure_context_t *c, 401 unsigned int lookupCount, 402 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 403 closure_lookup_func_t closure_func) 404{ 405 for (unsigned int i = 0; i < lookupCount; i++) 406 closure_func (c, lookupRecord->lookupListIndex); 407} 408 409static inline bool apply_lookup (hb_apply_context_t *c, 410 unsigned int count, /* Including the first glyph */ 411 unsigned int lookupCount, 412 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 413 apply_lookup_func_t apply_func) 414{ 415 unsigned int end = c->buffer->len; 416 if (unlikely (count == 0 || c->buffer->idx + count > end)) 417 return false; 418 419 /* TODO We don't support lookupRecord arrays that are not increasing: 420 * Should be easy for in_place ones at least. */ 421 422 /* Note: If sublookup is reverse, it will underflow after the first loop 423 * and we jump out of it. Not entirely disastrous. So we don't check 424 * for reverse lookup here. 425 */ 426 for (unsigned int i = 0; i < count; /* NOP */) 427 { 428 if (unlikely (c->buffer->idx == end)) 429 return true; 430 while (c->should_mark_skip_current_glyph ()) 431 { 432 /* No lookup applied for this index */ 433 c->buffer->next_glyph (); 434 if (unlikely (c->buffer->idx == end)) 435 return true; 436 } 437 438 if (lookupCount && i == lookupRecord->sequenceIndex) 439 { 440 unsigned int old_pos = c->buffer->idx; 441 442 /* Apply a lookup */ 443 bool done = apply_func (c, lookupRecord->lookupListIndex); 444 445 lookupRecord++; 446 lookupCount--; 447 /* Err, this is wrong if the lookup jumped over some glyphs */ 448 i += c->buffer->idx - old_pos; 449 if (unlikely (c->buffer->idx == end)) 450 return true; 451 452 if (!done) 453 goto not_applied; 454 } 455 else 456 { 457 not_applied: 458 /* No lookup applied for this index */ 459 c->buffer->next_glyph (); 460 i++; 461 } 462 } 463 464 return true; 465} 466 467 468 469/* Contextual lookups */ 470 471struct ContextClosureLookupContext 472{ 473 ContextClosureFuncs funcs; 474 const void *intersects_data; 475}; 476 477struct ContextApplyLookupContext 478{ 479 ContextApplyFuncs funcs; 480 const void *match_data; 481}; 482 483static inline void context_closure_lookup (hb_closure_context_t *c, 484 unsigned int inputCount, /* Including the first glyph (not matched) */ 485 const USHORT input[], /* Array of input values--start with second glyph */ 486 unsigned int lookupCount, 487 const LookupRecord lookupRecord[], 488 ContextClosureLookupContext &lookup_context) 489{ 490 if (intersects_array (c, 491 inputCount ? inputCount - 1 : 0, input, 492 lookup_context.funcs.intersects, lookup_context.intersects_data)) 493 closure_lookup (c, 494 lookupCount, lookupRecord, 495 lookup_context.funcs.closure); 496} 497 498 499static inline bool context_apply_lookup (hb_apply_context_t *c, 500 unsigned int inputCount, /* Including the first glyph (not matched) */ 501 const USHORT input[], /* Array of input values--start with second glyph */ 502 unsigned int lookupCount, 503 const LookupRecord lookupRecord[], 504 ContextApplyLookupContext &lookup_context) 505{ 506 return match_input (c, 507 inputCount, input, 508 lookup_context.funcs.match, lookup_context.match_data) 509 && apply_lookup (c, 510 inputCount, 511 lookupCount, lookupRecord, 512 lookup_context.funcs.apply); 513} 514 515struct Rule 516{ 517 friend struct RuleSet; 518 519 private: 520 521 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 522 { 523 TRACE_CLOSURE (); 524 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 525 context_closure_lookup (c, 526 inputCount, input, 527 lookupCount, lookupRecord, 528 lookup_context); 529 } 530 531 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 532 { 533 TRACE_APPLY (); 534 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 535 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 536 } 537 538 public: 539 inline bool sanitize (hb_sanitize_context_t *c) { 540 TRACE_SANITIZE (); 541 return inputCount.sanitize (c) 542 && lookupCount.sanitize (c) 543 && c->check_range (input, 544 input[0].static_size * inputCount 545 + lookupRecordX[0].static_size * lookupCount); 546 } 547 548 private: 549 USHORT inputCount; /* Total number of glyphs in input 550 * glyph sequence--includes the first 551 * glyph */ 552 USHORT lookupCount; /* Number of LookupRecords */ 553 USHORT input[VAR]; /* Array of match inputs--start with 554 * second glyph */ 555 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 556 * design order */ 557 public: 558 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); 559}; 560 561struct RuleSet 562{ 563 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 564 { 565 TRACE_CLOSURE (); 566 unsigned int num_rules = rule.len; 567 for (unsigned int i = 0; i < num_rules; i++) 568 (this+rule[i]).closure (c, lookup_context); 569 } 570 571 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 572 { 573 TRACE_APPLY (); 574 unsigned int num_rules = rule.len; 575 for (unsigned int i = 0; i < num_rules; i++) 576 { 577 if ((this+rule[i]).apply (c, lookup_context)) 578 return TRACE_RETURN (true); 579 } 580 return TRACE_RETURN (false); 581 } 582 583 inline bool sanitize (hb_sanitize_context_t *c) { 584 TRACE_SANITIZE (); 585 return TRACE_RETURN (rule.sanitize (c, this)); 586 } 587 588 private: 589 OffsetArrayOf<Rule> 590 rule; /* Array of Rule tables 591 * ordered by preference */ 592 public: 593 DEFINE_SIZE_ARRAY (2, rule); 594}; 595 596 597struct ContextFormat1 598{ 599 friend struct Context; 600 601 private: 602 603 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 604 { 605 TRACE_CLOSURE (); 606 607 const Coverage &cov = (this+coverage); 608 609 struct ContextClosureLookupContext lookup_context = { 610 {intersects_glyph, closure_func}, 611 NULL 612 }; 613 614 unsigned int count = ruleSet.len; 615 for (unsigned int i = 0; i < count; i++) 616 if (cov.intersects_coverage (c->glyphs, i)) { 617 const RuleSet &rule_set = this+ruleSet[i]; 618 rule_set.closure (c, lookup_context); 619 } 620 } 621 622 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 623 { 624 TRACE_APPLY (); 625 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 626 if (likely (index == NOT_COVERED)) 627 return TRACE_RETURN (false); 628 629 const RuleSet &rule_set = this+ruleSet[index]; 630 struct ContextApplyLookupContext lookup_context = { 631 {match_glyph, apply_func}, 632 NULL 633 }; 634 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 635 } 636 637 inline bool sanitize (hb_sanitize_context_t *c) { 638 TRACE_SANITIZE (); 639 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 640 } 641 642 private: 643 USHORT format; /* Format identifier--format = 1 */ 644 OffsetTo<Coverage> 645 coverage; /* Offset to Coverage table--from 646 * beginning of table */ 647 OffsetArrayOf<RuleSet> 648 ruleSet; /* Array of RuleSet tables 649 * ordered by Coverage Index */ 650 public: 651 DEFINE_SIZE_ARRAY (6, ruleSet); 652}; 653 654 655struct ContextFormat2 656{ 657 friend struct Context; 658 659 private: 660 661 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 662 { 663 TRACE_CLOSURE (); 664 if (!(this+coverage).intersects (c->glyphs)) 665 return; 666 667 const ClassDef &class_def = this+classDef; 668 669 struct ContextClosureLookupContext lookup_context = { 670 {intersects_class, closure_func}, 671 NULL 672 }; 673 674 unsigned int count = ruleSet.len; 675 for (unsigned int i = 0; i < count; i++) 676 if (class_def.intersects_class (c->glyphs, i)) { 677 const RuleSet &rule_set = this+ruleSet[i]; 678 rule_set.closure (c, lookup_context); 679 } 680 } 681 682 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 683 { 684 TRACE_APPLY (); 685 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 686 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 687 688 const ClassDef &class_def = this+classDef; 689 index = class_def (c->buffer->cur().codepoint); 690 const RuleSet &rule_set = this+ruleSet[index]; 691 struct ContextApplyLookupContext lookup_context = { 692 {match_class, apply_func}, 693 &class_def 694 }; 695 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 696 } 697 698 inline bool sanitize (hb_sanitize_context_t *c) { 699 TRACE_SANITIZE (); 700 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); 701 } 702 703 private: 704 USHORT format; /* Format identifier--format = 2 */ 705 OffsetTo<Coverage> 706 coverage; /* Offset to Coverage table--from 707 * beginning of table */ 708 OffsetTo<ClassDef> 709 classDef; /* Offset to glyph ClassDef table--from 710 * beginning of table */ 711 OffsetArrayOf<RuleSet> 712 ruleSet; /* Array of RuleSet tables 713 * ordered by class */ 714 public: 715 DEFINE_SIZE_ARRAY (8, ruleSet); 716}; 717 718 719struct ContextFormat3 720{ 721 friend struct Context; 722 723 private: 724 725 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 726 { 727 TRACE_CLOSURE (); 728 if (!(this+coverage[0]).intersects (c->glyphs)) 729 return; 730 731 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 732 struct ContextClosureLookupContext lookup_context = { 733 {intersects_coverage, closure_func}, 734 this 735 }; 736 context_closure_lookup (c, 737 glyphCount, (const USHORT *) (coverage + 1), 738 lookupCount, lookupRecord, 739 lookup_context); 740 } 741 742 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 743 { 744 TRACE_APPLY (); 745 unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint); 746 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 747 748 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 749 struct ContextApplyLookupContext lookup_context = { 750 {match_coverage, apply_func}, 751 this 752 }; 753 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 754 } 755 756 inline bool sanitize (hb_sanitize_context_t *c) { 757 TRACE_SANITIZE (); 758 if (!c->check_struct (this)) return TRACE_RETURN (false); 759 unsigned int count = glyphCount; 760 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); 761 for (unsigned int i = 0; i < count; i++) 762 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); 763 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 764 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); 765 } 766 767 private: 768 USHORT format; /* Format identifier--format = 3 */ 769 USHORT glyphCount; /* Number of glyphs in the input glyph 770 * sequence */ 771 USHORT lookupCount; /* Number of LookupRecords */ 772 OffsetTo<Coverage> 773 coverage[VAR]; /* Array of offsets to Coverage 774 * table in glyph sequence order */ 775 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 776 * design order */ 777 public: 778 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 779}; 780 781struct Context 782{ 783 protected: 784 785 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 786 { 787 TRACE_CLOSURE (); 788 switch (u.format) { 789 case 1: u.format1.closure (c, closure_func); break; 790 case 2: u.format2.closure (c, closure_func); break; 791 case 3: u.format3.closure (c, closure_func); break; 792 default: break; 793 } 794 } 795 796 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 797 { 798 TRACE_APPLY (); 799 switch (u.format) { 800 case 1: return TRACE_RETURN (u.format1.apply (c, apply_func)); 801 case 2: return TRACE_RETURN (u.format2.apply (c, apply_func)); 802 case 3: return TRACE_RETURN (u.format3.apply (c, apply_func)); 803 default:return TRACE_RETURN (false); 804 } 805 } 806 807 inline bool sanitize (hb_sanitize_context_t *c) { 808 TRACE_SANITIZE (); 809 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 810 switch (u.format) { 811 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 812 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 813 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 814 default:return TRACE_RETURN (true); 815 } 816 } 817 818 private: 819 union { 820 USHORT format; /* Format identifier */ 821 ContextFormat1 format1; 822 ContextFormat2 format2; 823 ContextFormat3 format3; 824 } u; 825}; 826 827 828/* Chaining Contextual lookups */ 829 830struct ChainContextClosureLookupContext 831{ 832 ContextClosureFuncs funcs; 833 const void *intersects_data[3]; 834}; 835 836struct ChainContextApplyLookupContext 837{ 838 ContextApplyFuncs funcs; 839 const void *match_data[3]; 840}; 841 842static inline void chain_context_closure_lookup (hb_closure_context_t *c, 843 unsigned int backtrackCount, 844 const USHORT backtrack[], 845 unsigned int inputCount, /* Including the first glyph (not matched) */ 846 const USHORT input[], /* Array of input values--start with second glyph */ 847 unsigned int lookaheadCount, 848 const USHORT lookahead[], 849 unsigned int lookupCount, 850 const LookupRecord lookupRecord[], 851 ChainContextClosureLookupContext &lookup_context) 852{ 853 if (intersects_array (c, 854 backtrackCount, backtrack, 855 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 856 && intersects_array (c, 857 inputCount ? inputCount - 1 : 0, input, 858 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 859 && intersects_array (c, 860 lookaheadCount, lookahead, 861 lookup_context.funcs.intersects, lookup_context.intersects_data[2])) 862 closure_lookup (c, 863 lookupCount, lookupRecord, 864 lookup_context.funcs.closure); 865} 866 867static inline bool chain_context_apply_lookup (hb_apply_context_t *c, 868 unsigned int backtrackCount, 869 const USHORT backtrack[], 870 unsigned int inputCount, /* Including the first glyph (not matched) */ 871 const USHORT input[], /* Array of input values--start with second glyph */ 872 unsigned int lookaheadCount, 873 const USHORT lookahead[], 874 unsigned int lookupCount, 875 const LookupRecord lookupRecord[], 876 ChainContextApplyLookupContext &lookup_context) 877{ 878 unsigned int lookahead_offset; 879 return match_backtrack (c, 880 backtrackCount, backtrack, 881 lookup_context.funcs.match, lookup_context.match_data[0]) 882 && match_input (c, 883 inputCount, input, 884 lookup_context.funcs.match, lookup_context.match_data[1], 885 &lookahead_offset) 886 && match_lookahead (c, 887 lookaheadCount, lookahead, 888 lookup_context.funcs.match, lookup_context.match_data[2], 889 lookahead_offset) 890 && apply_lookup (c, 891 inputCount, 892 lookupCount, lookupRecord, 893 lookup_context.funcs.apply); 894} 895 896struct ChainRule 897{ 898 friend struct ChainRuleSet; 899 900 private: 901 902 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 903 { 904 TRACE_CLOSURE (); 905 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 906 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 907 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 908 chain_context_closure_lookup (c, 909 backtrack.len, backtrack.array, 910 input.len, input.array, 911 lookahead.len, lookahead.array, 912 lookup.len, lookup.array, 913 lookup_context); 914 } 915 916 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 917 { 918 TRACE_APPLY (); 919 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 920 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 921 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 922 return TRACE_RETURN (chain_context_apply_lookup (c, 923 backtrack.len, backtrack.array, 924 input.len, input.array, 925 lookahead.len, lookahead.array, lookup.len, 926 lookup.array, lookup_context)); 927 } 928 929 public: 930 inline bool sanitize (hb_sanitize_context_t *c) { 931 TRACE_SANITIZE (); 932 if (!backtrack.sanitize (c)) return TRACE_RETURN (false); 933 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 934 if (!input.sanitize (c)) return TRACE_RETURN (false); 935 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 936 if (!lookahead.sanitize (c)) return TRACE_RETURN (false); 937 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 938 return TRACE_RETURN (lookup.sanitize (c)); 939 } 940 941 private: 942 ArrayOf<USHORT> 943 backtrack; /* Array of backtracking values 944 * (to be matched before the input 945 * sequence) */ 946 HeadlessArrayOf<USHORT> 947 inputX; /* Array of input values (start with 948 * second glyph) */ 949 ArrayOf<USHORT> 950 lookaheadX; /* Array of lookahead values's (to be 951 * matched after the input sequence) */ 952 ArrayOf<LookupRecord> 953 lookupX; /* Array of LookupRecords--in 954 * design order) */ 955 public: 956 DEFINE_SIZE_MIN (8); 957}; 958 959struct ChainRuleSet 960{ 961 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 962 { 963 TRACE_CLOSURE (); 964 unsigned int num_rules = rule.len; 965 for (unsigned int i = 0; i < num_rules; i++) 966 (this+rule[i]).closure (c, lookup_context); 967 } 968 969 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 970 { 971 TRACE_APPLY (); 972 unsigned int num_rules = rule.len; 973 for (unsigned int i = 0; i < num_rules; i++) 974 if ((this+rule[i]).apply (c, lookup_context)) 975 return TRACE_RETURN (true); 976 977 return TRACE_RETURN (false); 978 } 979 980 inline bool sanitize (hb_sanitize_context_t *c) { 981 TRACE_SANITIZE (); 982 return TRACE_RETURN (rule.sanitize (c, this)); 983 } 984 985 private: 986 OffsetArrayOf<ChainRule> 987 rule; /* Array of ChainRule tables 988 * ordered by preference */ 989 public: 990 DEFINE_SIZE_ARRAY (2, rule); 991}; 992 993struct ChainContextFormat1 994{ 995 friend struct ChainContext; 996 997 private: 998 999 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1000 { 1001 TRACE_CLOSURE (); 1002 const Coverage &cov = (this+coverage); 1003 1004 struct ChainContextClosureLookupContext lookup_context = { 1005 {intersects_glyph, closure_func}, 1006 {NULL, NULL, NULL} 1007 }; 1008 1009 unsigned int count = ruleSet.len; 1010 for (unsigned int i = 0; i < count; i++) 1011 if (cov.intersects_coverage (c->glyphs, i)) { 1012 const ChainRuleSet &rule_set = this+ruleSet[i]; 1013 rule_set.closure (c, lookup_context); 1014 } 1015 } 1016 1017 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1018 { 1019 TRACE_APPLY (); 1020 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 1021 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1022 1023 const ChainRuleSet &rule_set = this+ruleSet[index]; 1024 struct ChainContextApplyLookupContext lookup_context = { 1025 {match_glyph, apply_func}, 1026 {NULL, NULL, NULL} 1027 }; 1028 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1029 } 1030 1031 inline bool sanitize (hb_sanitize_context_t *c) { 1032 TRACE_SANITIZE (); 1033 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1034 } 1035 1036 private: 1037 USHORT format; /* Format identifier--format = 1 */ 1038 OffsetTo<Coverage> 1039 coverage; /* Offset to Coverage table--from 1040 * beginning of table */ 1041 OffsetArrayOf<ChainRuleSet> 1042 ruleSet; /* Array of ChainRuleSet tables 1043 * ordered by Coverage Index */ 1044 public: 1045 DEFINE_SIZE_ARRAY (6, ruleSet); 1046}; 1047 1048struct ChainContextFormat2 1049{ 1050 friend struct ChainContext; 1051 1052 private: 1053 1054 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1055 { 1056 TRACE_CLOSURE (); 1057 if (!(this+coverage).intersects (c->glyphs)) 1058 return; 1059 1060 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1061 const ClassDef &input_class_def = this+inputClassDef; 1062 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1063 1064 struct ChainContextClosureLookupContext lookup_context = { 1065 {intersects_class, closure_func}, 1066 {&backtrack_class_def, 1067 &input_class_def, 1068 &lookahead_class_def} 1069 }; 1070 1071 unsigned int count = ruleSet.len; 1072 for (unsigned int i = 0; i < count; i++) 1073 if (input_class_def.intersects_class (c->glyphs, i)) { 1074 const ChainRuleSet &rule_set = this+ruleSet[i]; 1075 rule_set.closure (c, lookup_context); 1076 } 1077 } 1078 1079 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1080 { 1081 TRACE_APPLY (); 1082 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 1083 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1084 1085 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1086 const ClassDef &input_class_def = this+inputClassDef; 1087 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1088 1089 index = input_class_def (c->buffer->cur().codepoint); 1090 const ChainRuleSet &rule_set = this+ruleSet[index]; 1091 struct ChainContextApplyLookupContext lookup_context = { 1092 {match_class, apply_func}, 1093 {&backtrack_class_def, 1094 &input_class_def, 1095 &lookahead_class_def} 1096 }; 1097 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1098 } 1099 1100 inline bool sanitize (hb_sanitize_context_t *c) { 1101 TRACE_SANITIZE (); 1102 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 1103 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 1104 ruleSet.sanitize (c, this)); 1105 } 1106 1107 private: 1108 USHORT format; /* Format identifier--format = 2 */ 1109 OffsetTo<Coverage> 1110 coverage; /* Offset to Coverage table--from 1111 * beginning of table */ 1112 OffsetTo<ClassDef> 1113 backtrackClassDef; /* Offset to glyph ClassDef table 1114 * containing backtrack sequence 1115 * data--from beginning of table */ 1116 OffsetTo<ClassDef> 1117 inputClassDef; /* Offset to glyph ClassDef 1118 * table containing input sequence 1119 * data--from beginning of table */ 1120 OffsetTo<ClassDef> 1121 lookaheadClassDef; /* Offset to glyph ClassDef table 1122 * containing lookahead sequence 1123 * data--from beginning of table */ 1124 OffsetArrayOf<ChainRuleSet> 1125 ruleSet; /* Array of ChainRuleSet tables 1126 * ordered by class */ 1127 public: 1128 DEFINE_SIZE_ARRAY (12, ruleSet); 1129}; 1130 1131struct ChainContextFormat3 1132{ 1133 friend struct ChainContext; 1134 1135 private: 1136 1137 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1138 { 1139 TRACE_CLOSURE (); 1140 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1141 1142 if (!(this+input[0]).intersects (c->glyphs)) 1143 return; 1144 1145 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1146 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1147 struct ChainContextClosureLookupContext lookup_context = { 1148 {intersects_coverage, closure_func}, 1149 {this, this, this} 1150 }; 1151 chain_context_closure_lookup (c, 1152 backtrack.len, (const USHORT *) backtrack.array, 1153 input.len, (const USHORT *) input.array + 1, 1154 lookahead.len, (const USHORT *) lookahead.array, 1155 lookup.len, lookup.array, 1156 lookup_context); 1157 } 1158 1159 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1160 { 1161 TRACE_APPLY (); 1162 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1163 1164 unsigned int index = (this+input[0]) (c->buffer->cur().codepoint); 1165 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1166 1167 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1168 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1169 struct ChainContextApplyLookupContext lookup_context = { 1170 {match_coverage, apply_func}, 1171 {this, this, this} 1172 }; 1173 return TRACE_RETURN (chain_context_apply_lookup (c, 1174 backtrack.len, (const USHORT *) backtrack.array, 1175 input.len, (const USHORT *) input.array + 1, 1176 lookahead.len, (const USHORT *) lookahead.array, 1177 lookup.len, lookup.array, lookup_context)); 1178 } 1179 1180 inline bool sanitize (hb_sanitize_context_t *c) { 1181 TRACE_SANITIZE (); 1182 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 1183 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1184 if (!input.sanitize (c, this)) return TRACE_RETURN (false); 1185 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1186 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 1187 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1188 return TRACE_RETURN (lookup.sanitize (c)); 1189 } 1190 1191 private: 1192 USHORT format; /* Format identifier--format = 3 */ 1193 OffsetArrayOf<Coverage> 1194 backtrack; /* Array of coverage tables 1195 * in backtracking sequence, in glyph 1196 * sequence order */ 1197 OffsetArrayOf<Coverage> 1198 inputX ; /* Array of coverage 1199 * tables in input sequence, in glyph 1200 * sequence order */ 1201 OffsetArrayOf<Coverage> 1202 lookaheadX; /* Array of coverage tables 1203 * in lookahead sequence, in glyph 1204 * sequence order */ 1205 ArrayOf<LookupRecord> 1206 lookupX; /* Array of LookupRecords--in 1207 * design order) */ 1208 public: 1209 DEFINE_SIZE_MIN (10); 1210}; 1211 1212struct ChainContext 1213{ 1214 protected: 1215 1216 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1217 { 1218 TRACE_CLOSURE (); 1219 switch (u.format) { 1220 case 1: u.format1.closure (c, closure_func); break; 1221 case 2: u.format2.closure (c, closure_func); break; 1222 case 3: u.format3.closure (c, closure_func); break; 1223 default: break; 1224 } 1225 } 1226 1227 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1228 { 1229 TRACE_APPLY (); 1230 switch (u.format) { 1231 case 1: return TRACE_RETURN (u.format1.apply (c, apply_func)); 1232 case 2: return TRACE_RETURN (u.format2.apply (c, apply_func)); 1233 case 3: return TRACE_RETURN (u.format3.apply (c, apply_func)); 1234 default:return TRACE_RETURN (false); 1235 } 1236 } 1237 1238 inline bool sanitize (hb_sanitize_context_t *c) { 1239 TRACE_SANITIZE (); 1240 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1241 switch (u.format) { 1242 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1243 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1244 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1245 default:return TRACE_RETURN (true); 1246 } 1247 } 1248 1249 private: 1250 union { 1251 USHORT format; /* Format identifier */ 1252 ChainContextFormat1 format1; 1253 ChainContextFormat2 format2; 1254 ChainContextFormat3 format3; 1255 } u; 1256}; 1257 1258 1259struct ExtensionFormat1 1260{ 1261 friend struct Extension; 1262 1263 protected: 1264 inline unsigned int get_type (void) const { return extensionLookupType; } 1265 inline unsigned int get_offset (void) const { return extensionOffset; } 1266 1267 inline bool sanitize (hb_sanitize_context_t *c) { 1268 TRACE_SANITIZE (); 1269 return TRACE_RETURN (c->check_struct (this)); 1270 } 1271 1272 private: 1273 USHORT format; /* Format identifier. Set to 1. */ 1274 USHORT extensionLookupType; /* Lookup type of subtable referenced 1275 * by ExtensionOffset (i.e. the 1276 * extension subtable). */ 1277 ULONG extensionOffset; /* Offset to the extension subtable, 1278 * of lookup type subtable. */ 1279 public: 1280 DEFINE_SIZE_STATIC (8); 1281}; 1282 1283struct Extension 1284{ 1285 inline unsigned int get_type (void) const 1286 { 1287 switch (u.format) { 1288 case 1: return u.format1.get_type (); 1289 default:return 0; 1290 } 1291 } 1292 inline unsigned int get_offset (void) const 1293 { 1294 switch (u.format) { 1295 case 1: return u.format1.get_offset (); 1296 default:return 0; 1297 } 1298 } 1299 1300 inline bool sanitize (hb_sanitize_context_t *c) { 1301 TRACE_SANITIZE (); 1302 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1303 switch (u.format) { 1304 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1305 default:return TRACE_RETURN (true); 1306 } 1307 } 1308 1309 private: 1310 union { 1311 USHORT format; /* Format identifier */ 1312 ExtensionFormat1 format1; 1313 } u; 1314}; 1315 1316 1317/* 1318 * GSUB/GPOS Common 1319 */ 1320 1321struct GSUBGPOS 1322{ 1323 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 1324 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 1325 1326 inline unsigned int get_script_count (void) const 1327 { return (this+scriptList).len; } 1328 inline const Tag& get_script_tag (unsigned int i) const 1329 { return (this+scriptList).get_tag (i); } 1330 inline unsigned int get_script_tags (unsigned int start_offset, 1331 unsigned int *script_count /* IN/OUT */, 1332 hb_tag_t *script_tags /* OUT */) const 1333 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 1334 inline const Script& get_script (unsigned int i) const 1335 { return (this+scriptList)[i]; } 1336 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 1337 { return (this+scriptList).find_index (tag, index); } 1338 1339 inline unsigned int get_feature_count (void) const 1340 { return (this+featureList).len; } 1341 inline const Tag& get_feature_tag (unsigned int i) const 1342 { return (this+featureList).get_tag (i); } 1343 inline unsigned int get_feature_tags (unsigned int start_offset, 1344 unsigned int *feature_count /* IN/OUT */, 1345 hb_tag_t *feature_tags /* OUT */) const 1346 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 1347 inline const Feature& get_feature (unsigned int i) const 1348 { return (this+featureList)[i]; } 1349 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 1350 { return (this+featureList).find_index (tag, index); } 1351 1352 inline unsigned int get_lookup_count (void) const 1353 { return (this+lookupList).len; } 1354 inline const Lookup& get_lookup (unsigned int i) const 1355 { return (this+lookupList)[i]; } 1356 1357 inline bool sanitize (hb_sanitize_context_t *c) { 1358 TRACE_SANITIZE (); 1359 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 1360 scriptList.sanitize (c, this) && 1361 featureList.sanitize (c, this) && 1362 lookupList.sanitize (c, this)); 1363 } 1364 1365 protected: 1366 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 1367 * to 0x00010000 */ 1368 OffsetTo<ScriptList> 1369 scriptList; /* ScriptList table */ 1370 OffsetTo<FeatureList> 1371 featureList; /* FeatureList table */ 1372 OffsetTo<LookupList> 1373 lookupList; /* LookupList table */ 1374 public: 1375 DEFINE_SIZE_STATIC (10); 1376}; 1377 1378 1379 1380#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 1381