hb-ot-layout-gsubgpos-private.hh revision 1f2bb172fe9a173ecfd61054f1fdd850943ef059
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 46struct hb_closure_context_t 47{ 48 hb_face_t *face; 49 hb_set_t *glyphs; 50 unsigned int nesting_level_left; 51 unsigned int debug_depth; 52 53 54 hb_closure_context_t (hb_face_t *face_, 55 hb_set_t *glyphs_, 56 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 57 face (face_), 58 glyphs (glyphs_), 59 nesting_level_left (nesting_level_left_), 60 debug_depth (0) {} 61}; 62 63 64 65/* TODO Add TRACE_RETURN annotation to gsub. */ 66#ifndef HB_DEBUG_WOULD_APPLY 67#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) 68#endif 69 70#define TRACE_WOULD_APPLY() \ 71 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY> trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "%d glyphs", c->len); 72 73 74struct hb_would_apply_context_t 75{ 76 hb_face_t *face; 77 const hb_codepoint_t *glyphs; 78 unsigned int len; 79 const hb_set_digest_t digest; 80 unsigned int debug_depth; 81 82 hb_would_apply_context_t (hb_face_t *face_, 83 const hb_codepoint_t *glyphs_, 84 unsigned int len_, 85 const hb_set_digest_t *digest_ 86 ) : 87 face (face_), 88 glyphs (glyphs_), 89 len (len_), 90 digest (*digest_), 91 debug_depth (0) {}; 92}; 93 94 95#ifndef HB_DEBUG_APPLY 96#define HB_DEBUG_APPLY (HB_DEBUG+0) 97#endif 98 99#define TRACE_APPLY() \ 100 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); 101 102 103struct hb_apply_context_t 104{ 105 hb_font_t *font; 106 hb_face_t *face; 107 hb_buffer_t *buffer; 108 hb_direction_t direction; 109 hb_mask_t lookup_mask; 110 unsigned int nesting_level_left; 111 unsigned int lookup_props; 112 unsigned int property; /* propety of first glyph */ 113 unsigned int debug_depth; 114 const GDEF &gdef; 115 bool has_glyph_classes; 116 const hb_set_digest_t digest; 117 118 119 hb_apply_context_t (hb_font_t *font_, 120 hb_buffer_t *buffer_, 121 hb_mask_t lookup_mask_, 122 const hb_set_digest_t *digest_) : 123 font (font_), face (font->face), buffer (buffer_), 124 direction (buffer_->props.direction), 125 lookup_mask (lookup_mask_), 126 nesting_level_left (MAX_NESTING_LEVEL), 127 lookup_props (0), property (0), debug_depth (0), 128 gdef (*hb_ot_layout_from_face (face)->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->glyphs[i], 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->glyphs[0])]; 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->glyphs[0]); 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 (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); 932 for (unsigned int i = 0; i < count; i++) 933 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); 934 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 935 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); 936 } 937 938 protected: 939 USHORT format; /* Format identifier--format = 3 */ 940 USHORT glyphCount; /* Number of glyphs in the input glyph 941 * sequence */ 942 USHORT lookupCount; /* Number of LookupRecords */ 943 OffsetTo<Coverage> 944 coverage[VAR]; /* Array of offsets to Coverage 945 * table in glyph sequence order */ 946 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 947 * design order */ 948 public: 949 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 950}; 951 952struct Context 953{ 954 protected: 955 956 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 957 { 958 TRACE_CLOSURE (); 959 switch (u.format) { 960 case 1: u.format1.closure (c, closure_func); break; 961 case 2: u.format2.closure (c, closure_func); break; 962 case 3: u.format3.closure (c, closure_func); break; 963 default: break; 964 } 965 } 966 967 inline const Coverage &get_coverage (void) const 968 { 969 switch (u.format) { 970 case 1: return this + u.format1.coverage; 971 case 2: return this + u.format2.coverage; 972 case 3: return this + u.format3.coverage[0]; 973 default:return Null(Coverage); 974 } 975 } 976 977 inline bool would_apply (hb_would_apply_context_t *c) const 978 { 979 switch (u.format) { 980 case 1: return u.format1.would_apply (c); 981 case 2: return u.format2.would_apply (c); 982 case 3: return u.format3.would_apply (c); 983 default:return false; 984 } 985 } 986 987 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 988 { 989 TRACE_APPLY (); 990 switch (u.format) { 991 case 1: return TRACE_RETURN (u.format1.apply (c, apply_func)); 992 case 2: return TRACE_RETURN (u.format2.apply (c, apply_func)); 993 case 3: return TRACE_RETURN (u.format3.apply (c, apply_func)); 994 default:return TRACE_RETURN (false); 995 } 996 } 997 998 inline bool sanitize (hb_sanitize_context_t *c) { 999 TRACE_SANITIZE (); 1000 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1001 switch (u.format) { 1002 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1003 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1004 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1005 default:return TRACE_RETURN (true); 1006 } 1007 } 1008 1009 protected: 1010 union { 1011 USHORT format; /* Format identifier */ 1012 ContextFormat1 format1; 1013 ContextFormat2 format2; 1014 ContextFormat3 format3; 1015 } u; 1016}; 1017 1018 1019/* Chaining Contextual lookups */ 1020 1021struct ChainContextClosureLookupContext 1022{ 1023 ContextClosureFuncs funcs; 1024 const void *intersects_data[3]; 1025}; 1026 1027struct ChainContextApplyLookupContext 1028{ 1029 ContextApplyFuncs funcs; 1030 const void *match_data[3]; 1031}; 1032 1033static inline void chain_context_closure_lookup (hb_closure_context_t *c, 1034 unsigned int backtrackCount, 1035 const USHORT backtrack[], 1036 unsigned int inputCount, /* Including the first glyph (not matched) */ 1037 const USHORT input[], /* Array of input values--start with second glyph */ 1038 unsigned int lookaheadCount, 1039 const USHORT lookahead[], 1040 unsigned int lookupCount, 1041 const LookupRecord lookupRecord[], 1042 ChainContextClosureLookupContext &lookup_context) 1043{ 1044 if (intersects_array (c, 1045 backtrackCount, backtrack, 1046 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 1047 && intersects_array (c, 1048 inputCount ? inputCount - 1 : 0, input, 1049 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 1050 && intersects_array (c, 1051 lookaheadCount, lookahead, 1052 lookup_context.funcs.intersects, lookup_context.intersects_data[2])) 1053 closure_lookup (c, 1054 lookupCount, lookupRecord, 1055 lookup_context.funcs.closure); 1056} 1057 1058static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, 1059 unsigned int backtrackCount, 1060 const USHORT backtrack[], 1061 unsigned int inputCount, /* Including the first glyph (not matched) */ 1062 const USHORT input[], /* Array of input values--start with second glyph */ 1063 unsigned int lookaheadCount, 1064 const USHORT lookahead[], 1065 unsigned int lookupCount, 1066 const LookupRecord lookupRecord[], 1067 ChainContextApplyLookupContext &lookup_context) 1068{ 1069 return !backtrackCount 1070 && !lookaheadCount 1071 && would_match_input (c, 1072 inputCount, input, 1073 lookup_context.funcs.match, lookup_context.match_data[1]); 1074} 1075 1076static inline bool chain_context_apply_lookup (hb_apply_context_t *c, 1077 unsigned int backtrackCount, 1078 const USHORT backtrack[], 1079 unsigned int inputCount, /* Including the first glyph (not matched) */ 1080 const USHORT input[], /* Array of input values--start with second glyph */ 1081 unsigned int lookaheadCount, 1082 const USHORT lookahead[], 1083 unsigned int lookupCount, 1084 const LookupRecord lookupRecord[], 1085 ChainContextApplyLookupContext &lookup_context) 1086{ 1087 unsigned int lookahead_offset; 1088 return match_input (c, 1089 inputCount, input, 1090 lookup_context.funcs.match, lookup_context.match_data[1], 1091 &lookahead_offset) 1092 && match_backtrack (c, 1093 backtrackCount, backtrack, 1094 lookup_context.funcs.match, lookup_context.match_data[0]) 1095 && match_lookahead (c, 1096 lookaheadCount, lookahead, 1097 lookup_context.funcs.match, lookup_context.match_data[2], 1098 lookahead_offset) 1099 && apply_lookup (c, 1100 inputCount, 1101 lookupCount, lookupRecord, 1102 lookup_context.funcs.apply); 1103} 1104 1105struct ChainRule 1106{ 1107 friend struct ChainRuleSet; 1108 1109 private: 1110 1111 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1112 { 1113 TRACE_CLOSURE (); 1114 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1115 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1116 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1117 chain_context_closure_lookup (c, 1118 backtrack.len, backtrack.array, 1119 input.len, input.array, 1120 lookahead.len, lookahead.array, 1121 lookup.len, lookup.array, 1122 lookup_context); 1123 } 1124 1125 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1126 { 1127 TRACE_WOULD_APPLY (); 1128 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1129 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1130 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1131 return TRACE_RETURN (chain_context_would_apply_lookup (c, 1132 backtrack.len, backtrack.array, 1133 input.len, input.array, 1134 lookahead.len, lookahead.array, lookup.len, 1135 lookup.array, lookup_context)); 1136 } 1137 1138 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1139 { 1140 TRACE_APPLY (); 1141 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1142 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1143 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1144 return TRACE_RETURN (chain_context_apply_lookup (c, 1145 backtrack.len, backtrack.array, 1146 input.len, input.array, 1147 lookahead.len, lookahead.array, lookup.len, 1148 lookup.array, lookup_context)); 1149 } 1150 1151 public: 1152 inline bool sanitize (hb_sanitize_context_t *c) { 1153 TRACE_SANITIZE (); 1154 if (!backtrack.sanitize (c)) return TRACE_RETURN (false); 1155 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1156 if (!input.sanitize (c)) return TRACE_RETURN (false); 1157 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1158 if (!lookahead.sanitize (c)) return TRACE_RETURN (false); 1159 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1160 return TRACE_RETURN (lookup.sanitize (c)); 1161 } 1162 1163 protected: 1164 ArrayOf<USHORT> 1165 backtrack; /* Array of backtracking values 1166 * (to be matched before the input 1167 * sequence) */ 1168 HeadlessArrayOf<USHORT> 1169 inputX; /* Array of input values (start with 1170 * second glyph) */ 1171 ArrayOf<USHORT> 1172 lookaheadX; /* Array of lookahead values's (to be 1173 * matched after the input sequence) */ 1174 ArrayOf<LookupRecord> 1175 lookupX; /* Array of LookupRecords--in 1176 * design order) */ 1177 public: 1178 DEFINE_SIZE_MIN (8); 1179}; 1180 1181struct ChainRuleSet 1182{ 1183 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1184 { 1185 TRACE_CLOSURE (); 1186 unsigned int num_rules = rule.len; 1187 for (unsigned int i = 0; i < num_rules; i++) 1188 (this+rule[i]).closure (c, lookup_context); 1189 } 1190 1191 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1192 { 1193 TRACE_WOULD_APPLY (); 1194 unsigned int num_rules = rule.len; 1195 for (unsigned int i = 0; i < num_rules; i++) 1196 if ((this+rule[i]).would_apply (c, lookup_context)) 1197 return TRACE_RETURN (true); 1198 1199 return TRACE_RETURN (false); 1200 } 1201 1202 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1203 { 1204 TRACE_APPLY (); 1205 unsigned int num_rules = rule.len; 1206 for (unsigned int i = 0; i < num_rules; i++) 1207 if ((this+rule[i]).apply (c, lookup_context)) 1208 return TRACE_RETURN (true); 1209 1210 return TRACE_RETURN (false); 1211 } 1212 1213 inline bool sanitize (hb_sanitize_context_t *c) { 1214 TRACE_SANITIZE (); 1215 return TRACE_RETURN (rule.sanitize (c, this)); 1216 } 1217 1218 protected: 1219 OffsetArrayOf<ChainRule> 1220 rule; /* Array of ChainRule tables 1221 * ordered by preference */ 1222 public: 1223 DEFINE_SIZE_ARRAY (2, rule); 1224}; 1225 1226struct ChainContextFormat1 1227{ 1228 friend struct ChainContext; 1229 1230 private: 1231 1232 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1233 { 1234 TRACE_CLOSURE (); 1235 const Coverage &cov = (this+coverage); 1236 1237 struct ChainContextClosureLookupContext lookup_context = { 1238 {intersects_glyph, closure_func}, 1239 {NULL, NULL, NULL} 1240 }; 1241 1242 unsigned int count = ruleSet.len; 1243 for (unsigned int i = 0; i < count; i++) 1244 if (cov.intersects_coverage (c->glyphs, i)) { 1245 const ChainRuleSet &rule_set = this+ruleSet[i]; 1246 rule_set.closure (c, lookup_context); 1247 } 1248 } 1249 1250 inline bool would_apply (hb_would_apply_context_t *c) const 1251 { 1252 TRACE_WOULD_APPLY (); 1253 1254 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])]; 1255 struct ChainContextApplyLookupContext lookup_context = { 1256 {match_glyph, NULL}, 1257 {NULL, NULL, 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 ChainRuleSet &rule_set = this+ruleSet[index]; 1269 struct ChainContextApplyLookupContext lookup_context = { 1270 {match_glyph, apply_func}, 1271 {NULL, NULL, NULL} 1272 }; 1273 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1274 } 1275 1276 inline bool sanitize (hb_sanitize_context_t *c) { 1277 TRACE_SANITIZE (); 1278 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1279 } 1280 1281 protected: 1282 USHORT format; /* Format identifier--format = 1 */ 1283 OffsetTo<Coverage> 1284 coverage; /* Offset to Coverage table--from 1285 * beginning of table */ 1286 OffsetArrayOf<ChainRuleSet> 1287 ruleSet; /* Array of ChainRuleSet tables 1288 * ordered by Coverage Index */ 1289 public: 1290 DEFINE_SIZE_ARRAY (6, ruleSet); 1291}; 1292 1293struct ChainContextFormat2 1294{ 1295 friend struct ChainContext; 1296 1297 private: 1298 1299 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1300 { 1301 TRACE_CLOSURE (); 1302 if (!(this+coverage).intersects (c->glyphs)) 1303 return; 1304 1305 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1306 const ClassDef &input_class_def = this+inputClassDef; 1307 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1308 1309 struct ChainContextClosureLookupContext lookup_context = { 1310 {intersects_class, closure_func}, 1311 {&backtrack_class_def, 1312 &input_class_def, 1313 &lookahead_class_def} 1314 }; 1315 1316 unsigned int count = ruleSet.len; 1317 for (unsigned int i = 0; i < count; i++) 1318 if (input_class_def.intersects_class (c->glyphs, i)) { 1319 const ChainRuleSet &rule_set = this+ruleSet[i]; 1320 rule_set.closure (c, lookup_context); 1321 } 1322 } 1323 1324 inline bool would_apply (hb_would_apply_context_t *c) const 1325 { 1326 TRACE_WOULD_APPLY (); 1327 1328 const ClassDef &input_class_def = this+inputClassDef; 1329 1330 unsigned int index = input_class_def (c->glyphs[0]); 1331 const ChainRuleSet &rule_set = this+ruleSet[index]; 1332 struct ChainContextApplyLookupContext lookup_context = { 1333 {match_class, NULL}, 1334 {NULL, &input_class_def, NULL} 1335 }; 1336 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1337 } 1338 1339 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1340 { 1341 TRACE_APPLY (); 1342 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 1343 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1344 1345 const ClassDef &backtrack_class_def = this+backtrackClassDef; 1346 const ClassDef &input_class_def = this+inputClassDef; 1347 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1348 1349 index = input_class_def (c->buffer->cur().codepoint); 1350 const ChainRuleSet &rule_set = this+ruleSet[index]; 1351 struct ChainContextApplyLookupContext lookup_context = { 1352 {match_class, apply_func}, 1353 {&backtrack_class_def, 1354 &input_class_def, 1355 &lookahead_class_def} 1356 }; 1357 return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1358 } 1359 1360 inline bool sanitize (hb_sanitize_context_t *c) { 1361 TRACE_SANITIZE (); 1362 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 1363 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 1364 ruleSet.sanitize (c, this)); 1365 } 1366 1367 protected: 1368 USHORT format; /* Format identifier--format = 2 */ 1369 OffsetTo<Coverage> 1370 coverage; /* Offset to Coverage table--from 1371 * beginning of table */ 1372 OffsetTo<ClassDef> 1373 backtrackClassDef; /* Offset to glyph ClassDef table 1374 * containing backtrack sequence 1375 * data--from beginning of table */ 1376 OffsetTo<ClassDef> 1377 inputClassDef; /* Offset to glyph ClassDef 1378 * table containing input sequence 1379 * data--from beginning of table */ 1380 OffsetTo<ClassDef> 1381 lookaheadClassDef; /* Offset to glyph ClassDef table 1382 * containing lookahead sequence 1383 * data--from beginning of table */ 1384 OffsetArrayOf<ChainRuleSet> 1385 ruleSet; /* Array of ChainRuleSet tables 1386 * ordered by class */ 1387 public: 1388 DEFINE_SIZE_ARRAY (12, ruleSet); 1389}; 1390 1391struct ChainContextFormat3 1392{ 1393 friend struct ChainContext; 1394 1395 private: 1396 1397 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1398 { 1399 TRACE_CLOSURE (); 1400 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1401 1402 if (!(this+input[0]).intersects (c->glyphs)) 1403 return; 1404 1405 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1406 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1407 struct ChainContextClosureLookupContext lookup_context = { 1408 {intersects_coverage, closure_func}, 1409 {this, this, this} 1410 }; 1411 chain_context_closure_lookup (c, 1412 backtrack.len, (const USHORT *) backtrack.array, 1413 input.len, (const USHORT *) input.array + 1, 1414 lookahead.len, (const USHORT *) lookahead.array, 1415 lookup.len, lookup.array, 1416 lookup_context); 1417 } 1418 1419 inline const Coverage &get_coverage (void) const 1420 { 1421 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1422 return this+input[0]; 1423 } 1424 1425 inline bool would_apply (hb_would_apply_context_t *c) const 1426 { 1427 TRACE_WOULD_APPLY (); 1428 1429 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1430 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1431 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1432 struct ChainContextApplyLookupContext lookup_context = { 1433 {match_coverage, NULL}, 1434 {this, this, this} 1435 }; 1436 return TRACE_RETURN (chain_context_would_apply_lookup (c, 1437 backtrack.len, (const USHORT *) backtrack.array, 1438 input.len, (const USHORT *) input.array + 1, 1439 lookahead.len, (const USHORT *) lookahead.array, 1440 lookup.len, lookup.array, lookup_context)); 1441 } 1442 1443 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1444 { 1445 TRACE_APPLY (); 1446 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1447 1448 unsigned int index = (this+input[0]) (c->buffer->cur().codepoint); 1449 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1450 1451 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1452 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1453 struct ChainContextApplyLookupContext lookup_context = { 1454 {match_coverage, apply_func}, 1455 {this, this, this} 1456 }; 1457 return TRACE_RETURN (chain_context_apply_lookup (c, 1458 backtrack.len, (const USHORT *) backtrack.array, 1459 input.len, (const USHORT *) input.array + 1, 1460 lookahead.len, (const USHORT *) lookahead.array, 1461 lookup.len, lookup.array, lookup_context)); 1462 } 1463 1464 inline bool sanitize (hb_sanitize_context_t *c) { 1465 TRACE_SANITIZE (); 1466 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 1467 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1468 if (!input.sanitize (c, this)) return TRACE_RETURN (false); 1469 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1470 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 1471 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1472 return TRACE_RETURN (lookup.sanitize (c)); 1473 } 1474 1475 protected: 1476 USHORT format; /* Format identifier--format = 3 */ 1477 OffsetArrayOf<Coverage> 1478 backtrack; /* Array of coverage tables 1479 * in backtracking sequence, in glyph 1480 * sequence order */ 1481 OffsetArrayOf<Coverage> 1482 inputX ; /* Array of coverage 1483 * tables in input sequence, in glyph 1484 * sequence order */ 1485 OffsetArrayOf<Coverage> 1486 lookaheadX; /* Array of coverage tables 1487 * in lookahead sequence, in glyph 1488 * sequence order */ 1489 ArrayOf<LookupRecord> 1490 lookupX; /* Array of LookupRecords--in 1491 * design order) */ 1492 public: 1493 DEFINE_SIZE_MIN (10); 1494}; 1495 1496struct ChainContext 1497{ 1498 protected: 1499 1500 inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const 1501 { 1502 TRACE_CLOSURE (); 1503 switch (u.format) { 1504 case 1: u.format1.closure (c, closure_func); break; 1505 case 2: u.format2.closure (c, closure_func); break; 1506 case 3: u.format3.closure (c, closure_func); break; 1507 default: break; 1508 } 1509 } 1510 1511 inline const Coverage &get_coverage (void) const 1512 { 1513 switch (u.format) { 1514 case 1: return this + u.format1.coverage; 1515 case 2: return this + u.format2.coverage; 1516 case 3: return u.format3.get_coverage (); 1517 default:return Null(Coverage); 1518 } 1519 } 1520 1521 inline bool would_apply (hb_would_apply_context_t *c) const 1522 { 1523 switch (u.format) { 1524 case 1: return u.format1.would_apply (c); 1525 case 2: return u.format2.would_apply (c); 1526 case 3: return u.format3.would_apply (c); 1527 default:return false; 1528 } 1529 } 1530 1531 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 1532 { 1533 TRACE_APPLY (); 1534 switch (u.format) { 1535 case 1: return TRACE_RETURN (u.format1.apply (c, apply_func)); 1536 case 2: return TRACE_RETURN (u.format2.apply (c, apply_func)); 1537 case 3: return TRACE_RETURN (u.format3.apply (c, apply_func)); 1538 default:return TRACE_RETURN (false); 1539 } 1540 } 1541 1542 inline bool sanitize (hb_sanitize_context_t *c) { 1543 TRACE_SANITIZE (); 1544 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1545 switch (u.format) { 1546 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1547 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1548 case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1549 default:return TRACE_RETURN (true); 1550 } 1551 } 1552 1553 protected: 1554 union { 1555 USHORT format; /* Format identifier */ 1556 ChainContextFormat1 format1; 1557 ChainContextFormat2 format2; 1558 ChainContextFormat3 format3; 1559 } u; 1560}; 1561 1562 1563struct ExtensionFormat1 1564{ 1565 friend struct Extension; 1566 1567 protected: 1568 inline unsigned int get_type (void) const { return extensionLookupType; } 1569 inline unsigned int get_offset (void) const { return extensionOffset; } 1570 1571 inline bool sanitize (hb_sanitize_context_t *c) { 1572 TRACE_SANITIZE (); 1573 return TRACE_RETURN (c->check_struct (this)); 1574 } 1575 1576 protected: 1577 USHORT format; /* Format identifier. Set to 1. */ 1578 USHORT extensionLookupType; /* Lookup type of subtable referenced 1579 * by ExtensionOffset (i.e. the 1580 * extension subtable). */ 1581 ULONG extensionOffset; /* Offset to the extension subtable, 1582 * of lookup type subtable. */ 1583 public: 1584 DEFINE_SIZE_STATIC (8); 1585}; 1586 1587struct Extension 1588{ 1589 inline unsigned int get_type (void) const 1590 { 1591 switch (u.format) { 1592 case 1: return u.format1.get_type (); 1593 default:return 0; 1594 } 1595 } 1596 inline unsigned int get_offset (void) const 1597 { 1598 switch (u.format) { 1599 case 1: return u.format1.get_offset (); 1600 default:return 0; 1601 } 1602 } 1603 1604 inline bool sanitize (hb_sanitize_context_t *c) { 1605 TRACE_SANITIZE (); 1606 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1607 switch (u.format) { 1608 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1609 default:return TRACE_RETURN (true); 1610 } 1611 } 1612 1613 protected: 1614 union { 1615 USHORT format; /* Format identifier */ 1616 ExtensionFormat1 format1; 1617 } u; 1618}; 1619 1620 1621/* 1622 * GSUB/GPOS Common 1623 */ 1624 1625struct GSUBGPOS 1626{ 1627 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 1628 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 1629 1630 inline unsigned int get_script_count (void) const 1631 { return (this+scriptList).len; } 1632 inline const Tag& get_script_tag (unsigned int i) const 1633 { return (this+scriptList).get_tag (i); } 1634 inline unsigned int get_script_tags (unsigned int start_offset, 1635 unsigned int *script_count /* IN/OUT */, 1636 hb_tag_t *script_tags /* OUT */) const 1637 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 1638 inline const Script& get_script (unsigned int i) const 1639 { return (this+scriptList)[i]; } 1640 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 1641 { return (this+scriptList).find_index (tag, index); } 1642 1643 inline unsigned int get_feature_count (void) const 1644 { return (this+featureList).len; } 1645 inline const Tag& get_feature_tag (unsigned int i) const 1646 { return (this+featureList).get_tag (i); } 1647 inline unsigned int get_feature_tags (unsigned int start_offset, 1648 unsigned int *feature_count /* IN/OUT */, 1649 hb_tag_t *feature_tags /* OUT */) const 1650 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 1651 inline const Feature& get_feature (unsigned int i) const 1652 { return (this+featureList)[i]; } 1653 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 1654 { return (this+featureList).find_index (tag, index); } 1655 1656 inline unsigned int get_lookup_count (void) const 1657 { return (this+lookupList).len; } 1658 inline const Lookup& get_lookup (unsigned int i) const 1659 { return (this+lookupList)[i]; } 1660 1661 inline bool sanitize (hb_sanitize_context_t *c) { 1662 TRACE_SANITIZE (); 1663 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 1664 scriptList.sanitize (c, this) && 1665 featureList.sanitize (c, this) && 1666 lookupList.sanitize (c, this)); 1667 } 1668 1669 protected: 1670 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 1671 * to 0x00010000 */ 1672 OffsetTo<ScriptList> 1673 scriptList; /* ScriptList table */ 1674 OffsetTo<FeatureList> 1675 featureList; /* FeatureList table */ 1676 OffsetTo<LookupList> 1677 lookupList; /* LookupList table */ 1678 public: 1679 DEFINE_SIZE_STATIC (10); 1680}; 1681 1682 1683 1684#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 1685