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