hb-ot-layout-gsub-table.hh revision e8cfdd7fa8d0fb66e0a261f3547e5824897e5131
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_GSUB_TABLE_HH 30#define HB_OT_LAYOUT_GSUB_TABLE_HH 31 32#include "hb-ot-layout-gsubgpos-private.hh" 33 34 35namespace OT { 36 37 38struct SingleSubstFormat1 39{ 40 friend struct SingleSubst; 41 42 private: 43 44 inline void closure (hb_closure_context_t *c) const 45 { 46 TRACE_CLOSURE (); 47 Coverage::Iter iter; 48 for (iter.init (this+coverage); iter.more (); iter.next ()) { 49 hb_codepoint_t glyph_id = iter.get_glyph (); 50 if (c->glyphs->has (glyph_id)) 51 c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF); 52 } 53 } 54 55 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 56 { 57 Coverage::Iter iter; 58 for (iter.init (this+coverage); iter.more (); iter.next ()) { 59 hb_codepoint_t glyph_id = iter.get_glyph (); 60 c->input.add (glyph_id); 61 c->output.add ((glyph_id + deltaGlyphID) & 0xFFFF); 62 } 63 } 64 65 inline const Coverage &get_coverage (void) const 66 { 67 return this+coverage; 68 } 69 70 inline bool apply (hb_apply_context_t *c) const 71 { 72 TRACE_APPLY (); 73 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 74 unsigned int index = (this+coverage) (glyph_id); 75 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 76 77 /* According to the Adobe Annotated OpenType Suite, result is always 78 * limited to 16bit. */ 79 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF; 80 c->replace_glyph (glyph_id); 81 82 return TRACE_RETURN (true); 83 } 84 85 inline bool serialize (hb_serialize_context_t *c, 86 Supplier<GlyphID> &glyphs, 87 unsigned int num_glyphs, 88 int delta) 89 { 90 TRACE_SERIALIZE (); 91 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 92 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 93 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ 94 return TRACE_RETURN (true); 95 } 96 97 inline bool sanitize (hb_sanitize_context_t *c) { 98 TRACE_SANITIZE (); 99 return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); 100 } 101 102 protected: 103 USHORT format; /* Format identifier--format = 1 */ 104 OffsetTo<Coverage> 105 coverage; /* Offset to Coverage table--from 106 * beginning of Substitution table */ 107 SHORT deltaGlyphID; /* Add to original GlyphID to get 108 * substitute GlyphID */ 109 public: 110 DEFINE_SIZE_STATIC (6); 111}; 112 113struct SingleSubstFormat2 114{ 115 friend struct SingleSubst; 116 117 private: 118 119 inline void closure (hb_closure_context_t *c) const 120 { 121 TRACE_CLOSURE (); 122 Coverage::Iter iter; 123 for (iter.init (this+coverage); iter.more (); iter.next ()) { 124 if (c->glyphs->has (iter.get_glyph ())) 125 c->glyphs->add (substitute[iter.get_coverage ()]); 126 } 127 } 128 129 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 130 { 131 Coverage::Iter iter; 132 for (iter.init (this+coverage); iter.more (); iter.next ()) { 133 c->input.add (iter.get_glyph ()); 134 c->output.add (substitute[iter.get_coverage ()]); 135 } 136 } 137 138 inline const Coverage &get_coverage (void) const 139 { 140 return this+coverage; 141 } 142 143 inline bool apply (hb_apply_context_t *c) const 144 { 145 TRACE_APPLY (); 146 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 147 unsigned int index = (this+coverage) (glyph_id); 148 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 149 150 if (unlikely (index >= substitute.len)) return TRACE_RETURN (false); 151 152 glyph_id = substitute[index]; 153 c->replace_glyph (glyph_id); 154 155 return TRACE_RETURN (true); 156 } 157 158 inline bool serialize (hb_serialize_context_t *c, 159 Supplier<GlyphID> &glyphs, 160 Supplier<GlyphID> &substitutes, 161 unsigned int num_glyphs) 162 { 163 TRACE_SERIALIZE (); 164 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 165 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false); 166 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 167 return TRACE_RETURN (true); 168 } 169 170 inline bool sanitize (hb_sanitize_context_t *c) { 171 TRACE_SANITIZE (); 172 return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c)); 173 } 174 175 protected: 176 USHORT format; /* Format identifier--format = 2 */ 177 OffsetTo<Coverage> 178 coverage; /* Offset to Coverage table--from 179 * beginning of Substitution table */ 180 ArrayOf<GlyphID> 181 substitute; /* Array of substitute 182 * GlyphIDs--ordered by Coverage Index */ 183 public: 184 DEFINE_SIZE_ARRAY (6, substitute); 185}; 186 187struct SingleSubst 188{ 189 friend struct SubstLookupSubTable; 190 friend struct SubstLookup; 191 192 private: 193 194 inline void closure (hb_closure_context_t *c) const 195 { 196 TRACE_CLOSURE (); 197 switch (u.format) { 198 case 1: u.format1.closure (c); break; 199 case 2: u.format2.closure (c); break; 200 default: break; 201 } 202 } 203 204 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 205 { 206 TRACE_CLOSURE (); 207 switch (u.format) { 208 case 1: u.format1.collect_glyphs (c); break; 209 case 2: u.format2.collect_glyphs (c); break; 210 default: break; 211 } 212 } 213 214 inline const Coverage &get_coverage (void) const 215 { 216 switch (u.format) { 217 case 1: return u.format1.get_coverage (); 218 case 2: return u.format2.get_coverage (); 219 default:return Null(Coverage); 220 } 221 } 222 223 inline bool apply (hb_apply_context_t *c) const 224 { 225 TRACE_APPLY (); 226 switch (u.format) { 227 case 1: return TRACE_RETURN (u.format1.apply (c)); 228 case 2: return TRACE_RETURN (u.format2.apply (c)); 229 default:return TRACE_RETURN (false); 230 } 231 } 232 233 inline bool serialize (hb_serialize_context_t *c, 234 Supplier<GlyphID> &glyphs, 235 Supplier<GlyphID> &substitutes, 236 unsigned int num_glyphs) 237 { 238 TRACE_SERIALIZE (); 239 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 240 unsigned int format = 2; 241 int delta; 242 if (num_glyphs) { 243 format = 1; 244 /* TODO(serialize) check for wrap-around */ 245 delta = substitutes[0] - glyphs[0]; 246 for (unsigned int i = 1; i < num_glyphs; i++) 247 if (delta != substitutes[i] - glyphs[i]) { 248 format = 2; 249 break; 250 } 251 } 252 u.format.set (format); 253 switch (u.format) { 254 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta)); 255 case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); 256 default:return TRACE_RETURN (false); 257 } 258 } 259 260 inline bool sanitize (hb_sanitize_context_t *c) { 261 TRACE_SANITIZE (); 262 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 263 switch (u.format) { 264 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 265 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 266 default:return TRACE_RETURN (true); 267 } 268 } 269 270 protected: 271 union { 272 USHORT format; /* Format identifier */ 273 SingleSubstFormat1 format1; 274 SingleSubstFormat2 format2; 275 } u; 276}; 277 278 279struct Sequence 280{ 281 friend struct MultipleSubstFormat1; 282 283 private: 284 285 inline void closure (hb_closure_context_t *c) const 286 { 287 TRACE_CLOSURE (); 288 unsigned int count = substitute.len; 289 for (unsigned int i = 0; i < count; i++) 290 c->glyphs->add (substitute[i]); 291 } 292 293 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 294 { 295 unsigned int count = substitute.len; 296 for (unsigned int i = 0; i < count; i++) 297 c->output.add (substitute[i]); 298 } 299 300 inline bool apply (hb_apply_context_t *c) const 301 { 302 TRACE_APPLY (); 303 if (unlikely (!substitute.len)) return TRACE_RETURN (false); 304 305 unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; 306 unsigned int count = substitute.len; 307 for (unsigned int i = 0; i < count; i++) { 308 set_lig_props_for_component (c->buffer->cur(), i); 309 c->output_glyph (substitute.array[i], klass); 310 } 311 c->buffer->skip_glyph (); 312 313 return TRACE_RETURN (true); 314 } 315 316 inline bool serialize (hb_serialize_context_t *c, 317 Supplier<GlyphID> &glyphs, 318 unsigned int num_glyphs) 319 { 320 TRACE_SERIALIZE (); 321 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 322 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 323 return TRACE_RETURN (true); 324 } 325 326 public: 327 inline bool sanitize (hb_sanitize_context_t *c) { 328 TRACE_SANITIZE (); 329 return TRACE_RETURN (substitute.sanitize (c)); 330 } 331 332 protected: 333 ArrayOf<GlyphID> 334 substitute; /* String of GlyphIDs to substitute */ 335 public: 336 DEFINE_SIZE_ARRAY (2, substitute); 337}; 338 339struct MultipleSubstFormat1 340{ 341 friend struct MultipleSubst; 342 343 private: 344 345 inline void closure (hb_closure_context_t *c) const 346 { 347 TRACE_CLOSURE (); 348 Coverage::Iter iter; 349 for (iter.init (this+coverage); iter.more (); iter.next ()) { 350 if (c->glyphs->has (iter.get_glyph ())) 351 (this+sequence[iter.get_coverage ()]).closure (c); 352 } 353 } 354 355 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 356 { 357 (this+coverage).add_coverage (&c->input); 358 unsigned int count = sequence.len; 359 for (unsigned int i = 0; i < count; i++) 360 (this+sequence[i]).collect_glyphs (c); 361 } 362 363 inline const Coverage &get_coverage (void) const 364 { 365 return this+coverage; 366 } 367 368 inline bool apply (hb_apply_context_t *c) const 369 { 370 TRACE_APPLY (); 371 372 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 373 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 374 375 return TRACE_RETURN ((this+sequence[index]).apply (c)); 376 } 377 378 inline bool serialize (hb_serialize_context_t *c, 379 Supplier<GlyphID> &glyphs, 380 Supplier<unsigned int> &substitute_len_list, 381 unsigned int num_glyphs, 382 Supplier<GlyphID> &substitute_glyphs_list) 383 { 384 TRACE_SERIALIZE (); 385 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 386 if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false); 387 for (unsigned int i = 0; i < num_glyphs; i++) 388 if (unlikely (!sequence[i].serialize (c, this).serialize (c, 389 substitute_glyphs_list, 390 substitute_len_list[i]))) return TRACE_RETURN (false); 391 substitute_len_list.advance (num_glyphs); 392 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 393 return TRACE_RETURN (true); 394 } 395 396 inline bool sanitize (hb_sanitize_context_t *c) { 397 TRACE_SANITIZE (); 398 return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this)); 399 } 400 401 protected: 402 USHORT format; /* Format identifier--format = 1 */ 403 OffsetTo<Coverage> 404 coverage; /* Offset to Coverage table--from 405 * beginning of Substitution table */ 406 OffsetArrayOf<Sequence> 407 sequence; /* Array of Sequence tables 408 * ordered by Coverage Index */ 409 public: 410 DEFINE_SIZE_ARRAY (6, sequence); 411}; 412 413struct MultipleSubst 414{ 415 friend struct SubstLookupSubTable; 416 friend struct SubstLookup; 417 418 private: 419 420 inline void closure (hb_closure_context_t *c) const 421 { 422 TRACE_CLOSURE (); 423 switch (u.format) { 424 case 1: u.format1.closure (c); break; 425 default: break; 426 } 427 } 428 429 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 430 { 431 switch (u.format) { 432 case 1: u.format1.collect_glyphs (c); break; 433 default: break; 434 } 435 } 436 437 inline const Coverage &get_coverage (void) const 438 { 439 switch (u.format) { 440 case 1: return u.format1.get_coverage (); 441 default:return Null(Coverage); 442 } 443 } 444 445 inline bool apply (hb_apply_context_t *c) const 446 { 447 TRACE_APPLY (); 448 switch (u.format) { 449 case 1: return TRACE_RETURN (u.format1.apply (c)); 450 default:return TRACE_RETURN (false); 451 } 452 } 453 454 inline bool serialize (hb_serialize_context_t *c, 455 Supplier<GlyphID> &glyphs, 456 Supplier<unsigned int> &substitute_len_list, 457 unsigned int num_glyphs, 458 Supplier<GlyphID> &substitute_glyphs_list) 459 { 460 TRACE_SERIALIZE (); 461 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 462 unsigned int format = 1; 463 u.format.set (format); 464 switch (u.format) { 465 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); 466 default:return TRACE_RETURN (false); 467 } 468 } 469 470 inline bool sanitize (hb_sanitize_context_t *c) { 471 TRACE_SANITIZE (); 472 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 473 switch (u.format) { 474 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 475 default:return TRACE_RETURN (true); 476 } 477 } 478 479 protected: 480 union { 481 USHORT format; /* Format identifier */ 482 MultipleSubstFormat1 format1; 483 } u; 484}; 485 486 487typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in 488 * arbitrary order */ 489 490struct AlternateSubstFormat1 491{ 492 friend struct AlternateSubst; 493 494 private: 495 496 inline void closure (hb_closure_context_t *c) const 497 { 498 TRACE_CLOSURE (); 499 Coverage::Iter iter; 500 for (iter.init (this+coverage); iter.more (); iter.next ()) { 501 if (c->glyphs->has (iter.get_glyph ())) { 502 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 503 unsigned int count = alt_set.len; 504 for (unsigned int i = 0; i < count; i++) 505 c->glyphs->add (alt_set[i]); 506 } 507 } 508 } 509 510 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 511 { 512 Coverage::Iter iter; 513 for (iter.init (this+coverage); iter.more (); iter.next ()) { 514 c->input.add (iter.get_glyph ()); 515 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 516 unsigned int count = alt_set.len; 517 for (unsigned int i = 0; i < count; i++) 518 c->output.add (alt_set[i]); 519 } 520 } 521 522 inline const Coverage &get_coverage (void) const 523 { 524 return this+coverage; 525 } 526 527 inline bool apply (hb_apply_context_t *c) const 528 { 529 TRACE_APPLY (); 530 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 531 532 unsigned int index = (this+coverage) (glyph_id); 533 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 534 535 const AlternateSet &alt_set = this+alternateSet[index]; 536 537 if (unlikely (!alt_set.len)) return TRACE_RETURN (false); 538 539 hb_mask_t glyph_mask = c->buffer->cur().mask; 540 hb_mask_t lookup_mask = c->lookup_mask; 541 542 /* Note: This breaks badly if two features enabled this lookup together. */ 543 unsigned int shift = _hb_ctz (lookup_mask); 544 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); 545 546 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false); 547 548 glyph_id = alt_set[alt_index - 1]; 549 550 c->replace_glyph (glyph_id); 551 552 return TRACE_RETURN (true); 553 } 554 555 inline bool serialize (hb_serialize_context_t *c, 556 Supplier<GlyphID> &glyphs, 557 Supplier<unsigned int> &alternate_len_list, 558 unsigned int num_glyphs, 559 Supplier<GlyphID> &alternate_glyphs_list) 560 { 561 TRACE_SERIALIZE (); 562 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 563 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false); 564 for (unsigned int i = 0; i < num_glyphs; i++) 565 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c, 566 alternate_glyphs_list, 567 alternate_len_list[i]))) return TRACE_RETURN (false); 568 alternate_len_list.advance (num_glyphs); 569 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 570 return TRACE_RETURN (true); 571 } 572 573 inline bool sanitize (hb_sanitize_context_t *c) { 574 TRACE_SANITIZE (); 575 return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); 576 } 577 578 protected: 579 USHORT format; /* Format identifier--format = 1 */ 580 OffsetTo<Coverage> 581 coverage; /* Offset to Coverage table--from 582 * beginning of Substitution table */ 583 OffsetArrayOf<AlternateSet> 584 alternateSet; /* Array of AlternateSet tables 585 * ordered by Coverage Index */ 586 public: 587 DEFINE_SIZE_ARRAY (6, alternateSet); 588}; 589 590struct AlternateSubst 591{ 592 friend struct SubstLookupSubTable; 593 friend struct SubstLookup; 594 595 private: 596 597 inline void closure (hb_closure_context_t *c) const 598 { 599 TRACE_CLOSURE (); 600 switch (u.format) { 601 case 1: u.format1.closure (c); break; 602 default: break; 603 } 604 } 605 606 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 607 { 608 switch (u.format) { 609 case 1: u.format1.collect_glyphs (c); break; 610 default: break; 611 } 612 } 613 614 inline const Coverage &get_coverage (void) const 615 { 616 switch (u.format) { 617 case 1: return u.format1.get_coverage (); 618 default:return Null(Coverage); 619 } 620 } 621 622 inline bool apply (hb_apply_context_t *c) const 623 { 624 TRACE_APPLY (); 625 switch (u.format) { 626 case 1: return TRACE_RETURN (u.format1.apply (c)); 627 default:return TRACE_RETURN (false); 628 } 629 } 630 631 inline bool serialize (hb_serialize_context_t *c, 632 Supplier<GlyphID> &glyphs, 633 Supplier<unsigned int> &alternate_len_list, 634 unsigned int num_glyphs, 635 Supplier<GlyphID> &alternate_glyphs_list) 636 { 637 TRACE_SERIALIZE (); 638 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 639 unsigned int format = 1; 640 u.format.set (format); 641 switch (u.format) { 642 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); 643 default:return TRACE_RETURN (false); 644 } 645 } 646 647 inline bool sanitize (hb_sanitize_context_t *c) { 648 TRACE_SANITIZE (); 649 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 650 switch (u.format) { 651 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 652 default:return TRACE_RETURN (true); 653 } 654 } 655 656 protected: 657 union { 658 USHORT format; /* Format identifier */ 659 AlternateSubstFormat1 format1; 660 } u; 661}; 662 663 664struct Ligature 665{ 666 friend struct LigatureSet; 667 668 private: 669 670 inline void closure (hb_closure_context_t *c) const 671 { 672 TRACE_CLOSURE (); 673 unsigned int count = component.len; 674 for (unsigned int i = 1; i < count; i++) 675 if (!c->glyphs->has (component[i])) 676 return; 677 c->glyphs->add (ligGlyph); 678 } 679 680 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 681 { 682 unsigned int count = component.len; 683 for (unsigned int i = 1; i < count; i++) 684 c->input.add (component[i]); 685 c->output.add (ligGlyph); 686 } 687 688 inline bool would_apply (hb_would_apply_context_t *c) const 689 { 690 if (c->len != component.len) 691 return false; 692 693 for (unsigned int i = 1; i < c->len; i++) 694 if (likely (c->glyphs[i] != component[i])) 695 return false; 696 697 return true; 698 } 699 700 inline bool apply (hb_apply_context_t *c) const 701 { 702 TRACE_APPLY (); 703 unsigned int count = component.len; 704 if (unlikely (count < 1)) return TRACE_RETURN (false); 705 706 unsigned int end_offset; 707 bool is_mark_ligature; 708 unsigned int total_component_count; 709 710 if (likely (!match_input (c, count, 711 &component[1], 712 match_glyph, 713 NULL, 714 &end_offset, 715 &is_mark_ligature, 716 &total_component_count))) 717 return TRACE_RETURN (false); 718 719 /* Deal, we are forming the ligature. */ 720 c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset); 721 722 ligate_input (c, 723 count, 724 &component[1], 725 ligGlyph, 726 match_glyph, 727 NULL, 728 is_mark_ligature, 729 total_component_count); 730 731 return TRACE_RETURN (true); 732 } 733 734 inline bool serialize (hb_serialize_context_t *c, 735 GlyphID ligature, 736 Supplier<GlyphID> &components, /* Starting from second */ 737 unsigned int num_components /* Including first component */) 738 { 739 TRACE_SERIALIZE (); 740 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 741 ligGlyph = ligature; 742 if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false); 743 return TRACE_RETURN (true); 744 } 745 746 public: 747 inline bool sanitize (hb_sanitize_context_t *c) { 748 TRACE_SANITIZE (); 749 return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c)); 750 } 751 752 protected: 753 GlyphID ligGlyph; /* GlyphID of ligature to substitute */ 754 HeadlessArrayOf<GlyphID> 755 component; /* Array of component GlyphIDs--start 756 * with the second component--ordered 757 * in writing direction */ 758 public: 759 DEFINE_SIZE_ARRAY (4, component); 760}; 761 762struct LigatureSet 763{ 764 friend struct LigatureSubstFormat1; 765 766 private: 767 768 inline void closure (hb_closure_context_t *c) const 769 { 770 TRACE_CLOSURE (); 771 unsigned int num_ligs = ligature.len; 772 for (unsigned int i = 0; i < num_ligs; i++) 773 (this+ligature[i]).closure (c); 774 } 775 776 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 777 { 778 unsigned int num_ligs = ligature.len; 779 for (unsigned int i = 0; i < num_ligs; i++) 780 (this+ligature[i]).collect_glyphs (c); 781 } 782 783 inline bool would_apply (hb_would_apply_context_t *c) const 784 { 785 unsigned int num_ligs = ligature.len; 786 for (unsigned int i = 0; i < num_ligs; i++) 787 { 788 const Ligature &lig = this+ligature[i]; 789 if (lig.would_apply (c)) 790 return true; 791 } 792 return false; 793 } 794 795 inline bool apply (hb_apply_context_t *c) const 796 { 797 TRACE_APPLY (); 798 unsigned int num_ligs = ligature.len; 799 for (unsigned int i = 0; i < num_ligs; i++) 800 { 801 const Ligature &lig = this+ligature[i]; 802 if (lig.apply (c)) return TRACE_RETURN (true); 803 } 804 805 return TRACE_RETURN (false); 806 } 807 808 inline bool serialize (hb_serialize_context_t *c, 809 Supplier<GlyphID> &ligatures, 810 Supplier<unsigned int> &component_count_list, 811 unsigned int num_ligatures, 812 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 813 { 814 TRACE_SERIALIZE (); 815 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 816 if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false); 817 for (unsigned int i = 0; i < num_ligatures; i++) 818 if (unlikely (!ligature[i].serialize (c, this).serialize (c, 819 ligatures[i], 820 component_list, 821 component_count_list[i]))) return TRACE_RETURN (false); 822 ligatures.advance (num_ligatures); 823 component_count_list.advance (num_ligatures); 824 return TRACE_RETURN (true); 825 } 826 827 public: 828 inline bool sanitize (hb_sanitize_context_t *c) { 829 TRACE_SANITIZE (); 830 return TRACE_RETURN (ligature.sanitize (c, this)); 831 } 832 833 protected: 834 OffsetArrayOf<Ligature> 835 ligature; /* Array LigatureSet tables 836 * ordered by preference */ 837 public: 838 DEFINE_SIZE_ARRAY (2, ligature); 839}; 840 841struct LigatureSubstFormat1 842{ 843 friend struct LigatureSubst; 844 845 private: 846 847 inline void closure (hb_closure_context_t *c) const 848 { 849 TRACE_CLOSURE (); 850 Coverage::Iter iter; 851 for (iter.init (this+coverage); iter.more (); iter.next ()) { 852 if (c->glyphs->has (iter.get_glyph ())) 853 (this+ligatureSet[iter.get_coverage ()]).closure (c); 854 } 855 } 856 857 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 858 { 859 Coverage::Iter iter; 860 for (iter.init (this+coverage); iter.more (); iter.next ()) { 861 c->input.add (iter.get_glyph ()); 862 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c); 863 } 864 } 865 866 inline const Coverage &get_coverage (void) const 867 { 868 return this+coverage; 869 } 870 871 inline bool would_apply (hb_would_apply_context_t *c) const 872 { 873 return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c); 874 } 875 876 inline bool apply (hb_apply_context_t *c) const 877 { 878 TRACE_APPLY (); 879 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 880 881 unsigned int index = (this+coverage) (glyph_id); 882 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 883 884 const LigatureSet &lig_set = this+ligatureSet[index]; 885 return TRACE_RETURN (lig_set.apply (c)); 886 } 887 888 inline bool serialize (hb_serialize_context_t *c, 889 Supplier<GlyphID> &first_glyphs, 890 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 891 unsigned int num_first_glyphs, 892 Supplier<GlyphID> &ligatures_list, 893 Supplier<unsigned int> &component_count_list, 894 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 895 { 896 TRACE_SERIALIZE (); 897 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 898 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false); 899 for (unsigned int i = 0; i < num_first_glyphs; i++) 900 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c, 901 ligatures_list, 902 component_count_list, 903 ligature_per_first_glyph_count_list[i], 904 component_list))) return TRACE_RETURN (false); 905 ligature_per_first_glyph_count_list.advance (num_first_glyphs); 906 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false); 907 return TRACE_RETURN (true); 908 } 909 910 inline bool sanitize (hb_sanitize_context_t *c) { 911 TRACE_SANITIZE (); 912 return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); 913 } 914 915 protected: 916 USHORT format; /* Format identifier--format = 1 */ 917 OffsetTo<Coverage> 918 coverage; /* Offset to Coverage table--from 919 * beginning of Substitution table */ 920 OffsetArrayOf<LigatureSet> 921 ligatureSet; /* Array LigatureSet tables 922 * ordered by Coverage Index */ 923 public: 924 DEFINE_SIZE_ARRAY (6, ligatureSet); 925}; 926 927struct LigatureSubst 928{ 929 friend struct SubstLookupSubTable; 930 friend struct SubstLookup; 931 932 private: 933 934 inline void closure (hb_closure_context_t *c) const 935 { 936 TRACE_CLOSURE (); 937 switch (u.format) { 938 case 1: u.format1.closure (c); break; 939 default: break; 940 } 941 } 942 943 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 944 { 945 switch (u.format) { 946 case 1: u.format1.collect_glyphs (c); break; 947 default: break; 948 } 949 } 950 951 inline const Coverage &get_coverage (void) const 952 { 953 switch (u.format) { 954 case 1: return u.format1.get_coverage (); 955 default:return Null(Coverage); 956 } 957 } 958 959 inline bool would_apply (hb_would_apply_context_t *c) const 960 { 961 switch (u.format) { 962 case 1: return u.format1.would_apply (c); 963 default:return false; 964 } 965 } 966 967 inline bool apply (hb_apply_context_t *c) const 968 { 969 TRACE_APPLY (); 970 switch (u.format) { 971 case 1: return TRACE_RETURN (u.format1.apply (c)); 972 default:return TRACE_RETURN (false); 973 } 974 } 975 976 inline bool serialize (hb_serialize_context_t *c, 977 Supplier<GlyphID> &first_glyphs, 978 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 979 unsigned int num_first_glyphs, 980 Supplier<GlyphID> &ligatures_list, 981 Supplier<unsigned int> &component_count_list, 982 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 983 { 984 TRACE_SERIALIZE (); 985 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 986 unsigned int format = 1; 987 u.format.set (format); 988 switch (u.format) { 989 case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, 990 ligatures_list, component_count_list, component_list)); 991 default:return TRACE_RETURN (false); 992 } 993 } 994 995 inline bool sanitize (hb_sanitize_context_t *c) { 996 TRACE_SANITIZE (); 997 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 998 switch (u.format) { 999 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1000 default:return TRACE_RETURN (true); 1001 } 1002 } 1003 1004 protected: 1005 union { 1006 USHORT format; /* Format identifier */ 1007 LigatureSubstFormat1 format1; 1008 } u; 1009}; 1010 1011 1012static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index); 1013static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index); 1014static inline void collect_glyphs_lookup (hb_collect_glyphs_context_t *c, unsigned int lookup_index); 1015 1016struct ContextSubst : Context 1017{ 1018 friend struct SubstLookupSubTable; 1019 1020 private: 1021 1022 inline void closure (hb_closure_context_t *c) const 1023 { 1024 TRACE_CLOSURE (); 1025 return Context::closure (c, closure_lookup); 1026 } 1027 1028 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1029 { 1030 return Context::collect_glyphs (c, collect_glyphs_lookup); 1031 } 1032 1033 inline bool apply (hb_apply_context_t *c) const 1034 { 1035 TRACE_APPLY (); 1036 return TRACE_RETURN (Context::apply (c, substitute_lookup)); 1037 } 1038}; 1039 1040struct ChainContextSubst : ChainContext 1041{ 1042 friend struct SubstLookupSubTable; 1043 1044 private: 1045 1046 inline void closure (hb_closure_context_t *c) const 1047 { 1048 TRACE_CLOSURE (); 1049 return ChainContext::closure (c, closure_lookup); 1050 } 1051 1052 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1053 { 1054 return ChainContext::collect_glyphs (c, collect_glyphs_lookup); 1055 } 1056 1057 inline bool apply (hb_apply_context_t *c) const 1058 { 1059 TRACE_APPLY (); 1060 return TRACE_RETURN (ChainContext::apply (c, substitute_lookup)); 1061 } 1062}; 1063 1064 1065struct ExtensionSubst : Extension 1066{ 1067 friend struct SubstLookupSubTable; 1068 friend struct SubstLookup; 1069 1070 private: 1071 inline const struct SubstLookupSubTable& get_subtable (void) const 1072 { 1073 unsigned int offset = get_offset (); 1074 if (unlikely (!offset)) return Null(SubstLookupSubTable); 1075 return StructAtOffset<SubstLookupSubTable> (this, offset); 1076 } 1077 1078 inline void closure (hb_closure_context_t *c) const; 1079 1080 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const; 1081 1082 inline const Coverage &get_coverage (void) const; 1083 1084 inline bool would_apply (hb_would_apply_context_t *c) const; 1085 1086 inline bool apply (hb_apply_context_t *c) const; 1087 1088 inline bool sanitize (hb_sanitize_context_t *c); 1089 1090 inline bool is_reverse (void) const; 1091}; 1092 1093 1094struct ReverseChainSingleSubstFormat1 1095{ 1096 friend struct ReverseChainSingleSubst; 1097 1098 private: 1099 1100 inline void closure (hb_closure_context_t *c) const 1101 { 1102 TRACE_CLOSURE (); 1103 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1104 1105 unsigned int count; 1106 1107 count = backtrack.len; 1108 for (unsigned int i = 0; i < count; i++) 1109 if (!(this+backtrack[i]).intersects (c->glyphs)) 1110 return; 1111 1112 count = lookahead.len; 1113 for (unsigned int i = 0; i < count; i++) 1114 if (!(this+lookahead[i]).intersects (c->glyphs)) 1115 return; 1116 1117 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1118 Coverage::Iter iter; 1119 for (iter.init (this+coverage); iter.more (); iter.next ()) { 1120 if (c->glyphs->has (iter.get_glyph ())) 1121 c->glyphs->add (substitute[iter.get_coverage ()]); 1122 } 1123 } 1124 1125 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1126 { 1127 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1128 1129 unsigned int count; 1130 1131 (this+coverage).add_coverage (&c->input); 1132 1133 count = backtrack.len; 1134 for (unsigned int i = 0; i < count; i++) 1135 (this+backtrack[i]).add_coverage (&c->before); 1136 1137 count = lookahead.len; 1138 for (unsigned int i = 0; i < count; i++) 1139 (this+lookahead[i]).add_coverage (&c->after); 1140 1141 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1142 count = substitute.len; 1143 for (unsigned int i = 0; i < count; i++) 1144 c->output.add (substitute[i]); 1145 } 1146 1147 inline const Coverage &get_coverage (void) const 1148 { 1149 return this+coverage; 1150 } 1151 1152 inline bool apply (hb_apply_context_t *c) const 1153 { 1154 TRACE_APPLY (); 1155 if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL)) 1156 return TRACE_RETURN (false); /* No chaining to this type */ 1157 1158 unsigned int index = (this+coverage) (c->buffer->cur().codepoint); 1159 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1160 1161 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1162 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1163 1164 if (match_backtrack (c, 1165 backtrack.len, (USHORT *) backtrack.array, 1166 match_coverage, this) && 1167 match_lookahead (c, 1168 lookahead.len, (USHORT *) lookahead.array, 1169 match_coverage, this, 1170 1)) 1171 { 1172 c->replace_glyph_inplace (substitute[index]); 1173 c->buffer->idx--; /* Reverse! */ 1174 return TRACE_RETURN (true); 1175 } 1176 1177 return TRACE_RETURN (false); 1178 } 1179 1180 inline bool sanitize (hb_sanitize_context_t *c) { 1181 TRACE_SANITIZE (); 1182 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) 1183 return TRACE_RETURN (false); 1184 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1185 if (!lookahead.sanitize (c, this)) 1186 return TRACE_RETURN (false); 1187 ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1188 return TRACE_RETURN (substitute.sanitize (c)); 1189 } 1190 1191 protected: 1192 USHORT format; /* Format identifier--format = 1 */ 1193 OffsetTo<Coverage> 1194 coverage; /* Offset to Coverage table--from 1195 * beginning of table */ 1196 OffsetArrayOf<Coverage> 1197 backtrack; /* Array of coverage tables 1198 * in backtracking sequence, in glyph 1199 * sequence order */ 1200 OffsetArrayOf<Coverage> 1201 lookaheadX; /* Array of coverage tables 1202 * in lookahead sequence, in glyph 1203 * sequence order */ 1204 ArrayOf<GlyphID> 1205 substituteX; /* Array of substitute 1206 * GlyphIDs--ordered by Coverage Index */ 1207 public: 1208 DEFINE_SIZE_MIN (10); 1209}; 1210 1211struct ReverseChainSingleSubst 1212{ 1213 friend struct SubstLookupSubTable; 1214 1215 private: 1216 1217 inline void closure (hb_closure_context_t *c) const 1218 { 1219 TRACE_CLOSURE (); 1220 switch (u.format) { 1221 case 1: u.format1.closure (c); break; 1222 default: break; 1223 } 1224 } 1225 1226 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1227 { 1228 switch (u.format) { 1229 case 1: u.format1.collect_glyphs (c); break; 1230 default: break; 1231 } 1232 } 1233 1234 inline const Coverage &get_coverage (void) const 1235 { 1236 switch (u.format) { 1237 case 1: return u.format1.get_coverage (); 1238 default:return Null(Coverage); 1239 } 1240 } 1241 1242 inline bool apply (hb_apply_context_t *c) const 1243 { 1244 TRACE_APPLY (); 1245 switch (u.format) { 1246 case 1: return TRACE_RETURN (u.format1.apply (c)); 1247 default:return TRACE_RETURN (false); 1248 } 1249 } 1250 1251 inline bool sanitize (hb_sanitize_context_t *c) { 1252 TRACE_SANITIZE (); 1253 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1254 switch (u.format) { 1255 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1256 default:return TRACE_RETURN (true); 1257 } 1258 } 1259 1260 protected: 1261 union { 1262 USHORT format; /* Format identifier */ 1263 ReverseChainSingleSubstFormat1 format1; 1264 } u; 1265}; 1266 1267 1268 1269/* 1270 * SubstLookup 1271 */ 1272 1273struct SubstLookupSubTable 1274{ 1275 friend struct SubstLookup; 1276 1277 enum Type { 1278 Single = 1, 1279 Multiple = 2, 1280 Alternate = 3, 1281 Ligature = 4, 1282 Context = 5, 1283 ChainContext = 6, 1284 Extension = 7, 1285 ReverseChainSingle = 8 1286 }; 1287 1288 inline void closure (hb_closure_context_t *c, 1289 unsigned int lookup_type) const 1290 { 1291 TRACE_CLOSURE (); 1292 switch (lookup_type) { 1293 case Single: u.single.closure (c); break; 1294 case Multiple: u.multiple.closure (c); break; 1295 case Alternate: u.alternate.closure (c); break; 1296 case Ligature: u.ligature.closure (c); break; 1297 case Context: u.context.closure (c); break; 1298 case ChainContext: u.chainContext.closure (c); break; 1299 case Extension: u.extension.closure (c); break; 1300 case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break; 1301 default: break; 1302 } 1303 } 1304 1305 inline void collect_glyphs (hb_collect_glyphs_context_t *c, 1306 unsigned int lookup_type) const 1307 { 1308 switch (lookup_type) { 1309 case Single: u.single.collect_glyphs (c); break; 1310 case Multiple: u.multiple.collect_glyphs (c); break; 1311 case Alternate: u.alternate.collect_glyphs (c); break; 1312 case Ligature: u.ligature.collect_glyphs (c); break; 1313 case Context: u.context.collect_glyphs (c); break; 1314 case ChainContext: u.chainContext.collect_glyphs (c); break; 1315 case Extension: u.extension.collect_glyphs (c); break; 1316 case ReverseChainSingle: u.reverseChainContextSingle.collect_glyphs (c); break; 1317 default: break; 1318 } 1319 } 1320 1321 inline const Coverage &get_coverage (unsigned int lookup_type) const 1322 { 1323 switch (lookup_type) { 1324 case Single: return u.single.get_coverage (); 1325 case Multiple: return u.multiple.get_coverage (); 1326 case Alternate: return u.alternate.get_coverage (); 1327 case Ligature: return u.ligature.get_coverage (); 1328 case Context: return u.context.get_coverage (); 1329 case ChainContext: return u.chainContext.get_coverage (); 1330 case Extension: return u.extension.get_coverage (); 1331 case ReverseChainSingle: return u.reverseChainContextSingle.get_coverage (); 1332 default: return Null(Coverage); 1333 } 1334 } 1335 1336 inline bool would_apply (hb_would_apply_context_t *c, 1337 unsigned int lookup_type) const 1338 { 1339 TRACE_WOULD_APPLY (); 1340 if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false; 1341 if (c->len == 1) { 1342 switch (lookup_type) { 1343 case Single: 1344 case Multiple: 1345 case Alternate: 1346 case ReverseChainSingle: 1347 return true; 1348 } 1349 } 1350 1351 /* Only need to look further for lookups that support substitutions 1352 * of input longer than 1. */ 1353 switch (lookup_type) { 1354 case Ligature: return u.ligature.would_apply (c); 1355 case Context: return u.context.would_apply (c); 1356 case ChainContext: return u.chainContext.would_apply (c); 1357 case Extension: return u.extension.would_apply (c); 1358 default: return false; 1359 } 1360 } 1361 1362 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const 1363 { 1364 TRACE_APPLY (); 1365 switch (lookup_type) { 1366 case Single: return TRACE_RETURN (u.single.apply (c)); 1367 case Multiple: return TRACE_RETURN (u.multiple.apply (c)); 1368 case Alternate: return TRACE_RETURN (u.alternate.apply (c)); 1369 case Ligature: return TRACE_RETURN (u.ligature.apply (c)); 1370 case Context: return TRACE_RETURN (u.context.apply (c)); 1371 case ChainContext: return TRACE_RETURN (u.chainContext.apply (c)); 1372 case Extension: return TRACE_RETURN (u.extension.apply (c)); 1373 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c)); 1374 default: return TRACE_RETURN (false); 1375 } 1376 } 1377 1378 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { 1379 TRACE_SANITIZE (); 1380 if (!u.header.sub_format.sanitize (c)) 1381 return TRACE_RETURN (false); 1382 switch (lookup_type) { 1383 case Single: return TRACE_RETURN (u.single.sanitize (c)); 1384 case Multiple: return TRACE_RETURN (u.multiple.sanitize (c)); 1385 case Alternate: return TRACE_RETURN (u.alternate.sanitize (c)); 1386 case Ligature: return TRACE_RETURN (u.ligature.sanitize (c)); 1387 case Context: return TRACE_RETURN (u.context.sanitize (c)); 1388 case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); 1389 case Extension: return TRACE_RETURN (u.extension.sanitize (c)); 1390 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c)); 1391 default: return TRACE_RETURN (true); 1392 } 1393 } 1394 1395 protected: 1396 union { 1397 struct { 1398 USHORT sub_format; 1399 } header; 1400 SingleSubst single; 1401 MultipleSubst multiple; 1402 AlternateSubst alternate; 1403 LigatureSubst ligature; 1404 ContextSubst context; 1405 ChainContextSubst chainContext; 1406 ExtensionSubst extension; 1407 ReverseChainSingleSubst reverseChainContextSingle; 1408 } u; 1409 public: 1410 DEFINE_SIZE_UNION (2, header.sub_format); 1411}; 1412 1413 1414struct SubstLookup : Lookup 1415{ 1416 inline const SubstLookupSubTable& get_subtable (unsigned int i) const 1417 { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; } 1418 1419 inline static bool lookup_type_is_reverse (unsigned int lookup_type) 1420 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; } 1421 1422 inline bool is_reverse (void) const 1423 { 1424 unsigned int type = get_type (); 1425 if (unlikely (type == SubstLookupSubTable::Extension)) 1426 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse (); 1427 return lookup_type_is_reverse (type); 1428 } 1429 1430 inline void closure (hb_closure_context_t *c) const 1431 { 1432 unsigned int lookup_type = get_type (); 1433 unsigned int count = get_subtable_count (); 1434 for (unsigned int i = 0; i < count; i++) 1435 get_subtable (i).closure (c, lookup_type); 1436 } 1437 1438 template <typename set_t> 1439 inline void add_coverage (set_t *glyphs) const 1440 { 1441 const Coverage *last = NULL; 1442 unsigned int count = get_subtable_count (); 1443 for (unsigned int i = 0; i < count; i++) { 1444 const Coverage *c = &get_subtable (i).get_coverage (get_type ()); 1445 if (c != last) { 1446 c->add_coverage (glyphs); 1447 last = c; 1448 } 1449 } 1450 } 1451 1452 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1453 { 1454 unsigned int lookup_type = get_type (); 1455 unsigned int count = get_subtable_count (); 1456 for (unsigned int i = 0; i < count; i++) 1457 get_subtable (i).collect_glyphs (c, lookup_type); 1458 } 1459 1460 inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const 1461 { 1462 if (unlikely (!c->len)) return false; 1463 if (!digest->may_have (c->glyphs[0])) return false; 1464 unsigned int lookup_type = get_type (); 1465 unsigned int count = get_subtable_count (); 1466 for (unsigned int i = 0; i < count; i++) 1467 if (get_subtable (i).would_apply (c, lookup_type)) 1468 return true; 1469 return false; 1470 } 1471 1472 inline bool apply_once (hb_apply_context_t *c) const 1473 { 1474 unsigned int lookup_type = get_type (); 1475 1476 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property)) 1477 return false; 1478 1479 unsigned int count = get_subtable_count (); 1480 for (unsigned int i = 0; i < count; i++) 1481 if (get_subtable (i).apply (c, lookup_type)) 1482 return true; 1483 1484 return false; 1485 } 1486 1487 inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const 1488 { 1489 bool ret = false; 1490 1491 if (unlikely (!c->buffer->len || !c->lookup_mask)) 1492 return false; 1493 1494 c->set_lookup (*this); 1495 1496 if (likely (!is_reverse ())) 1497 { 1498 /* in/out forward substitution */ 1499 c->buffer->clear_output (); 1500 c->buffer->idx = 0; 1501 1502 while (c->buffer->idx < c->buffer->len) 1503 { 1504 if ((c->buffer->cur().mask & c->lookup_mask) && 1505 digest->may_have (c->buffer->cur().codepoint) && 1506 apply_once (c)) 1507 ret = true; 1508 else 1509 c->buffer->next_glyph (); 1510 } 1511 if (ret) 1512 c->buffer->swap_buffers (); 1513 } 1514 else 1515 { 1516 /* in-place backward substitution */ 1517 c->buffer->remove_output (); 1518 c->buffer->idx = c->buffer->len - 1; 1519 do 1520 { 1521 if ((c->buffer->cur().mask & c->lookup_mask) && 1522 digest->may_have (c->buffer->cur().codepoint) && 1523 apply_once (c)) 1524 ret = true; 1525 else 1526 c->buffer->idx--; 1527 1528 } 1529 while ((int) c->buffer->idx >= 0); 1530 } 1531 1532 return ret; 1533 } 1534 1535 private: 1536 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, 1537 unsigned int i) 1538 { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); } 1539 public: 1540 1541 inline bool serialize_single (hb_serialize_context_t *c, 1542 uint32_t lookup_props, 1543 Supplier<GlyphID> &glyphs, 1544 Supplier<GlyphID> &substitutes, 1545 unsigned int num_glyphs) 1546 { 1547 TRACE_SERIALIZE (); 1548 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false); 1549 return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); 1550 } 1551 1552 inline bool serialize_multiple (hb_serialize_context_t *c, 1553 uint32_t lookup_props, 1554 Supplier<GlyphID> &glyphs, 1555 Supplier<unsigned int> &substitute_len_list, 1556 unsigned int num_glyphs, 1557 Supplier<GlyphID> &substitute_glyphs_list) 1558 { 1559 TRACE_SERIALIZE (); 1560 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false); 1561 return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs, 1562 substitute_glyphs_list)); 1563 } 1564 1565 inline bool serialize_alternate (hb_serialize_context_t *c, 1566 uint32_t lookup_props, 1567 Supplier<GlyphID> &glyphs, 1568 Supplier<unsigned int> &alternate_len_list, 1569 unsigned int num_glyphs, 1570 Supplier<GlyphID> &alternate_glyphs_list) 1571 { 1572 TRACE_SERIALIZE (); 1573 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false); 1574 return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs, 1575 alternate_glyphs_list)); 1576 } 1577 1578 inline bool serialize_ligature (hb_serialize_context_t *c, 1579 uint32_t lookup_props, 1580 Supplier<GlyphID> &first_glyphs, 1581 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 1582 unsigned int num_first_glyphs, 1583 Supplier<GlyphID> &ligatures_list, 1584 Supplier<unsigned int> &component_count_list, 1585 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 1586 { 1587 TRACE_SERIALIZE (); 1588 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false); 1589 return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, 1590 ligatures_list, component_count_list, component_list)); 1591 } 1592 1593 inline bool sanitize (hb_sanitize_context_t *c) 1594 { 1595 TRACE_SANITIZE (); 1596 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); 1597 OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable); 1598 if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false); 1599 1600 if (unlikely (get_type () == SubstLookupSubTable::Extension)) 1601 { 1602 /* The spec says all subtables of an Extension lookup should 1603 * have the same type. This is specially important if one has 1604 * a reverse type! 1605 * 1606 * We just check that they are all either forward, or reverse. */ 1607 unsigned int type = get_subtable (0).u.extension.get_type (); 1608 unsigned int count = get_subtable_count (); 1609 for (unsigned int i = 1; i < count; i++) 1610 if (get_subtable (i).u.extension.get_type () != type) 1611 return TRACE_RETURN (false); 1612 } 1613 return TRACE_RETURN (true); 1614 } 1615}; 1616 1617typedef OffsetListOf<SubstLookup> SubstLookupList; 1618 1619/* 1620 * GSUB -- The Glyph Substitution Table 1621 */ 1622 1623struct GSUB : GSUBGPOS 1624{ 1625 static const hb_tag_t Tag = HB_OT_TAG_GSUB; 1626 1627 inline const SubstLookup& get_lookup (unsigned int i) const 1628 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } 1629 1630 template <typename set_t> 1631 inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const 1632 { get_lookup (lookup_index).add_coverage (glyphs); } 1633 1634 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); 1635 static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer); 1636 1637 inline void closure_lookup (hb_closure_context_t *c, 1638 unsigned int lookup_index) const 1639 { return get_lookup (lookup_index).closure (c); } 1640 1641 inline bool sanitize (hb_sanitize_context_t *c) { 1642 TRACE_SANITIZE (); 1643 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); 1644 OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); 1645 return TRACE_RETURN (list.sanitize (c, this)); 1646 } 1647 public: 1648 DEFINE_SIZE_STATIC (10); 1649}; 1650 1651 1652void 1653GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) 1654{ 1655 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props); 1656 HB_BUFFER_ALLOCATE_VAR (buffer, lig_props); 1657 HB_BUFFER_ALLOCATE_VAR (buffer, syllable); 1658 1659 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; 1660 unsigned int count = buffer->len; 1661 for (unsigned int i = 0; i < count; i++) { 1662 buffer->info[i].lig_props() = buffer->info[i].syllable() = 0; 1663 buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint); 1664 } 1665} 1666 1667void 1668GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) 1669{ 1670} 1671 1672 1673/* Out-of-class implementation for methods recursing */ 1674 1675inline void ExtensionSubst::closure (hb_closure_context_t *c) const 1676{ 1677 get_subtable ().closure (c, get_type ()); 1678} 1679 1680inline void ExtensionSubst::collect_glyphs (hb_collect_glyphs_context_t *c) const 1681{ 1682 get_subtable ().collect_glyphs (c, get_type ()); 1683} 1684 1685inline const Coverage & ExtensionSubst::get_coverage (void) const 1686{ 1687 return get_subtable ().get_coverage (get_type ()); 1688} 1689 1690inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const 1691{ 1692 return get_subtable ().would_apply (c, get_type ()); 1693} 1694 1695inline bool ExtensionSubst::apply (hb_apply_context_t *c) const 1696{ 1697 TRACE_APPLY (); 1698 return TRACE_RETURN (get_subtable ().apply (c, get_type ())); 1699} 1700 1701inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c) 1702{ 1703 TRACE_SANITIZE (); 1704 if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false); 1705 unsigned int offset = get_offset (); 1706 if (unlikely (!offset)) return TRACE_RETURN (true); 1707 return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ())); 1708} 1709 1710inline bool ExtensionSubst::is_reverse (void) const 1711{ 1712 unsigned int type = get_type (); 1713 if (unlikely (type == SubstLookupSubTable::Extension)) 1714 return CastR<ExtensionSubst> (get_subtable()).is_reverse (); 1715 return SubstLookup::lookup_type_is_reverse (type); 1716} 1717 1718static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index) 1719{ 1720 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1721 const SubstLookup &l = gsub.get_lookup (lookup_index); 1722 1723 if (unlikely (c->nesting_level_left == 0)) 1724 return; 1725 1726 c->nesting_level_left--; 1727 l.closure (c); 1728 c->nesting_level_left++; 1729} 1730 1731static inline void collect_glyphs_lookup (hb_collect_glyphs_context_t *c, unsigned int lookup_index) 1732{ 1733 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1734 const SubstLookup &l = gsub.get_lookup (lookup_index); 1735 1736 /* XXX TODO */ 1737 l.collect_glyphs (c); 1738} 1739 1740static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) 1741{ 1742 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1743 const SubstLookup &l = gsub.get_lookup (lookup_index); 1744 1745 if (unlikely (c->nesting_level_left == 0)) 1746 return false; 1747 1748 hb_apply_context_t new_c (*c); 1749 new_c.nesting_level_left--; 1750 new_c.set_lookup (l); 1751 return l.apply_once (&new_c); 1752} 1753 1754 1755} /* namespace OT */ 1756 1757 1758#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */ 1759