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