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