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