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