hb-ot-layout-gsubgpos-private.hh revision c605bbbb6d4b2a98b1f40ca818760088d991f7d1
1/* 2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 3 * Copyright © 2010 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-private.hh" 34 35 36/* buffer var allocations */ 37#define lig_id() var2.u8[2] /* unique ligature id */ 38#define lig_comp() var2.u8[3] /* component number in the ligature (0 = base) */ 39 40static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) { 41 uint8_t lig_id = buffer->next_serial (); 42 if (unlikely (!lig_id)) lig_id = buffer->next_serial (); /* in case of overflow */ 43 return lig_id; 44} 45 46 47 48#ifndef HB_DEBUG_APPLY 49#define HB_DEBUG_APPLY (HB_DEBUG+0) 50#endif 51 52#define TRACE_APPLY() \ 53 hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, NULL, HB_FUNC); 54 55 56 57struct hb_apply_context_t 58{ 59 unsigned int debug_depth; 60 hb_font_t *font; 61 hb_face_t *face; 62 hb_buffer_t *buffer; 63 hb_direction_t direction; 64 hb_mask_t lookup_mask; 65 unsigned int context_length; 66 unsigned int nesting_level_left; 67 unsigned int lookup_props; 68 unsigned int property; /* propety of first glyph */ 69 70 71 inline void replace_glyph (hb_codepoint_t glyph_index) const 72 { 73 clear_property (); 74 buffer->replace_glyph (glyph_index); 75 } 76 inline void replace_glyphs_be16 (unsigned int num_in, 77 unsigned int num_out, 78 const uint16_t *glyph_data_be) const 79 { 80 clear_property (); 81 buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be); 82 } 83 84 inline void guess_glyph_class (unsigned int klass) 85 { 86 /* XXX if ! has gdef */ 87 buffer->info[buffer->idx].props_cache() = klass; 88 } 89 90 private: 91 inline void clear_property (void) const 92 { 93 /* XXX if has gdef */ 94 buffer->info[buffer->idx].props_cache() = 0; 95 } 96}; 97 98 99 100typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 101typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index); 102 103struct ContextFuncs 104{ 105 match_func_t match; 106 apply_lookup_func_t apply; 107}; 108 109 110static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) 111{ 112 return glyph_id == value; 113} 114 115static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 116{ 117 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 118 return class_def.get_class (glyph_id) == value; 119} 120 121static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 122{ 123 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 124 return (data+coverage) (glyph_id) != NOT_COVERED; 125} 126 127 128static inline bool match_input (hb_apply_context_t *c, 129 unsigned int count, /* Including the first glyph (not matched) */ 130 const USHORT input[], /* Array of input values--start with second glyph */ 131 match_func_t match_func, 132 const void *match_data, 133 unsigned int *context_length_out) 134{ 135 unsigned int i, j; 136 unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length); 137 if (unlikely (c->buffer->idx + count > end)) 138 return false; 139 140 for (i = 1, j = c->buffer->idx + 1; i < count; i++, j++) 141 { 142 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL)) 143 { 144 if (unlikely (j + count - i == end)) 145 return false; 146 j++; 147 } 148 149 if (likely (!match_func (c->buffer->info[j].codepoint, input[i - 1], match_data))) 150 return false; 151 } 152 153 *context_length_out = j - c->buffer->idx; 154 155 return true; 156} 157 158static inline bool match_backtrack (hb_apply_context_t *c, 159 unsigned int count, 160 const USHORT backtrack[], 161 match_func_t match_func, 162 const void *match_data) 163{ 164 if (unlikely (c->buffer->backtrack_len () < count)) 165 return false; 166 167 for (unsigned int i = 0, j = c->buffer->backtrack_len () - 1; i < count; i++, j--) 168 { 169 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[j], c->lookup_props, NULL)) 170 { 171 if (unlikely (j + 1 == count - i)) 172 return false; 173 j--; 174 } 175 176 if (likely (!match_func (c->buffer->out_info[j].codepoint, backtrack[i], match_data))) 177 return false; 178 } 179 180 return true; 181} 182 183static inline bool match_lookahead (hb_apply_context_t *c, 184 unsigned int count, 185 const USHORT lookahead[], 186 match_func_t match_func, 187 const void *match_data, 188 unsigned int offset) 189{ 190 unsigned int i, j; 191 unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length); 192 if (unlikely (c->buffer->idx + offset + count > end)) 193 return false; 194 195 for (i = 0, j = c->buffer->idx + offset; i < count; i++, j++) 196 { 197 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[j], c->lookup_props, NULL)) 198 { 199 if (unlikely (j + count - i == end)) 200 return false; 201 j++; 202 } 203 204 if (likely (!match_func (c->buffer->info[j].codepoint, lookahead[i], match_data))) 205 return false; 206 } 207 208 return true; 209} 210 211 212 213struct LookupRecord 214{ 215 inline bool sanitize (hb_sanitize_context_t *c) { 216 TRACE_SANITIZE (); 217 return c->check_struct (this); 218 } 219 220 USHORT sequenceIndex; /* Index into current glyph 221 * sequence--first glyph = 0 */ 222 USHORT lookupListIndex; /* Lookup to apply to that 223 * position--zero--based */ 224 public: 225 DEFINE_SIZE_STATIC (4); 226}; 227 228 229 230static inline bool apply_lookup (hb_apply_context_t *c, 231 unsigned int count, /* Including the first glyph */ 232 unsigned int lookupCount, 233 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 234 apply_lookup_func_t apply_func) 235{ 236 unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length); 237 if (unlikely (count == 0 || c->buffer->idx + count > end)) 238 return false; 239 240 /* TODO We don't support lookupRecord arrays that are not increasing: 241 * Should be easy for in_place ones at least. */ 242 243 /* Note: If sublookup is reverse, it will underflow after the first loop 244 * and we jump out of it. Not entirely disastrous. So we don't check 245 * for reverse lookup here. 246 */ 247 for (unsigned int i = 0; i < count; /* NOP */) 248 { 249 while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, NULL)) 250 { 251 if (unlikely (c->buffer->idx == end)) 252 return true; 253 /* No lookup applied for this index */ 254 c->buffer->next_glyph (); 255 } 256 257 if (lookupCount && i == lookupRecord->sequenceIndex) 258 { 259 unsigned int old_pos = c->buffer->idx; 260 261 /* Apply a lookup */ 262 bool done = apply_func (c, lookupRecord->lookupListIndex); 263 264 lookupRecord++; 265 lookupCount--; 266 /* Err, this is wrong if the lookup jumped over some glyphs */ 267 i += c->buffer->idx - old_pos; 268 if (unlikely (c->buffer->idx == end)) 269 return true; 270 271 if (!done) 272 goto not_applied; 273 } 274 else 275 { 276 not_applied: 277 /* No lookup applied for this index */ 278 c->buffer->next_glyph (); 279 i++; 280 } 281 } 282 283 return true; 284} 285 286 287 288/* Contextual lookups */ 289 290struct ContextLookupContext 291{ 292 ContextFuncs funcs; 293 const void *match_data; 294}; 295 296static inline bool context_lookup (hb_apply_context_t *c, 297 unsigned int inputCount, /* Including the first glyph (not matched) */ 298 const USHORT input[], /* Array of input values--start with second glyph */ 299 unsigned int lookupCount, 300 const LookupRecord lookupRecord[], 301 ContextLookupContext &lookup_context) 302{ 303 hb_apply_context_t new_context = *c; 304 return match_input (c, 305 inputCount, input, 306 lookup_context.funcs.match, lookup_context.match_data, 307 &new_context.context_length) 308 && apply_lookup (&new_context, 309 inputCount, 310 lookupCount, lookupRecord, 311 lookup_context.funcs.apply); 312} 313 314struct Rule 315{ 316 friend struct RuleSet; 317 318 private: 319 inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const 320 { 321 TRACE_APPLY (); 322 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 323 return context_lookup (c, 324 inputCount, input, 325 lookupCount, lookupRecord, 326 lookup_context); 327 } 328 329 public: 330 inline bool sanitize (hb_sanitize_context_t *c) { 331 TRACE_SANITIZE (); 332 return inputCount.sanitize (c) 333 && lookupCount.sanitize (c) 334 && c->check_range (input, 335 input[0].static_size * inputCount 336 + lookupRecordX[0].static_size * lookupCount); 337 } 338 339 private: 340 USHORT inputCount; /* Total number of glyphs in input 341 * glyph sequence--includes the first 342 * glyph */ 343 USHORT lookupCount; /* Number of LookupRecords */ 344 USHORT input[VAR]; /* Array of match inputs--start with 345 * second glyph */ 346 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 347 * design order */ 348 public: 349 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); 350}; 351 352struct RuleSet 353{ 354 inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const 355 { 356 TRACE_APPLY (); 357 unsigned int num_rules = rule.len; 358 for (unsigned int i = 0; i < num_rules; i++) 359 { 360 if ((this+rule[i]).apply (c, lookup_context)) 361 return true; 362 } 363 364 return false; 365 } 366 367 inline bool sanitize (hb_sanitize_context_t *c) { 368 TRACE_SANITIZE (); 369 return rule.sanitize (c, this); 370 } 371 372 private: 373 OffsetArrayOf<Rule> 374 rule; /* Array of Rule tables 375 * ordered by preference */ 376 public: 377 DEFINE_SIZE_ARRAY (2, rule); 378}; 379 380 381struct ContextFormat1 382{ 383 friend struct Context; 384 385 private: 386 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 387 { 388 TRACE_APPLY (); 389 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); 390 if (likely (index == NOT_COVERED)) 391 return false; 392 393 const RuleSet &rule_set = this+ruleSet[index]; 394 struct ContextLookupContext lookup_context = { 395 {match_glyph, apply_func}, 396 NULL 397 }; 398 return rule_set.apply (c, lookup_context); 399 } 400 401 inline bool sanitize (hb_sanitize_context_t *c) { 402 TRACE_SANITIZE (); 403 return coverage.sanitize (c, this) 404 && ruleSet.sanitize (c, this); 405 } 406 407 private: 408 USHORT format; /* Format identifier--format = 1 */ 409 OffsetTo<Coverage> 410 coverage; /* Offset to Coverage table--from 411 * beginning of table */ 412 OffsetArrayOf<RuleSet> 413 ruleSet; /* Array of RuleSet tables 414 * ordered by Coverage Index */ 415 public: 416 DEFINE_SIZE_ARRAY (6, ruleSet); 417}; 418 419 420struct ContextFormat2 421{ 422 friend struct Context; 423 424 private: 425 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 426 { 427 TRACE_APPLY (); 428 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); 429 if (likely (index == NOT_COVERED)) 430 return false; 431 432 const ClassDef &class_def = this+classDef; 433 index = class_def (c->buffer->info[c->buffer->idx].codepoint); 434 const RuleSet &rule_set = this+ruleSet[index]; 435 struct ContextLookupContext lookup_context = { 436 {match_class, apply_func}, 437 &class_def 438 }; 439 return rule_set.apply (c, lookup_context); 440 } 441 442 inline bool sanitize (hb_sanitize_context_t *c) { 443 TRACE_SANITIZE (); 444 return coverage.sanitize (c, this) 445 && classDef.sanitize (c, this) 446 && ruleSet.sanitize (c, this); 447 } 448 449 private: 450 USHORT format; /* Format identifier--format = 2 */ 451 OffsetTo<Coverage> 452 coverage; /* Offset to Coverage table--from 453 * beginning of table */ 454 OffsetTo<ClassDef> 455 classDef; /* Offset to glyph ClassDef table--from 456 * beginning of table */ 457 OffsetArrayOf<RuleSet> 458 ruleSet; /* Array of RuleSet tables 459 * ordered by class */ 460 public: 461 DEFINE_SIZE_ARRAY (8, ruleSet); 462}; 463 464 465struct ContextFormat3 466{ 467 friend struct Context; 468 469 private: 470 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 471 { 472 TRACE_APPLY (); 473 unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->idx].codepoint); 474 if (likely (index == NOT_COVERED)) 475 return false; 476 477 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 478 struct ContextLookupContext lookup_context = { 479 {match_coverage, apply_func}, 480 this 481 }; 482 return context_lookup (c, 483 glyphCount, (const USHORT *) (coverage + 1), 484 lookupCount, lookupRecord, 485 lookup_context); 486 } 487 488 inline bool sanitize (hb_sanitize_context_t *c) { 489 TRACE_SANITIZE (); 490 if (!c->check_struct (this)) return false; 491 unsigned int count = glyphCount; 492 if (!c->check_array (coverage, coverage[0].static_size, count)) return false; 493 for (unsigned int i = 0; i < count; i++) 494 if (!coverage[i].sanitize (c, this)) return false; 495 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 496 return c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount); 497 } 498 499 private: 500 USHORT format; /* Format identifier--format = 3 */ 501 USHORT glyphCount; /* Number of glyphs in the input glyph 502 * sequence */ 503 USHORT lookupCount; /* Number of LookupRecords */ 504 OffsetTo<Coverage> 505 coverage[VAR]; /* Array of offsets to Coverage 506 * table in glyph sequence order */ 507 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 508 * design order */ 509 public: 510 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 511}; 512 513struct Context 514{ 515 protected: 516 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 517 { 518 TRACE_APPLY (); 519 switch (u.format) { 520 case 1: return u.format1.apply (c, apply_func); 521 case 2: return u.format2.apply (c, apply_func); 522 case 3: return u.format3.apply (c, apply_func); 523 default:return false; 524 } 525 } 526 527 inline bool sanitize (hb_sanitize_context_t *c) { 528 TRACE_SANITIZE (); 529 if (!u.format.sanitize (c)) return false; 530 switch (u.format) { 531 case 1: return u.format1.sanitize (c); 532 case 2: return u.format2.sanitize (c); 533 case 3: return u.format3.sanitize (c); 534 default:return true; 535 } 536 } 537 538 private: 539 union { 540 USHORT format; /* Format identifier */ 541 ContextFormat1 format1; 542 ContextFormat2 format2; 543 ContextFormat3 format3; 544 } u; 545}; 546 547 548/* Chaining Contextual lookups */ 549 550struct ChainContextLookupContext 551{ 552 ContextFuncs funcs; 553 const void *match_data[3]; 554}; 555 556static inline bool chain_context_lookup (hb_apply_context_t *c, 557 unsigned int backtrackCount, 558 const USHORT backtrack[], 559 unsigned int inputCount, /* Including the first glyph (not matched) */ 560 const USHORT input[], /* Array of input values--start with second glyph */ 561 unsigned int lookaheadCount, 562 const USHORT lookahead[], 563 unsigned int lookupCount, 564 const LookupRecord lookupRecord[], 565 ChainContextLookupContext &lookup_context) 566{ 567 /* First guess */ 568 if (unlikely (c->buffer->backtrack_len () < backtrackCount || 569 c->buffer->idx + inputCount + lookaheadCount > c->buffer->len || 570 inputCount + lookaheadCount > c->context_length)) 571 return false; 572 573 hb_apply_context_t new_context = *c; 574 return match_backtrack (c, 575 backtrackCount, backtrack, 576 lookup_context.funcs.match, lookup_context.match_data[0]) 577 && match_input (c, 578 inputCount, input, 579 lookup_context.funcs.match, lookup_context.match_data[1], 580 &new_context.context_length) 581 && match_lookahead (c, 582 lookaheadCount, lookahead, 583 lookup_context.funcs.match, lookup_context.match_data[2], 584 new_context.context_length) 585 && apply_lookup (&new_context, 586 inputCount, 587 lookupCount, lookupRecord, 588 lookup_context.funcs.apply); 589} 590 591struct ChainRule 592{ 593 friend struct ChainRuleSet; 594 595 private: 596 inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const 597 { 598 TRACE_APPLY (); 599 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 600 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 601 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 602 return chain_context_lookup (c, 603 backtrack.len, backtrack.array, 604 input.len, input.array, 605 lookahead.len, lookahead.array, 606 lookup.len, lookup.array, 607 lookup_context); 608 } 609 610 public: 611 inline bool sanitize (hb_sanitize_context_t *c) { 612 TRACE_SANITIZE (); 613 if (!backtrack.sanitize (c)) return false; 614 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 615 if (!input.sanitize (c)) return false; 616 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 617 if (!lookahead.sanitize (c)) return false; 618 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 619 return lookup.sanitize (c); 620 } 621 622 private: 623 ArrayOf<USHORT> 624 backtrack; /* Array of backtracking values 625 * (to be matched before the input 626 * sequence) */ 627 HeadlessArrayOf<USHORT> 628 inputX; /* Array of input values (start with 629 * second glyph) */ 630 ArrayOf<USHORT> 631 lookaheadX; /* Array of lookahead values's (to be 632 * matched after the input sequence) */ 633 ArrayOf<LookupRecord> 634 lookupX; /* Array of LookupRecords--in 635 * design order) */ 636 public: 637 DEFINE_SIZE_MIN (8); 638}; 639 640struct ChainRuleSet 641{ 642 inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const 643 { 644 TRACE_APPLY (); 645 unsigned int num_rules = rule.len; 646 for (unsigned int i = 0; i < num_rules; i++) 647 { 648 if ((this+rule[i]).apply (c, lookup_context)) 649 return true; 650 } 651 652 return false; 653 } 654 655 inline bool sanitize (hb_sanitize_context_t *c) { 656 TRACE_SANITIZE (); 657 return rule.sanitize (c, this); 658 } 659 660 private: 661 OffsetArrayOf<ChainRule> 662 rule; /* Array of ChainRule tables 663 * ordered by preference */ 664 public: 665 DEFINE_SIZE_ARRAY (2, rule); 666}; 667 668struct ChainContextFormat1 669{ 670 friend struct ChainContext; 671 672 private: 673 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 674 { 675 TRACE_APPLY (); 676 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); 677 if (likely (index == NOT_COVERED)) 678 return false; 679 680 const ChainRuleSet &rule_set = this+ruleSet[index]; 681 struct ChainContextLookupContext lookup_context = { 682 {match_glyph, apply_func}, 683 {NULL, NULL, NULL} 684 }; 685 return rule_set.apply (c, lookup_context); 686 } 687 688 inline bool sanitize (hb_sanitize_context_t *c) { 689 TRACE_SANITIZE (); 690 return coverage.sanitize (c, this) 691 && ruleSet.sanitize (c, this); 692 } 693 694 private: 695 USHORT format; /* Format identifier--format = 1 */ 696 OffsetTo<Coverage> 697 coverage; /* Offset to Coverage table--from 698 * beginning of table */ 699 OffsetArrayOf<ChainRuleSet> 700 ruleSet; /* Array of ChainRuleSet tables 701 * ordered by Coverage Index */ 702 public: 703 DEFINE_SIZE_ARRAY (6, ruleSet); 704}; 705 706struct ChainContextFormat2 707{ 708 friend struct ChainContext; 709 710 private: 711 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 712 { 713 TRACE_APPLY (); 714 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); 715 if (likely (index == NOT_COVERED)) 716 return false; 717 718 const ClassDef &backtrack_class_def = this+backtrackClassDef; 719 const ClassDef &input_class_def = this+inputClassDef; 720 const ClassDef &lookahead_class_def = this+lookaheadClassDef; 721 722 index = input_class_def (c->buffer->info[c->buffer->idx].codepoint); 723 const ChainRuleSet &rule_set = this+ruleSet[index]; 724 struct ChainContextLookupContext lookup_context = { 725 {match_class, apply_func}, 726 {&backtrack_class_def, 727 &input_class_def, 728 &lookahead_class_def} 729 }; 730 return rule_set.apply (c, lookup_context); 731 } 732 733 inline bool sanitize (hb_sanitize_context_t *c) { 734 TRACE_SANITIZE (); 735 return coverage.sanitize (c, this) 736 && backtrackClassDef.sanitize (c, this) 737 && inputClassDef.sanitize (c, this) 738 && lookaheadClassDef.sanitize (c, this) 739 && ruleSet.sanitize (c, this); 740 } 741 742 private: 743 USHORT format; /* Format identifier--format = 2 */ 744 OffsetTo<Coverage> 745 coverage; /* Offset to Coverage table--from 746 * beginning of table */ 747 OffsetTo<ClassDef> 748 backtrackClassDef; /* Offset to glyph ClassDef table 749 * containing backtrack sequence 750 * data--from beginning of table */ 751 OffsetTo<ClassDef> 752 inputClassDef; /* Offset to glyph ClassDef 753 * table containing input sequence 754 * data--from beginning of table */ 755 OffsetTo<ClassDef> 756 lookaheadClassDef; /* Offset to glyph ClassDef table 757 * containing lookahead sequence 758 * data--from beginning of table */ 759 OffsetArrayOf<ChainRuleSet> 760 ruleSet; /* Array of ChainRuleSet tables 761 * ordered by class */ 762 public: 763 DEFINE_SIZE_ARRAY (12, ruleSet); 764}; 765 766struct ChainContextFormat3 767{ 768 friend struct ChainContext; 769 770 private: 771 772 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 773 { 774 TRACE_APPLY (); 775 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 776 777 unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->idx].codepoint); 778 if (likely (index == NOT_COVERED)) 779 return false; 780 781 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 782 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 783 struct ChainContextLookupContext lookup_context = { 784 {match_coverage, apply_func}, 785 {this, this, this} 786 }; 787 return chain_context_lookup (c, 788 backtrack.len, (const USHORT *) backtrack.array, 789 input.len, (const USHORT *) input.array + 1, 790 lookahead.len, (const USHORT *) lookahead.array, 791 lookup.len, lookup.array, 792 lookup_context); 793 } 794 795 inline bool sanitize (hb_sanitize_context_t *c) { 796 TRACE_SANITIZE (); 797 if (!backtrack.sanitize (c, this)) return false; 798 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 799 if (!input.sanitize (c, this)) return false; 800 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 801 if (!lookahead.sanitize (c, this)) return false; 802 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 803 return lookup.sanitize (c); 804 } 805 806 private: 807 USHORT format; /* Format identifier--format = 3 */ 808 OffsetArrayOf<Coverage> 809 backtrack; /* Array of coverage tables 810 * in backtracking sequence, in glyph 811 * sequence order */ 812 OffsetArrayOf<Coverage> 813 inputX ; /* Array of coverage 814 * tables in input sequence, in glyph 815 * sequence order */ 816 OffsetArrayOf<Coverage> 817 lookaheadX; /* Array of coverage tables 818 * in lookahead sequence, in glyph 819 * sequence order */ 820 ArrayOf<LookupRecord> 821 lookupX; /* Array of LookupRecords--in 822 * design order) */ 823 public: 824 DEFINE_SIZE_MIN (10); 825}; 826 827struct ChainContext 828{ 829 protected: 830 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const 831 { 832 TRACE_APPLY (); 833 switch (u.format) { 834 case 1: return u.format1.apply (c, apply_func); 835 case 2: return u.format2.apply (c, apply_func); 836 case 3: return u.format3.apply (c, apply_func); 837 default:return false; 838 } 839 } 840 841 inline bool sanitize (hb_sanitize_context_t *c) { 842 TRACE_SANITIZE (); 843 if (!u.format.sanitize (c)) return false; 844 switch (u.format) { 845 case 1: return u.format1.sanitize (c); 846 case 2: return u.format2.sanitize (c); 847 case 3: return u.format3.sanitize (c); 848 default:return true; 849 } 850 } 851 852 private: 853 union { 854 USHORT format; /* Format identifier */ 855 ChainContextFormat1 format1; 856 ChainContextFormat2 format2; 857 ChainContextFormat3 format3; 858 } u; 859}; 860 861 862struct ExtensionFormat1 863{ 864 friend struct Extension; 865 866 protected: 867 inline unsigned int get_type (void) const { return extensionLookupType; } 868 inline unsigned int get_offset (void) const { return extensionOffset; } 869 870 inline bool sanitize (hb_sanitize_context_t *c) { 871 TRACE_SANITIZE (); 872 return c->check_struct (this); 873 } 874 875 private: 876 USHORT format; /* Format identifier. Set to 1. */ 877 USHORT extensionLookupType; /* Lookup type of subtable referenced 878 * by ExtensionOffset (i.e. the 879 * extension subtable). */ 880 ULONG extensionOffset; /* Offset to the extension subtable, 881 * of lookup type subtable. */ 882 public: 883 DEFINE_SIZE_STATIC (8); 884}; 885 886struct Extension 887{ 888 inline unsigned int get_type (void) const 889 { 890 switch (u.format) { 891 case 1: return u.format1.get_type (); 892 default:return 0; 893 } 894 } 895 inline unsigned int get_offset (void) const 896 { 897 switch (u.format) { 898 case 1: return u.format1.get_offset (); 899 default:return 0; 900 } 901 } 902 903 inline bool sanitize (hb_sanitize_context_t *c) { 904 TRACE_SANITIZE (); 905 if (!u.format.sanitize (c)) return false; 906 switch (u.format) { 907 case 1: return u.format1.sanitize (c); 908 default:return true; 909 } 910 } 911 912 private: 913 union { 914 USHORT format; /* Format identifier */ 915 ExtensionFormat1 format1; 916 } u; 917}; 918 919 920/* 921 * GSUB/GPOS Common 922 */ 923 924struct GSUBGPOS 925{ 926 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 927 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 928 929 inline unsigned int get_script_count (void) const 930 { return (this+scriptList).len; } 931 inline const Tag& get_script_tag (unsigned int i) const 932 { return (this+scriptList).get_tag (i); } 933 inline unsigned int get_script_tags (unsigned int start_offset, 934 unsigned int *script_count /* IN/OUT */, 935 hb_tag_t *script_tags /* OUT */) const 936 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 937 inline const Script& get_script (unsigned int i) const 938 { return (this+scriptList)[i]; } 939 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 940 { return (this+scriptList).find_index (tag, index); } 941 942 inline unsigned int get_feature_count (void) const 943 { return (this+featureList).len; } 944 inline const Tag& get_feature_tag (unsigned int i) const 945 { return (this+featureList).get_tag (i); } 946 inline unsigned int get_feature_tags (unsigned int start_offset, 947 unsigned int *feature_count /* IN/OUT */, 948 hb_tag_t *feature_tags /* OUT */) const 949 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 950 inline const Feature& get_feature (unsigned int i) const 951 { return (this+featureList)[i]; } 952 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 953 { return (this+featureList).find_index (tag, index); } 954 955 inline unsigned int get_lookup_count (void) const 956 { return (this+lookupList).len; } 957 inline const Lookup& get_lookup (unsigned int i) const 958 { return (this+lookupList)[i]; } 959 960 inline bool sanitize (hb_sanitize_context_t *c) { 961 TRACE_SANITIZE (); 962 return version.sanitize (c) && likely (version.major == 1) 963 && scriptList.sanitize (c, this) 964 && featureList.sanitize (c, this) 965 && lookupList.sanitize (c, this); 966 } 967 968 protected: 969 FixedVersion version; /* Version of the GSUB/GPOS table--initially set 970 * to 0x00010000 */ 971 OffsetTo<ScriptList> 972 scriptList; /* ScriptList table */ 973 OffsetTo<FeatureList> 974 featureList; /* FeatureList table */ 975 OffsetTo<LookupList> 976 lookupList; /* LookupList table */ 977 public: 978 DEFINE_SIZE_STATIC (10); 979}; 980 981 982 983#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ 984