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