1 /* 2 * Copyright 2007,2008,2009,2010 Red Hat, Inc. 3 * Copyright 2010,2012,2013 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 35 namespace OT { 36 37 38 struct SingleSubstFormat1 39 { 40 inline void closure (hb_closure_context_t *c) const 41 { 42 TRACE_CLOSURE (this); 43 Coverage::Iter iter; 44 for (iter.init (this+coverage); iter.more (); iter.next ()) { 45 hb_codepoint_t glyph_id = iter.get_glyph (); 46 if (c->glyphs->has (glyph_id)) 47 c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu); 48 } 49 } 50 51 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 52 { 53 TRACE_COLLECT_GLYPHS (this); 54 Coverage::Iter iter; 55 for (iter.init (this+coverage); iter.more (); iter.next ()) { 56 hb_codepoint_t glyph_id = iter.get_glyph (); 57 c->input->add (glyph_id); 58 c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu); 59 } 60 } 61 62 inline const Coverage &get_coverage (void) const 63 { 64 return this+coverage; 65 } 66 67 inline bool would_apply (hb_would_apply_context_t *c) const 68 { 69 TRACE_WOULD_APPLY (this); 70 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 71 } 72 73 inline bool apply (hb_apply_context_t *c) const 74 { 75 TRACE_APPLY (this); 76 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 77 unsigned int index = (this+coverage).get_coverage (glyph_id); 78 if (likely (index == NOT_COVERED)) return_trace (false); 79 80 /* According to the Adobe Annotated OpenType Suite, result is always 81 * limited to 16bit. */ 82 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu; 83 c->replace_glyph (glyph_id); 84 85 return_trace (true); 86 } 87 88 inline bool serialize (hb_serialize_context_t *c, 89 Supplier<GlyphID> &glyphs, 90 unsigned int num_glyphs, 91 int delta) 92 { 93 TRACE_SERIALIZE (this); 94 if (unlikely (!c->extend_min (*this))) return_trace (false); 95 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 96 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ 97 return_trace (true); 98 } 99 100 inline bool sanitize (hb_sanitize_context_t *c) const 101 { 102 TRACE_SANITIZE (this); 103 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); 104 } 105 106 protected: 107 USHORT format; /* Format identifier--format = 1 */ 108 OffsetTo<Coverage> 109 coverage; /* Offset to Coverage table--from 110 * beginning of Substitution table */ 111 SHORT deltaGlyphID; /* Add to original GlyphID to get 112 * substitute GlyphID */ 113 public: 114 DEFINE_SIZE_STATIC (6); 115 }; 116 117 struct SingleSubstFormat2 118 { 119 inline void closure (hb_closure_context_t *c) const 120 { 121 TRACE_CLOSURE (this); 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 TRACE_COLLECT_GLYPHS (this); 132 Coverage::Iter iter; 133 for (iter.init (this+coverage); iter.more (); iter.next ()) { 134 c->input->add (iter.get_glyph ()); 135 c->output->add (substitute[iter.get_coverage ()]); 136 } 137 } 138 139 inline const Coverage &get_coverage (void) const 140 { 141 return this+coverage; 142 } 143 144 inline bool would_apply (hb_would_apply_context_t *c) const 145 { 146 TRACE_WOULD_APPLY (this); 147 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 148 } 149 150 inline bool apply (hb_apply_context_t *c) const 151 { 152 TRACE_APPLY (this); 153 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 154 unsigned int index = (this+coverage).get_coverage (glyph_id); 155 if (likely (index == NOT_COVERED)) return_trace (false); 156 157 if (unlikely (index >= substitute.len)) return_trace (false); 158 159 glyph_id = substitute[index]; 160 c->replace_glyph (glyph_id); 161 162 return_trace (true); 163 } 164 165 inline bool serialize (hb_serialize_context_t *c, 166 Supplier<GlyphID> &glyphs, 167 Supplier<GlyphID> &substitutes, 168 unsigned int num_glyphs) 169 { 170 TRACE_SERIALIZE (this); 171 if (unlikely (!c->extend_min (*this))) return_trace (false); 172 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false); 173 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 174 return_trace (true); 175 } 176 177 inline bool sanitize (hb_sanitize_context_t *c) const 178 { 179 TRACE_SANITIZE (this); 180 return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); 181 } 182 183 protected: 184 USHORT format; /* Format identifier--format = 2 */ 185 OffsetTo<Coverage> 186 coverage; /* Offset to Coverage table--from 187 * beginning of Substitution table */ 188 ArrayOf<GlyphID> 189 substitute; /* Array of substitute 190 * GlyphIDs--ordered by Coverage Index */ 191 public: 192 DEFINE_SIZE_ARRAY (6, substitute); 193 }; 194 195 struct SingleSubst 196 { 197 inline bool serialize (hb_serialize_context_t *c, 198 Supplier<GlyphID> &glyphs, 199 Supplier<GlyphID> &substitutes, 200 unsigned int num_glyphs) 201 { 202 TRACE_SERIALIZE (this); 203 if (unlikely (!c->extend_min (u.format))) return_trace (false); 204 unsigned int format = 2; 205 int delta = 0; 206 if (num_glyphs) { 207 format = 1; 208 /* TODO(serialize) check for wrap-around */ 209 delta = substitutes[0] - glyphs[0]; 210 for (unsigned int i = 1; i < num_glyphs; i++) 211 if (delta != substitutes[i] - glyphs[i]) { 212 format = 2; 213 break; 214 } 215 } 216 u.format.set (format); 217 switch (u.format) { 218 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta)); 219 case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); 220 default:return_trace (false); 221 } 222 } 223 224 template <typename context_t> 225 inline typename context_t::return_t dispatch (context_t *c) const 226 { 227 TRACE_DISPATCH (this, u.format); 228 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 229 switch (u.format) { 230 case 1: return_trace (c->dispatch (u.format1)); 231 case 2: return_trace (c->dispatch (u.format2)); 232 default:return_trace (c->default_return_value ()); 233 } 234 } 235 236 protected: 237 union { 238 USHORT format; /* Format identifier */ 239 SingleSubstFormat1 format1; 240 SingleSubstFormat2 format2; 241 } u; 242 }; 243 244 245 struct Sequence 246 { 247 inline void closure (hb_closure_context_t *c) const 248 { 249 TRACE_CLOSURE (this); 250 unsigned int count = substitute.len; 251 for (unsigned int i = 0; i < count; i++) 252 c->glyphs->add (substitute[i]); 253 } 254 255 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 256 { 257 TRACE_COLLECT_GLYPHS (this); 258 unsigned int count = substitute.len; 259 for (unsigned int i = 0; i < count; i++) 260 c->output->add (substitute[i]); 261 } 262 263 inline bool apply (hb_apply_context_t *c) const 264 { 265 TRACE_APPLY (this); 266 unsigned int count = substitute.len; 267 268 /* TODO: 269 * Testing shows that Uniscribe actually allows zero-len susbstitute, 270 * which essentially deletes a glyph. We don't allow for now. It 271 * can be confusing to the client since the cluster from the deleted 272 * glyph won't be merged with any output cluster... Also, currently 273 * buffer->move_to() makes assumptions about this too. Perhaps fix 274 * in the future after figuring out what to do with the clusters. 275 */ 276 if (unlikely (!count)) return_trace (false); 277 278 /* Special-case to make it in-place and not consider this 279 * as a "multiplied" substitution. */ 280 if (unlikely (count == 1)) 281 { 282 c->replace_glyph (substitute.array[0]); 283 return_trace (true); 284 } 285 286 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? 287 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; 288 289 for (unsigned int i = 0; i < count; i++) { 290 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); 291 c->output_glyph_for_component (substitute.array[i], klass); 292 } 293 c->buffer->skip_glyph (); 294 295 return_trace (true); 296 } 297 298 inline bool serialize (hb_serialize_context_t *c, 299 Supplier<GlyphID> &glyphs, 300 unsigned int num_glyphs) 301 { 302 TRACE_SERIALIZE (this); 303 if (unlikely (!c->extend_min (*this))) return_trace (false); 304 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false); 305 return_trace (true); 306 } 307 308 inline bool sanitize (hb_sanitize_context_t *c) const 309 { 310 TRACE_SANITIZE (this); 311 return_trace (substitute.sanitize (c)); 312 } 313 314 protected: 315 ArrayOf<GlyphID> 316 substitute; /* String of GlyphIDs to substitute */ 317 public: 318 DEFINE_SIZE_ARRAY (2, substitute); 319 }; 320 321 struct MultipleSubstFormat1 322 { 323 inline void closure (hb_closure_context_t *c) const 324 { 325 TRACE_CLOSURE (this); 326 Coverage::Iter iter; 327 for (iter.init (this+coverage); iter.more (); iter.next ()) { 328 if (c->glyphs->has (iter.get_glyph ())) 329 (this+sequence[iter.get_coverage ()]).closure (c); 330 } 331 } 332 333 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 334 { 335 TRACE_COLLECT_GLYPHS (this); 336 (this+coverage).add_coverage (c->input); 337 unsigned int count = sequence.len; 338 for (unsigned int i = 0; i < count; i++) 339 (this+sequence[i]).collect_glyphs (c); 340 } 341 342 inline const Coverage &get_coverage (void) const 343 { 344 return this+coverage; 345 } 346 347 inline bool would_apply (hb_would_apply_context_t *c) const 348 { 349 TRACE_WOULD_APPLY (this); 350 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 351 } 352 353 inline bool apply (hb_apply_context_t *c) const 354 { 355 TRACE_APPLY (this); 356 357 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 358 if (likely (index == NOT_COVERED)) return_trace (false); 359 360 return_trace ((this+sequence[index]).apply (c)); 361 } 362 363 inline bool serialize (hb_serialize_context_t *c, 364 Supplier<GlyphID> &glyphs, 365 Supplier<unsigned int> &substitute_len_list, 366 unsigned int num_glyphs, 367 Supplier<GlyphID> &substitute_glyphs_list) 368 { 369 TRACE_SERIALIZE (this); 370 if (unlikely (!c->extend_min (*this))) return_trace (false); 371 if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false); 372 for (unsigned int i = 0; i < num_glyphs; i++) 373 if (unlikely (!sequence[i].serialize (c, this).serialize (c, 374 substitute_glyphs_list, 375 substitute_len_list[i]))) return_trace (false); 376 substitute_len_list.advance (num_glyphs); 377 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 378 return_trace (true); 379 } 380 381 inline bool sanitize (hb_sanitize_context_t *c) const 382 { 383 TRACE_SANITIZE (this); 384 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); 385 } 386 387 protected: 388 USHORT format; /* Format identifier--format = 1 */ 389 OffsetTo<Coverage> 390 coverage; /* Offset to Coverage table--from 391 * beginning of Substitution table */ 392 OffsetArrayOf<Sequence> 393 sequence; /* Array of Sequence tables 394 * ordered by Coverage Index */ 395 public: 396 DEFINE_SIZE_ARRAY (6, sequence); 397 }; 398 399 struct MultipleSubst 400 { 401 inline bool serialize (hb_serialize_context_t *c, 402 Supplier<GlyphID> &glyphs, 403 Supplier<unsigned int> &substitute_len_list, 404 unsigned int num_glyphs, 405 Supplier<GlyphID> &substitute_glyphs_list) 406 { 407 TRACE_SERIALIZE (this); 408 if (unlikely (!c->extend_min (u.format))) return_trace (false); 409 unsigned int format = 1; 410 u.format.set (format); 411 switch (u.format) { 412 case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); 413 default:return_trace (false); 414 } 415 } 416 417 template <typename context_t> 418 inline typename context_t::return_t dispatch (context_t *c) const 419 { 420 TRACE_DISPATCH (this, u.format); 421 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 422 switch (u.format) { 423 case 1: return_trace (c->dispatch (u.format1)); 424 default:return_trace (c->default_return_value ()); 425 } 426 } 427 428 protected: 429 union { 430 USHORT format; /* Format identifier */ 431 MultipleSubstFormat1 format1; 432 } u; 433 }; 434 435 436 typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in 437 * arbitrary order */ 438 439 struct AlternateSubstFormat1 440 { 441 inline void closure (hb_closure_context_t *c) const 442 { 443 TRACE_CLOSURE (this); 444 Coverage::Iter iter; 445 for (iter.init (this+coverage); iter.more (); iter.next ()) { 446 if (c->glyphs->has (iter.get_glyph ())) { 447 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 448 unsigned int count = alt_set.len; 449 for (unsigned int i = 0; i < count; i++) 450 c->glyphs->add (alt_set[i]); 451 } 452 } 453 } 454 455 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 456 { 457 TRACE_COLLECT_GLYPHS (this); 458 Coverage::Iter iter; 459 for (iter.init (this+coverage); iter.more (); iter.next ()) { 460 c->input->add (iter.get_glyph ()); 461 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 462 unsigned int count = alt_set.len; 463 for (unsigned int i = 0; i < count; i++) 464 c->output->add (alt_set[i]); 465 } 466 } 467 468 inline const Coverage &get_coverage (void) const 469 { 470 return this+coverage; 471 } 472 473 inline bool would_apply (hb_would_apply_context_t *c) const 474 { 475 TRACE_WOULD_APPLY (this); 476 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 477 } 478 479 inline bool apply (hb_apply_context_t *c) const 480 { 481 TRACE_APPLY (this); 482 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 483 484 unsigned int index = (this+coverage).get_coverage (glyph_id); 485 if (likely (index == NOT_COVERED)) return_trace (false); 486 487 const AlternateSet &alt_set = this+alternateSet[index]; 488 489 if (unlikely (!alt_set.len)) return_trace (false); 490 491 hb_mask_t glyph_mask = c->buffer->cur().mask; 492 hb_mask_t lookup_mask = c->lookup_mask; 493 494 /* Note: This breaks badly if two features enabled this lookup together. */ 495 unsigned int shift = _hb_ctz (lookup_mask); 496 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); 497 498 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false); 499 500 glyph_id = alt_set[alt_index - 1]; 501 502 c->replace_glyph (glyph_id); 503 504 return_trace (true); 505 } 506 507 inline bool serialize (hb_serialize_context_t *c, 508 Supplier<GlyphID> &glyphs, 509 Supplier<unsigned int> &alternate_len_list, 510 unsigned int num_glyphs, 511 Supplier<GlyphID> &alternate_glyphs_list) 512 { 513 TRACE_SERIALIZE (this); 514 if (unlikely (!c->extend_min (*this))) return_trace (false); 515 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false); 516 for (unsigned int i = 0; i < num_glyphs; i++) 517 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c, 518 alternate_glyphs_list, 519 alternate_len_list[i]))) return_trace (false); 520 alternate_len_list.advance (num_glyphs); 521 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 522 return_trace (true); 523 } 524 525 inline bool sanitize (hb_sanitize_context_t *c) const 526 { 527 TRACE_SANITIZE (this); 528 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); 529 } 530 531 protected: 532 USHORT format; /* Format identifier--format = 1 */ 533 OffsetTo<Coverage> 534 coverage; /* Offset to Coverage table--from 535 * beginning of Substitution table */ 536 OffsetArrayOf<AlternateSet> 537 alternateSet; /* Array of AlternateSet tables 538 * ordered by Coverage Index */ 539 public: 540 DEFINE_SIZE_ARRAY (6, alternateSet); 541 }; 542 543 struct AlternateSubst 544 { 545 inline bool serialize (hb_serialize_context_t *c, 546 Supplier<GlyphID> &glyphs, 547 Supplier<unsigned int> &alternate_len_list, 548 unsigned int num_glyphs, 549 Supplier<GlyphID> &alternate_glyphs_list) 550 { 551 TRACE_SERIALIZE (this); 552 if (unlikely (!c->extend_min (u.format))) return_trace (false); 553 unsigned int format = 1; 554 u.format.set (format); 555 switch (u.format) { 556 case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); 557 default:return_trace (false); 558 } 559 } 560 561 template <typename context_t> 562 inline typename context_t::return_t dispatch (context_t *c) const 563 { 564 TRACE_DISPATCH (this, u.format); 565 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 566 switch (u.format) { 567 case 1: return_trace (c->dispatch (u.format1)); 568 default:return_trace (c->default_return_value ()); 569 } 570 } 571 572 protected: 573 union { 574 USHORT format; /* Format identifier */ 575 AlternateSubstFormat1 format1; 576 } u; 577 }; 578 579 580 struct Ligature 581 { 582 inline void closure (hb_closure_context_t *c) const 583 { 584 TRACE_CLOSURE (this); 585 unsigned int count = component.len; 586 for (unsigned int i = 1; i < count; i++) 587 if (!c->glyphs->has (component[i])) 588 return; 589 c->glyphs->add (ligGlyph); 590 } 591 592 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 593 { 594 TRACE_COLLECT_GLYPHS (this); 595 unsigned int count = component.len; 596 for (unsigned int i = 1; i < count; i++) 597 c->input->add (component[i]); 598 c->output->add (ligGlyph); 599 } 600 601 inline bool would_apply (hb_would_apply_context_t *c) const 602 { 603 TRACE_WOULD_APPLY (this); 604 if (c->len != component.len) 605 return_trace (false); 606 607 for (unsigned int i = 1; i < c->len; i++) 608 if (likely (c->glyphs[i] != component[i])) 609 return_trace (false); 610 611 return_trace (true); 612 } 613 614 inline bool apply (hb_apply_context_t *c) const 615 { 616 TRACE_APPLY (this); 617 unsigned int count = component.len; 618 619 if (unlikely (!count)) return_trace (false); 620 621 /* Special-case to make it in-place and not consider this 622 * as a "ligated" substitution. */ 623 if (unlikely (count == 1)) 624 { 625 c->replace_glyph (ligGlyph); 626 return_trace (true); 627 } 628 629 bool is_mark_ligature = false; 630 unsigned int total_component_count = 0; 631 632 unsigned int match_length = 0; 633 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 634 635 if (likely (!match_input (c, count, 636 &component[1], 637 match_glyph, 638 NULL, 639 &match_length, 640 match_positions, 641 &is_mark_ligature, 642 &total_component_count))) 643 return_trace (false); 644 645 ligate_input (c, 646 count, 647 match_positions, 648 match_length, 649 ligGlyph, 650 is_mark_ligature, 651 total_component_count); 652 653 return_trace (true); 654 } 655 656 inline bool serialize (hb_serialize_context_t *c, 657 GlyphID ligature, 658 Supplier<GlyphID> &components, /* Starting from second */ 659 unsigned int num_components /* Including first component */) 660 { 661 TRACE_SERIALIZE (this); 662 if (unlikely (!c->extend_min (*this))) return_trace (false); 663 ligGlyph = ligature; 664 if (unlikely (!component.serialize (c, components, num_components))) return_trace (false); 665 return_trace (true); 666 } 667 668 public: 669 inline bool sanitize (hb_sanitize_context_t *c) const 670 { 671 TRACE_SANITIZE (this); 672 return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); 673 } 674 675 protected: 676 GlyphID ligGlyph; /* GlyphID of ligature to substitute */ 677 HeadlessArrayOf<GlyphID> 678 component; /* Array of component GlyphIDs--start 679 * with the second component--ordered 680 * in writing direction */ 681 public: 682 DEFINE_SIZE_ARRAY (4, component); 683 }; 684 685 struct LigatureSet 686 { 687 inline void closure (hb_closure_context_t *c) const 688 { 689 TRACE_CLOSURE (this); 690 unsigned int num_ligs = ligature.len; 691 for (unsigned int i = 0; i < num_ligs; i++) 692 (this+ligature[i]).closure (c); 693 } 694 695 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 696 { 697 TRACE_COLLECT_GLYPHS (this); 698 unsigned int num_ligs = ligature.len; 699 for (unsigned int i = 0; i < num_ligs; i++) 700 (this+ligature[i]).collect_glyphs (c); 701 } 702 703 inline bool would_apply (hb_would_apply_context_t *c) const 704 { 705 TRACE_WOULD_APPLY (this); 706 unsigned int num_ligs = ligature.len; 707 for (unsigned int i = 0; i < num_ligs; i++) 708 { 709 const Ligature &lig = this+ligature[i]; 710 if (lig.would_apply (c)) 711 return_trace (true); 712 } 713 return_trace (false); 714 } 715 716 inline bool apply (hb_apply_context_t *c) const 717 { 718 TRACE_APPLY (this); 719 unsigned int num_ligs = ligature.len; 720 for (unsigned int i = 0; i < num_ligs; i++) 721 { 722 const Ligature &lig = this+ligature[i]; 723 if (lig.apply (c)) return_trace (true); 724 } 725 726 return_trace (false); 727 } 728 729 inline bool serialize (hb_serialize_context_t *c, 730 Supplier<GlyphID> &ligatures, 731 Supplier<unsigned int> &component_count_list, 732 unsigned int num_ligatures, 733 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 734 { 735 TRACE_SERIALIZE (this); 736 if (unlikely (!c->extend_min (*this))) return_trace (false); 737 if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false); 738 for (unsigned int i = 0; i < num_ligatures; i++) 739 if (unlikely (!ligature[i].serialize (c, this).serialize (c, 740 ligatures[i], 741 component_list, 742 component_count_list[i]))) return_trace (false); 743 ligatures.advance (num_ligatures); 744 component_count_list.advance (num_ligatures); 745 return_trace (true); 746 } 747 748 inline bool sanitize (hb_sanitize_context_t *c) const 749 { 750 TRACE_SANITIZE (this); 751 return_trace (ligature.sanitize (c, this)); 752 } 753 754 protected: 755 OffsetArrayOf<Ligature> 756 ligature; /* Array LigatureSet tables 757 * ordered by preference */ 758 public: 759 DEFINE_SIZE_ARRAY (2, ligature); 760 }; 761 762 struct LigatureSubstFormat1 763 { 764 inline void closure (hb_closure_context_t *c) const 765 { 766 TRACE_CLOSURE (this); 767 Coverage::Iter iter; 768 for (iter.init (this+coverage); iter.more (); iter.next ()) { 769 if (c->glyphs->has (iter.get_glyph ())) 770 (this+ligatureSet[iter.get_coverage ()]).closure (c); 771 } 772 } 773 774 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 775 { 776 TRACE_COLLECT_GLYPHS (this); 777 Coverage::Iter iter; 778 for (iter.init (this+coverage); iter.more (); iter.next ()) { 779 c->input->add (iter.get_glyph ()); 780 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c); 781 } 782 } 783 784 inline const Coverage &get_coverage (void) const 785 { 786 return this+coverage; 787 } 788 789 inline bool would_apply (hb_would_apply_context_t *c) const 790 { 791 TRACE_WOULD_APPLY (this); 792 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); 793 if (likely (index == NOT_COVERED)) return_trace (false); 794 795 const LigatureSet &lig_set = this+ligatureSet[index]; 796 return_trace (lig_set.would_apply (c)); 797 } 798 799 inline bool apply (hb_apply_context_t *c) const 800 { 801 TRACE_APPLY (this); 802 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 803 804 unsigned int index = (this+coverage).get_coverage (glyph_id); 805 if (likely (index == NOT_COVERED)) return_trace (false); 806 807 const LigatureSet &lig_set = this+ligatureSet[index]; 808 return_trace (lig_set.apply (c)); 809 } 810 811 inline bool serialize (hb_serialize_context_t *c, 812 Supplier<GlyphID> &first_glyphs, 813 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 814 unsigned int num_first_glyphs, 815 Supplier<GlyphID> &ligatures_list, 816 Supplier<unsigned int> &component_count_list, 817 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 818 { 819 TRACE_SERIALIZE (this); 820 if (unlikely (!c->extend_min (*this))) return_trace (false); 821 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false); 822 for (unsigned int i = 0; i < num_first_glyphs; i++) 823 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c, 824 ligatures_list, 825 component_count_list, 826 ligature_per_first_glyph_count_list[i], 827 component_list))) return_trace (false); 828 ligature_per_first_glyph_count_list.advance (num_first_glyphs); 829 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false); 830 return_trace (true); 831 } 832 833 inline bool sanitize (hb_sanitize_context_t *c) const 834 { 835 TRACE_SANITIZE (this); 836 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); 837 } 838 839 protected: 840 USHORT format; /* Format identifier--format = 1 */ 841 OffsetTo<Coverage> 842 coverage; /* Offset to Coverage table--from 843 * beginning of Substitution table */ 844 OffsetArrayOf<LigatureSet> 845 ligatureSet; /* Array LigatureSet tables 846 * ordered by Coverage Index */ 847 public: 848 DEFINE_SIZE_ARRAY (6, ligatureSet); 849 }; 850 851 struct LigatureSubst 852 { 853 inline bool serialize (hb_serialize_context_t *c, 854 Supplier<GlyphID> &first_glyphs, 855 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 856 unsigned int num_first_glyphs, 857 Supplier<GlyphID> &ligatures_list, 858 Supplier<unsigned int> &component_count_list, 859 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 860 { 861 TRACE_SERIALIZE (this); 862 if (unlikely (!c->extend_min (u.format))) return_trace (false); 863 unsigned int format = 1; 864 u.format.set (format); 865 switch (u.format) { 866 case 1: return_trace (u.format1.serialize (c, 867 first_glyphs, 868 ligature_per_first_glyph_count_list, 869 num_first_glyphs, 870 ligatures_list, 871 component_count_list, 872 component_list)); 873 default:return_trace (false); 874 } 875 } 876 877 template <typename context_t> 878 inline typename context_t::return_t dispatch (context_t *c) const 879 { 880 TRACE_DISPATCH (this, u.format); 881 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 882 switch (u.format) { 883 case 1: return_trace (c->dispatch (u.format1)); 884 default:return_trace (c->default_return_value ()); 885 } 886 } 887 888 protected: 889 union { 890 USHORT format; /* Format identifier */ 891 LigatureSubstFormat1 format1; 892 } u; 893 }; 894 895 896 struct ContextSubst : Context {}; 897 898 struct ChainContextSubst : ChainContext {}; 899 900 struct ExtensionSubst : Extension<ExtensionSubst> 901 { 902 typedef struct SubstLookupSubTable LookupSubTable; 903 904 inline bool is_reverse (void) const; 905 }; 906 907 908 struct ReverseChainSingleSubstFormat1 909 { 910 inline void closure (hb_closure_context_t *c) const 911 { 912 TRACE_CLOSURE (this); 913 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 914 915 unsigned int count; 916 917 count = backtrack.len; 918 for (unsigned int i = 0; i < count; i++) 919 if (!(this+backtrack[i]).intersects (c->glyphs)) 920 return; 921 922 count = lookahead.len; 923 for (unsigned int i = 0; i < count; i++) 924 if (!(this+lookahead[i]).intersects (c->glyphs)) 925 return; 926 927 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 928 Coverage::Iter iter; 929 for (iter.init (this+coverage); iter.more (); iter.next ()) { 930 if (c->glyphs->has (iter.get_glyph ())) 931 c->glyphs->add (substitute[iter.get_coverage ()]); 932 } 933 } 934 935 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 936 { 937 TRACE_COLLECT_GLYPHS (this); 938 939 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 940 941 unsigned int count; 942 943 (this+coverage).add_coverage (c->input); 944 945 count = backtrack.len; 946 for (unsigned int i = 0; i < count; i++) 947 (this+backtrack[i]).add_coverage (c->before); 948 949 count = lookahead.len; 950 for (unsigned int i = 0; i < count; i++) 951 (this+lookahead[i]).add_coverage (c->after); 952 953 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 954 count = substitute.len; 955 for (unsigned int i = 0; i < count; i++) 956 c->output->add (substitute[i]); 957 } 958 959 inline const Coverage &get_coverage (void) const 960 { 961 return this+coverage; 962 } 963 964 inline bool would_apply (hb_would_apply_context_t *c) const 965 { 966 TRACE_WOULD_APPLY (this); 967 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 968 } 969 970 inline bool apply (hb_apply_context_t *c) const 971 { 972 TRACE_APPLY (this); 973 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) 974 return_trace (false); /* No chaining to this type */ 975 976 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 977 if (likely (index == NOT_COVERED)) return_trace (false); 978 979 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 980 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 981 982 if (match_backtrack (c, 983 backtrack.len, (USHORT *) backtrack.array, 984 match_coverage, this) && 985 match_lookahead (c, 986 lookahead.len, (USHORT *) lookahead.array, 987 match_coverage, this, 988 1)) 989 { 990 c->replace_glyph_inplace (substitute[index]); 991 /* Note: We DON'T decrease buffer->idx. The main loop does it 992 * for us. This is useful for preventing surprises if someone 993 * calls us through a Context lookup. */ 994 return_trace (true); 995 } 996 997 return_trace (false); 998 } 999 1000 inline bool sanitize (hb_sanitize_context_t *c) const 1001 { 1002 TRACE_SANITIZE (this); 1003 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) 1004 return_trace (false); 1005 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1006 if (!lookahead.sanitize (c, this)) 1007 return_trace (false); 1008 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1009 return_trace (substitute.sanitize (c)); 1010 } 1011 1012 protected: 1013 USHORT format; /* Format identifier--format = 1 */ 1014 OffsetTo<Coverage> 1015 coverage; /* Offset to Coverage table--from 1016 * beginning of table */ 1017 OffsetArrayOf<Coverage> 1018 backtrack; /* Array of coverage tables 1019 * in backtracking sequence, in glyph 1020 * sequence order */ 1021 OffsetArrayOf<Coverage> 1022 lookaheadX; /* Array of coverage tables 1023 * in lookahead sequence, in glyph 1024 * sequence order */ 1025 ArrayOf<GlyphID> 1026 substituteX; /* Array of substitute 1027 * GlyphIDs--ordered by Coverage Index */ 1028 public: 1029 DEFINE_SIZE_MIN (10); 1030 }; 1031 1032 struct ReverseChainSingleSubst 1033 { 1034 template <typename context_t> 1035 inline typename context_t::return_t dispatch (context_t *c) const 1036 { 1037 TRACE_DISPATCH (this, u.format); 1038 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1039 switch (u.format) { 1040 case 1: return_trace (c->dispatch (u.format1)); 1041 default:return_trace (c->default_return_value ()); 1042 } 1043 } 1044 1045 protected: 1046 union { 1047 USHORT format; /* Format identifier */ 1048 ReverseChainSingleSubstFormat1 format1; 1049 } u; 1050 }; 1051 1052 1053 1054 /* 1055 * SubstLookup 1056 */ 1057 1058 struct SubstLookupSubTable 1059 { 1060 friend struct SubstLookup; 1061 1062 enum Type { 1063 Single = 1, 1064 Multiple = 2, 1065 Alternate = 3, 1066 Ligature = 4, 1067 Context = 5, 1068 ChainContext = 6, 1069 Extension = 7, 1070 ReverseChainSingle = 8 1071 }; 1072 1073 template <typename context_t> 1074 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const 1075 { 1076 TRACE_DISPATCH (this, lookup_type); 1077 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); 1078 switch (lookup_type) { 1079 case Single: return_trace (u.single.dispatch (c)); 1080 case Multiple: return_trace (u.multiple.dispatch (c)); 1081 case Alternate: return_trace (u.alternate.dispatch (c)); 1082 case Ligature: return_trace (u.ligature.dispatch (c)); 1083 case Context: return_trace (u.context.dispatch (c)); 1084 case ChainContext: return_trace (u.chainContext.dispatch (c)); 1085 case Extension: return_trace (u.extension.dispatch (c)); 1086 case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c)); 1087 default: return_trace (c->default_return_value ()); 1088 } 1089 } 1090 1091 protected: 1092 union { 1093 USHORT sub_format; 1094 SingleSubst single; 1095 MultipleSubst multiple; 1096 AlternateSubst alternate; 1097 LigatureSubst ligature; 1098 ContextSubst context; 1099 ChainContextSubst chainContext; 1100 ExtensionSubst extension; 1101 ReverseChainSingleSubst reverseChainContextSingle; 1102 } u; 1103 public: 1104 DEFINE_SIZE_UNION (2, sub_format); 1105 }; 1106 1107 1108 struct SubstLookup : Lookup 1109 { 1110 inline const SubstLookupSubTable& get_subtable (unsigned int i) const 1111 { return Lookup::get_subtable<SubstLookupSubTable> (i); } 1112 1113 inline static bool lookup_type_is_reverse (unsigned int lookup_type) 1114 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; } 1115 1116 inline bool is_reverse (void) const 1117 { 1118 unsigned int type = get_type (); 1119 if (unlikely (type == SubstLookupSubTable::Extension)) 1120 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse (); 1121 return lookup_type_is_reverse (type); 1122 } 1123 1124 inline bool apply (hb_apply_context_t *c) const 1125 { 1126 TRACE_APPLY (this); 1127 return_trace (dispatch (c)); 1128 } 1129 1130 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const 1131 { 1132 TRACE_CLOSURE (this); 1133 c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>); 1134 return_trace (dispatch (c)); 1135 } 1136 1137 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const 1138 { 1139 TRACE_COLLECT_GLYPHS (this); 1140 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); 1141 return_trace (dispatch (c)); 1142 } 1143 1144 template <typename set_t> 1145 inline void add_coverage (set_t *glyphs) const 1146 { 1147 hb_add_coverage_context_t<set_t> c (glyphs); 1148 dispatch (&c); 1149 } 1150 1151 inline bool would_apply (hb_would_apply_context_t *c, 1152 const hb_ot_layout_lookup_accelerator_t *accel) const 1153 { 1154 TRACE_WOULD_APPLY (this); 1155 if (unlikely (!c->len)) return_trace (false); 1156 if (!accel->may_have (c->glyphs[0])) return_trace (false); 1157 return_trace (dispatch (c)); 1158 } 1159 1160 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); 1161 1162 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, 1163 unsigned int i) 1164 { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); } 1165 1166 inline bool serialize_single (hb_serialize_context_t *c, 1167 uint32_t lookup_props, 1168 Supplier<GlyphID> &glyphs, 1169 Supplier<GlyphID> &substitutes, 1170 unsigned int num_glyphs) 1171 { 1172 TRACE_SERIALIZE (this); 1173 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false); 1174 return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); 1175 } 1176 1177 inline bool serialize_multiple (hb_serialize_context_t *c, 1178 uint32_t lookup_props, 1179 Supplier<GlyphID> &glyphs, 1180 Supplier<unsigned int> &substitute_len_list, 1181 unsigned int num_glyphs, 1182 Supplier<GlyphID> &substitute_glyphs_list) 1183 { 1184 TRACE_SERIALIZE (this); 1185 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false); 1186 return_trace (serialize_subtable (c, 0).u.multiple.serialize (c, 1187 glyphs, 1188 substitute_len_list, 1189 num_glyphs, 1190 substitute_glyphs_list)); 1191 } 1192 1193 inline bool serialize_alternate (hb_serialize_context_t *c, 1194 uint32_t lookup_props, 1195 Supplier<GlyphID> &glyphs, 1196 Supplier<unsigned int> &alternate_len_list, 1197 unsigned int num_glyphs, 1198 Supplier<GlyphID> &alternate_glyphs_list) 1199 { 1200 TRACE_SERIALIZE (this); 1201 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false); 1202 return_trace (serialize_subtable (c, 0).u.alternate.serialize (c, 1203 glyphs, 1204 alternate_len_list, 1205 num_glyphs, 1206 alternate_glyphs_list)); 1207 } 1208 1209 inline bool serialize_ligature (hb_serialize_context_t *c, 1210 uint32_t lookup_props, 1211 Supplier<GlyphID> &first_glyphs, 1212 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 1213 unsigned int num_first_glyphs, 1214 Supplier<GlyphID> &ligatures_list, 1215 Supplier<unsigned int> &component_count_list, 1216 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 1217 { 1218 TRACE_SERIALIZE (this); 1219 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false); 1220 return_trace (serialize_subtable (c, 0).u.ligature.serialize (c, 1221 first_glyphs, 1222 ligature_per_first_glyph_count_list, 1223 num_first_glyphs, 1224 ligatures_list, 1225 component_count_list, 1226 component_list)); 1227 } 1228 1229 template <typename context_t> 1230 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); 1231 1232 template <typename context_t> 1233 inline typename context_t::return_t dispatch (context_t *c) const 1234 { return Lookup::dispatch<SubstLookupSubTable> (c); } 1235 1236 inline bool sanitize (hb_sanitize_context_t *c) const 1237 { 1238 TRACE_SANITIZE (this); 1239 if (unlikely (!Lookup::sanitize (c))) return_trace (false); 1240 if (unlikely (!dispatch (c))) return_trace (false); 1241 1242 if (unlikely (get_type () == SubstLookupSubTable::Extension)) 1243 { 1244 /* The spec says all subtables of an Extension lookup should 1245 * have the same type. This is specially important if one has 1246 * a reverse type! */ 1247 unsigned int type = get_subtable (0).u.extension.get_type (); 1248 unsigned int count = get_subtable_count (); 1249 for (unsigned int i = 1; i < count; i++) 1250 if (get_subtable (i).u.extension.get_type () != type) 1251 return_trace (false); 1252 } 1253 return_trace (true); 1254 } 1255 }; 1256 1257 typedef OffsetListOf<SubstLookup> SubstLookupList; 1258 1259 /* 1260 * GSUB -- The Glyph Substitution Table 1261 */ 1262 1263 struct GSUB : GSUBGPOS 1264 { 1265 static const hb_tag_t tableTag = HB_OT_TAG_GSUB; 1266 1267 inline const SubstLookup& get_lookup (unsigned int i) const 1268 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } 1269 1270 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); 1271 1272 inline bool sanitize (hb_sanitize_context_t *c) const 1273 { 1274 TRACE_SANITIZE (this); 1275 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); 1276 const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); 1277 return_trace (list.sanitize (c, this)); 1278 } 1279 public: 1280 DEFINE_SIZE_STATIC (10); 1281 }; 1282 1283 1284 void 1285 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) 1286 { 1287 _hb_buffer_assert_gsubgpos_vars (buffer); 1288 1289 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; 1290 unsigned int count = buffer->len; 1291 hb_glyph_info_t *info = buffer->info; 1292 for (unsigned int i = 0; i < count; i++) 1293 { 1294 unsigned int props = gdef.get_glyph_props (info[i].codepoint); 1295 if (!props) 1296 { 1297 /* Never mark default-ignorables as marks. 1298 * They won't get in the way of lookups anyway, 1299 * but having them as mark will cause them to be skipped 1300 * over if the lookup-flag says so, but at least for the 1301 * Mongolian variation selectors, looks like Uniscribe 1302 * marks them as non-mark. Some Mongolian fonts without 1303 * GDEF rely on this. Another notable character that 1304 * this applies to is COMBINING GRAPHEME JOINER. */ 1305 props = (_hb_glyph_info_get_general_category (&info[i]) != 1306 HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK || 1307 _hb_glyph_info_is_default_ignorable (&info[i])) ? 1308 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 1309 HB_OT_LAYOUT_GLYPH_PROPS_MARK; 1310 } 1311 _hb_glyph_info_set_glyph_props (&info[i], props); 1312 _hb_glyph_info_clear_lig_props (&info[i]); 1313 buffer->info[i].syllable() = 0; 1314 } 1315 } 1316 1317 1318 /* Out-of-class implementation for methods recursing */ 1319 1320 /*static*/ inline bool ExtensionSubst::is_reverse (void) const 1321 { 1322 unsigned int type = get_type (); 1323 if (unlikely (type == SubstLookupSubTable::Extension)) 1324 return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse (); 1325 return SubstLookup::lookup_type_is_reverse (type); 1326 } 1327 1328 template <typename context_t> 1329 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) 1330 { 1331 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1332 const SubstLookup &l = gsub.get_lookup (lookup_index); 1333 return l.dispatch (c); 1334 } 1335 1336 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) 1337 { 1338 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1339 const SubstLookup &l = gsub.get_lookup (lookup_index); 1340 unsigned int saved_lookup_props = c->lookup_props; 1341 unsigned int saved_lookup_index = c->lookup_index; 1342 c->set_lookup_index (lookup_index); 1343 c->set_lookup_props (l.get_props ()); 1344 bool ret = l.dispatch (c); 1345 c->set_lookup_index (saved_lookup_index); 1346 c->set_lookup_props (saved_lookup_props); 1347 return ret; 1348 } 1349 1350 1351 } /* namespace OT */ 1352 1353 1354 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */ 1355