1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 // This file is available under and governed by the GNU General Public 26 // License version 2 only, as published by the Free Software Foundation. 27 // However, the following notice accompanied the original version of this 28 // file: 29 // 30 /* 31 * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 32 * Copyright © 2010,2012,2013 Google, Inc. 33 * 34 * This is part of HarfBuzz, a text shaping library. 35 * 36 * Permission is hereby granted, without written agreement and without 37 * license or royalty fees, to use, copy, modify, and distribute this 38 * software and its documentation for any purpose, provided that the 39 * above copyright notice and the following two paragraphs appear in 40 * all copies of this software. 41 * 42 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 43 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 44 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 45 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 46 * DAMAGE. 47 * 48 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 49 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 50 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 51 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 52 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 53 * 54 * Red Hat Author(s): Behdad Esfahbod 55 * Google Author(s): Behdad Esfahbod 56 */ 57 58 #ifndef HB_OT_LAYOUT_GSUB_TABLE_HH 59 #define HB_OT_LAYOUT_GSUB_TABLE_HH 60 61 #include "hb-ot-layout-gsubgpos-private.hh" 62 63 64 namespace OT { 65 66 67 struct SingleSubstFormat1 68 { 69 inline void closure (hb_closure_context_t *c) const 70 { 71 TRACE_CLOSURE (this); 72 Coverage::Iter iter; 73 for (iter.init (this+coverage); iter.more (); iter.next ()) { 74 hb_codepoint_t glyph_id = iter.get_glyph (); 75 if (c->glyphs->has (glyph_id)) 76 c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu); 77 } 78 } 79 80 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 81 { 82 TRACE_COLLECT_GLYPHS (this); 83 Coverage::Iter iter; 84 for (iter.init (this+coverage); iter.more (); iter.next ()) { 85 hb_codepoint_t glyph_id = iter.get_glyph (); 86 c->input->add (glyph_id); 87 c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu); 88 } 89 } 90 91 inline const Coverage &get_coverage (void) const 92 { 93 return this+coverage; 94 } 95 96 inline bool would_apply (hb_would_apply_context_t *c) const 97 { 98 TRACE_WOULD_APPLY (this); 99 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 100 } 101 102 inline bool apply (hb_apply_context_t *c) const 103 { 104 TRACE_APPLY (this); 105 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 106 unsigned int index = (this+coverage).get_coverage (glyph_id); 107 if (likely (index == NOT_COVERED)) return_trace (false); 108 109 /* According to the Adobe Annotated OpenType Suite, result is always 110 * limited to 16bit. */ 111 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu; 112 c->replace_glyph (glyph_id); 113 114 return_trace (true); 115 } 116 117 inline bool serialize (hb_serialize_context_t *c, 118 Supplier<GlyphID> &glyphs, 119 unsigned int num_glyphs, 120 int delta) 121 { 122 TRACE_SERIALIZE (this); 123 if (unlikely (!c->extend_min (*this))) return_trace (false); 124 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 125 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ 126 return_trace (true); 127 } 128 129 inline bool sanitize (hb_sanitize_context_t *c) const 130 { 131 TRACE_SANITIZE (this); 132 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); 133 } 134 135 protected: 136 USHORT format; /* Format identifier--format = 1 */ 137 OffsetTo<Coverage> 138 coverage; /* Offset to Coverage table--from 139 * beginning of Substitution table */ 140 SHORT deltaGlyphID; /* Add to original GlyphID to get 141 * substitute GlyphID */ 142 public: 143 DEFINE_SIZE_STATIC (6); 144 }; 145 146 struct SingleSubstFormat2 147 { 148 inline void closure (hb_closure_context_t *c) const 149 { 150 TRACE_CLOSURE (this); 151 Coverage::Iter iter; 152 for (iter.init (this+coverage); iter.more (); iter.next ()) { 153 if (c->glyphs->has (iter.get_glyph ())) 154 c->glyphs->add (substitute[iter.get_coverage ()]); 155 } 156 } 157 158 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 159 { 160 TRACE_COLLECT_GLYPHS (this); 161 Coverage::Iter iter; 162 for (iter.init (this+coverage); iter.more (); iter.next ()) { 163 c->input->add (iter.get_glyph ()); 164 c->output->add (substitute[iter.get_coverage ()]); 165 } 166 } 167 168 inline const Coverage &get_coverage (void) const 169 { 170 return this+coverage; 171 } 172 173 inline bool would_apply (hb_would_apply_context_t *c) const 174 { 175 TRACE_WOULD_APPLY (this); 176 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 177 } 178 179 inline bool apply (hb_apply_context_t *c) const 180 { 181 TRACE_APPLY (this); 182 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 183 unsigned int index = (this+coverage).get_coverage (glyph_id); 184 if (likely (index == NOT_COVERED)) return_trace (false); 185 186 if (unlikely (index >= substitute.len)) return_trace (false); 187 188 glyph_id = substitute[index]; 189 c->replace_glyph (glyph_id); 190 191 return_trace (true); 192 } 193 194 inline bool serialize (hb_serialize_context_t *c, 195 Supplier<GlyphID> &glyphs, 196 Supplier<GlyphID> &substitutes, 197 unsigned int num_glyphs) 198 { 199 TRACE_SERIALIZE (this); 200 if (unlikely (!c->extend_min (*this))) return_trace (false); 201 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false); 202 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 203 return_trace (true); 204 } 205 206 inline bool sanitize (hb_sanitize_context_t *c) const 207 { 208 TRACE_SANITIZE (this); 209 return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); 210 } 211 212 protected: 213 USHORT format; /* Format identifier--format = 2 */ 214 OffsetTo<Coverage> 215 coverage; /* Offset to Coverage table--from 216 * beginning of Substitution table */ 217 ArrayOf<GlyphID> 218 substitute; /* Array of substitute 219 * GlyphIDs--ordered by Coverage Index */ 220 public: 221 DEFINE_SIZE_ARRAY (6, substitute); 222 }; 223 224 struct SingleSubst 225 { 226 inline bool serialize (hb_serialize_context_t *c, 227 Supplier<GlyphID> &glyphs, 228 Supplier<GlyphID> &substitutes, 229 unsigned int num_glyphs) 230 { 231 TRACE_SERIALIZE (this); 232 if (unlikely (!c->extend_min (u.format))) return_trace (false); 233 unsigned int format = 2; 234 int delta = 0; 235 if (num_glyphs) { 236 format = 1; 237 /* TODO(serialize) check for wrap-around */ 238 delta = substitutes[0] - glyphs[0]; 239 for (unsigned int i = 1; i < num_glyphs; i++) 240 if (delta != substitutes[i] - glyphs[i]) { 241 format = 2; 242 break; 243 } 244 } 245 u.format.set (format); 246 switch (u.format) { 247 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta)); 248 case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); 249 default:return_trace (false); 250 } 251 } 252 253 template <typename context_t> 254 inline typename context_t::return_t dispatch (context_t *c) const 255 { 256 TRACE_DISPATCH (this, u.format); 257 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 258 switch (u.format) { 259 case 1: return_trace (c->dispatch (u.format1)); 260 case 2: return_trace (c->dispatch (u.format2)); 261 default:return_trace (c->default_return_value ()); 262 } 263 } 264 265 protected: 266 union { 267 USHORT format; /* Format identifier */ 268 SingleSubstFormat1 format1; 269 SingleSubstFormat2 format2; 270 } u; 271 }; 272 273 274 struct Sequence 275 { 276 inline void closure (hb_closure_context_t *c) const 277 { 278 TRACE_CLOSURE (this); 279 unsigned int count = substitute.len; 280 for (unsigned int i = 0; i < count; i++) 281 c->glyphs->add (substitute[i]); 282 } 283 284 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 285 { 286 TRACE_COLLECT_GLYPHS (this); 287 unsigned int count = substitute.len; 288 for (unsigned int i = 0; i < count; i++) 289 c->output->add (substitute[i]); 290 } 291 292 inline bool apply (hb_apply_context_t *c) const 293 { 294 TRACE_APPLY (this); 295 unsigned int count = substitute.len; 296 297 /* TODO: 298 * Testing shows that Uniscribe actually allows zero-len susbstitute, 299 * which essentially deletes a glyph. We don't allow for now. It 300 * can be confusing to the client since the cluster from the deleted 301 * glyph won't be merged with any output cluster... Also, currently 302 * buffer->move_to() makes assumptions about this too. Perhaps fix 303 * in the future after figuring out what to do with the clusters. 304 */ 305 if (unlikely (!count)) return_trace (false); 306 307 /* Special-case to make it in-place and not consider this 308 * as a "multiplied" substitution. */ 309 if (unlikely (count == 1)) 310 { 311 c->replace_glyph (substitute.array[0]); 312 return_trace (true); 313 } 314 315 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? 316 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; 317 318 for (unsigned int i = 0; i < count; i++) { 319 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); 320 c->output_glyph_for_component (substitute.array[i], klass); 321 } 322 c->buffer->skip_glyph (); 323 324 return_trace (true); 325 } 326 327 inline bool serialize (hb_serialize_context_t *c, 328 Supplier<GlyphID> &glyphs, 329 unsigned int num_glyphs) 330 { 331 TRACE_SERIALIZE (this); 332 if (unlikely (!c->extend_min (*this))) return_trace (false); 333 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false); 334 return_trace (true); 335 } 336 337 inline bool sanitize (hb_sanitize_context_t *c) const 338 { 339 TRACE_SANITIZE (this); 340 return_trace (substitute.sanitize (c)); 341 } 342 343 protected: 344 ArrayOf<GlyphID> 345 substitute; /* String of GlyphIDs to substitute */ 346 public: 347 DEFINE_SIZE_ARRAY (2, substitute); 348 }; 349 350 struct MultipleSubstFormat1 351 { 352 inline void closure (hb_closure_context_t *c) const 353 { 354 TRACE_CLOSURE (this); 355 Coverage::Iter iter; 356 for (iter.init (this+coverage); iter.more (); iter.next ()) { 357 if (c->glyphs->has (iter.get_glyph ())) 358 (this+sequence[iter.get_coverage ()]).closure (c); 359 } 360 } 361 362 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 363 { 364 TRACE_COLLECT_GLYPHS (this); 365 (this+coverage).add_coverage (c->input); 366 unsigned int count = sequence.len; 367 for (unsigned int i = 0; i < count; i++) 368 (this+sequence[i]).collect_glyphs (c); 369 } 370 371 inline const Coverage &get_coverage (void) const 372 { 373 return this+coverage; 374 } 375 376 inline bool would_apply (hb_would_apply_context_t *c) const 377 { 378 TRACE_WOULD_APPLY (this); 379 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 380 } 381 382 inline bool apply (hb_apply_context_t *c) const 383 { 384 TRACE_APPLY (this); 385 386 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 387 if (likely (index == NOT_COVERED)) return_trace (false); 388 389 return_trace ((this+sequence[index]).apply (c)); 390 } 391 392 inline bool serialize (hb_serialize_context_t *c, 393 Supplier<GlyphID> &glyphs, 394 Supplier<unsigned int> &substitute_len_list, 395 unsigned int num_glyphs, 396 Supplier<GlyphID> &substitute_glyphs_list) 397 { 398 TRACE_SERIALIZE (this); 399 if (unlikely (!c->extend_min (*this))) return_trace (false); 400 if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false); 401 for (unsigned int i = 0; i < num_glyphs; i++) 402 if (unlikely (!sequence[i].serialize (c, this).serialize (c, 403 substitute_glyphs_list, 404 substitute_len_list[i]))) return_trace (false); 405 substitute_len_list.advance (num_glyphs); 406 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 407 return_trace (true); 408 } 409 410 inline bool sanitize (hb_sanitize_context_t *c) const 411 { 412 TRACE_SANITIZE (this); 413 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); 414 } 415 416 protected: 417 USHORT format; /* Format identifier--format = 1 */ 418 OffsetTo<Coverage> 419 coverage; /* Offset to Coverage table--from 420 * beginning of Substitution table */ 421 OffsetArrayOf<Sequence> 422 sequence; /* Array of Sequence tables 423 * ordered by Coverage Index */ 424 public: 425 DEFINE_SIZE_ARRAY (6, sequence); 426 }; 427 428 struct MultipleSubst 429 { 430 inline bool serialize (hb_serialize_context_t *c, 431 Supplier<GlyphID> &glyphs, 432 Supplier<unsigned int> &substitute_len_list, 433 unsigned int num_glyphs, 434 Supplier<GlyphID> &substitute_glyphs_list) 435 { 436 TRACE_SERIALIZE (this); 437 if (unlikely (!c->extend_min (u.format))) return_trace (false); 438 unsigned int format = 1; 439 u.format.set (format); 440 switch (u.format) { 441 case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); 442 default:return_trace (false); 443 } 444 } 445 446 template <typename context_t> 447 inline typename context_t::return_t dispatch (context_t *c) const 448 { 449 TRACE_DISPATCH (this, u.format); 450 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 451 switch (u.format) { 452 case 1: return_trace (c->dispatch (u.format1)); 453 default:return_trace (c->default_return_value ()); 454 } 455 } 456 457 protected: 458 union { 459 USHORT format; /* Format identifier */ 460 MultipleSubstFormat1 format1; 461 } u; 462 }; 463 464 465 typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in 466 * arbitrary order */ 467 468 struct AlternateSubstFormat1 469 { 470 inline void closure (hb_closure_context_t *c) const 471 { 472 TRACE_CLOSURE (this); 473 Coverage::Iter iter; 474 for (iter.init (this+coverage); iter.more (); iter.next ()) { 475 if (c->glyphs->has (iter.get_glyph ())) { 476 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 477 unsigned int count = alt_set.len; 478 for (unsigned int i = 0; i < count; i++) 479 c->glyphs->add (alt_set[i]); 480 } 481 } 482 } 483 484 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 485 { 486 TRACE_COLLECT_GLYPHS (this); 487 Coverage::Iter iter; 488 for (iter.init (this+coverage); iter.more (); iter.next ()) { 489 c->input->add (iter.get_glyph ()); 490 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 491 unsigned int count = alt_set.len; 492 for (unsigned int i = 0; i < count; i++) 493 c->output->add (alt_set[i]); 494 } 495 } 496 497 inline const Coverage &get_coverage (void) const 498 { 499 return this+coverage; 500 } 501 502 inline bool would_apply (hb_would_apply_context_t *c) const 503 { 504 TRACE_WOULD_APPLY (this); 505 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 506 } 507 508 inline bool apply (hb_apply_context_t *c) const 509 { 510 TRACE_APPLY (this); 511 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 512 513 unsigned int index = (this+coverage).get_coverage (glyph_id); 514 if (likely (index == NOT_COVERED)) return_trace (false); 515 516 const AlternateSet &alt_set = this+alternateSet[index]; 517 518 if (unlikely (!alt_set.len)) return_trace (false); 519 520 hb_mask_t glyph_mask = c->buffer->cur().mask; 521 hb_mask_t lookup_mask = c->lookup_mask; 522 523 /* Note: This breaks badly if two features enabled this lookup together. */ 524 unsigned int shift = _hb_ctz (lookup_mask); 525 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); 526 527 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false); 528 529 glyph_id = alt_set[alt_index - 1]; 530 531 c->replace_glyph (glyph_id); 532 533 return_trace (true); 534 } 535 536 inline bool serialize (hb_serialize_context_t *c, 537 Supplier<GlyphID> &glyphs, 538 Supplier<unsigned int> &alternate_len_list, 539 unsigned int num_glyphs, 540 Supplier<GlyphID> &alternate_glyphs_list) 541 { 542 TRACE_SERIALIZE (this); 543 if (unlikely (!c->extend_min (*this))) return_trace (false); 544 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false); 545 for (unsigned int i = 0; i < num_glyphs; i++) 546 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c, 547 alternate_glyphs_list, 548 alternate_len_list[i]))) return_trace (false); 549 alternate_len_list.advance (num_glyphs); 550 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); 551 return_trace (true); 552 } 553 554 inline bool sanitize (hb_sanitize_context_t *c) const 555 { 556 TRACE_SANITIZE (this); 557 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); 558 } 559 560 protected: 561 USHORT format; /* Format identifier--format = 1 */ 562 OffsetTo<Coverage> 563 coverage; /* Offset to Coverage table--from 564 * beginning of Substitution table */ 565 OffsetArrayOf<AlternateSet> 566 alternateSet; /* Array of AlternateSet tables 567 * ordered by Coverage Index */ 568 public: 569 DEFINE_SIZE_ARRAY (6, alternateSet); 570 }; 571 572 struct AlternateSubst 573 { 574 inline bool serialize (hb_serialize_context_t *c, 575 Supplier<GlyphID> &glyphs, 576 Supplier<unsigned int> &alternate_len_list, 577 unsigned int num_glyphs, 578 Supplier<GlyphID> &alternate_glyphs_list) 579 { 580 TRACE_SERIALIZE (this); 581 if (unlikely (!c->extend_min (u.format))) return_trace (false); 582 unsigned int format = 1; 583 u.format.set (format); 584 switch (u.format) { 585 case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); 586 default:return_trace (false); 587 } 588 } 589 590 template <typename context_t> 591 inline typename context_t::return_t dispatch (context_t *c) const 592 { 593 TRACE_DISPATCH (this, u.format); 594 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 595 switch (u.format) { 596 case 1: return_trace (c->dispatch (u.format1)); 597 default:return_trace (c->default_return_value ()); 598 } 599 } 600 601 protected: 602 union { 603 USHORT format; /* Format identifier */ 604 AlternateSubstFormat1 format1; 605 } u; 606 }; 607 608 609 struct Ligature 610 { 611 inline void closure (hb_closure_context_t *c) const 612 { 613 TRACE_CLOSURE (this); 614 unsigned int count = component.len; 615 for (unsigned int i = 1; i < count; i++) 616 if (!c->glyphs->has (component[i])) 617 return; 618 c->glyphs->add (ligGlyph); 619 } 620 621 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 622 { 623 TRACE_COLLECT_GLYPHS (this); 624 unsigned int count = component.len; 625 for (unsigned int i = 1; i < count; i++) 626 c->input->add (component[i]); 627 c->output->add (ligGlyph); 628 } 629 630 inline bool would_apply (hb_would_apply_context_t *c) const 631 { 632 TRACE_WOULD_APPLY (this); 633 if (c->len != component.len) 634 return_trace (false); 635 636 for (unsigned int i = 1; i < c->len; i++) 637 if (likely (c->glyphs[i] != component[i])) 638 return_trace (false); 639 640 return_trace (true); 641 } 642 643 inline bool apply (hb_apply_context_t *c) const 644 { 645 TRACE_APPLY (this); 646 unsigned int count = component.len; 647 648 if (unlikely (!count)) return_trace (false); 649 650 /* Special-case to make it in-place and not consider this 651 * as a "ligated" substitution. */ 652 if (unlikely (count == 1)) 653 { 654 c->replace_glyph (ligGlyph); 655 return_trace (true); 656 } 657 658 bool is_mark_ligature = false; 659 unsigned int total_component_count = 0; 660 661 unsigned int match_length = 0; 662 unsigned int match_positions[MAX_CONTEXT_LENGTH]; 663 664 if (likely (!match_input (c, count, 665 &component[1], 666 match_glyph, 667 NULL, 668 &match_length, 669 match_positions, 670 &is_mark_ligature, 671 &total_component_count))) 672 return_trace (false); 673 674 ligate_input (c, 675 count, 676 match_positions, 677 match_length, 678 ligGlyph, 679 is_mark_ligature, 680 total_component_count); 681 682 return_trace (true); 683 } 684 685 inline bool serialize (hb_serialize_context_t *c, 686 GlyphID ligature, 687 Supplier<GlyphID> &components, /* Starting from second */ 688 unsigned int num_components /* Including first component */) 689 { 690 TRACE_SERIALIZE (this); 691 if (unlikely (!c->extend_min (*this))) return_trace (false); 692 ligGlyph = ligature; 693 if (unlikely (!component.serialize (c, components, num_components))) return_trace (false); 694 return_trace (true); 695 } 696 697 public: 698 inline bool sanitize (hb_sanitize_context_t *c) const 699 { 700 TRACE_SANITIZE (this); 701 return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); 702 } 703 704 protected: 705 GlyphID ligGlyph; /* GlyphID of ligature to substitute */ 706 HeadlessArrayOf<GlyphID> 707 component; /* Array of component GlyphIDs--start 708 * with the second component--ordered 709 * in writing direction */ 710 public: 711 DEFINE_SIZE_ARRAY (4, component); 712 }; 713 714 struct LigatureSet 715 { 716 inline void closure (hb_closure_context_t *c) const 717 { 718 TRACE_CLOSURE (this); 719 unsigned int num_ligs = ligature.len; 720 for (unsigned int i = 0; i < num_ligs; i++) 721 (this+ligature[i]).closure (c); 722 } 723 724 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 725 { 726 TRACE_COLLECT_GLYPHS (this); 727 unsigned int num_ligs = ligature.len; 728 for (unsigned int i = 0; i < num_ligs; i++) 729 (this+ligature[i]).collect_glyphs (c); 730 } 731 732 inline bool would_apply (hb_would_apply_context_t *c) const 733 { 734 TRACE_WOULD_APPLY (this); 735 unsigned int num_ligs = ligature.len; 736 for (unsigned int i = 0; i < num_ligs; i++) 737 { 738 const Ligature &lig = this+ligature[i]; 739 if (lig.would_apply (c)) 740 return_trace (true); 741 } 742 return_trace (false); 743 } 744 745 inline bool apply (hb_apply_context_t *c) const 746 { 747 TRACE_APPLY (this); 748 unsigned int num_ligs = ligature.len; 749 for (unsigned int i = 0; i < num_ligs; i++) 750 { 751 const Ligature &lig = this+ligature[i]; 752 if (lig.apply (c)) return_trace (true); 753 } 754 755 return_trace (false); 756 } 757 758 inline bool serialize (hb_serialize_context_t *c, 759 Supplier<GlyphID> &ligatures, 760 Supplier<unsigned int> &component_count_list, 761 unsigned int num_ligatures, 762 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 763 { 764 TRACE_SERIALIZE (this); 765 if (unlikely (!c->extend_min (*this))) return_trace (false); 766 if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false); 767 for (unsigned int i = 0; i < num_ligatures; i++) 768 if (unlikely (!ligature[i].serialize (c, this).serialize (c, 769 ligatures[i], 770 component_list, 771 component_count_list[i]))) return_trace (false); 772 ligatures.advance (num_ligatures); 773 component_count_list.advance (num_ligatures); 774 return_trace (true); 775 } 776 777 inline bool sanitize (hb_sanitize_context_t *c) const 778 { 779 TRACE_SANITIZE (this); 780 return_trace (ligature.sanitize (c, this)); 781 } 782 783 protected: 784 OffsetArrayOf<Ligature> 785 ligature; /* Array LigatureSet tables 786 * ordered by preference */ 787 public: 788 DEFINE_SIZE_ARRAY (2, ligature); 789 }; 790 791 struct LigatureSubstFormat1 792 { 793 inline void closure (hb_closure_context_t *c) const 794 { 795 TRACE_CLOSURE (this); 796 Coverage::Iter iter; 797 for (iter.init (this+coverage); iter.more (); iter.next ()) { 798 if (c->glyphs->has (iter.get_glyph ())) 799 (this+ligatureSet[iter.get_coverage ()]).closure (c); 800 } 801 } 802 803 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 804 { 805 TRACE_COLLECT_GLYPHS (this); 806 Coverage::Iter iter; 807 for (iter.init (this+coverage); iter.more (); iter.next ()) { 808 c->input->add (iter.get_glyph ()); 809 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c); 810 } 811 } 812 813 inline const Coverage &get_coverage (void) const 814 { 815 return this+coverage; 816 } 817 818 inline bool would_apply (hb_would_apply_context_t *c) const 819 { 820 TRACE_WOULD_APPLY (this); 821 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); 822 if (likely (index == NOT_COVERED)) return_trace (false); 823 824 const LigatureSet &lig_set = this+ligatureSet[index]; 825 return_trace (lig_set.would_apply (c)); 826 } 827 828 inline bool apply (hb_apply_context_t *c) const 829 { 830 TRACE_APPLY (this); 831 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 832 833 unsigned int index = (this+coverage).get_coverage (glyph_id); 834 if (likely (index == NOT_COVERED)) return_trace (false); 835 836 const LigatureSet &lig_set = this+ligatureSet[index]; 837 return_trace (lig_set.apply (c)); 838 } 839 840 inline bool serialize (hb_serialize_context_t *c, 841 Supplier<GlyphID> &first_glyphs, 842 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 843 unsigned int num_first_glyphs, 844 Supplier<GlyphID> &ligatures_list, 845 Supplier<unsigned int> &component_count_list, 846 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 847 { 848 TRACE_SERIALIZE (this); 849 if (unlikely (!c->extend_min (*this))) return_trace (false); 850 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false); 851 for (unsigned int i = 0; i < num_first_glyphs; i++) 852 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c, 853 ligatures_list, 854 component_count_list, 855 ligature_per_first_glyph_count_list[i], 856 component_list))) return_trace (false); 857 ligature_per_first_glyph_count_list.advance (num_first_glyphs); 858 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false); 859 return_trace (true); 860 } 861 862 inline bool sanitize (hb_sanitize_context_t *c) const 863 { 864 TRACE_SANITIZE (this); 865 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); 866 } 867 868 protected: 869 USHORT format; /* Format identifier--format = 1 */ 870 OffsetTo<Coverage> 871 coverage; /* Offset to Coverage table--from 872 * beginning of Substitution table */ 873 OffsetArrayOf<LigatureSet> 874 ligatureSet; /* Array LigatureSet tables 875 * ordered by Coverage Index */ 876 public: 877 DEFINE_SIZE_ARRAY (6, ligatureSet); 878 }; 879 880 struct LigatureSubst 881 { 882 inline bool serialize (hb_serialize_context_t *c, 883 Supplier<GlyphID> &first_glyphs, 884 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 885 unsigned int num_first_glyphs, 886 Supplier<GlyphID> &ligatures_list, 887 Supplier<unsigned int> &component_count_list, 888 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 889 { 890 TRACE_SERIALIZE (this); 891 if (unlikely (!c->extend_min (u.format))) return_trace (false); 892 unsigned int format = 1; 893 u.format.set (format); 894 switch (u.format) { 895 case 1: return_trace (u.format1.serialize (c, 896 first_glyphs, 897 ligature_per_first_glyph_count_list, 898 num_first_glyphs, 899 ligatures_list, 900 component_count_list, 901 component_list)); 902 default:return_trace (false); 903 } 904 } 905 906 template <typename context_t> 907 inline typename context_t::return_t dispatch (context_t *c) const 908 { 909 TRACE_DISPATCH (this, u.format); 910 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 911 switch (u.format) { 912 case 1: return_trace (c->dispatch (u.format1)); 913 default:return_trace (c->default_return_value ()); 914 } 915 } 916 917 protected: 918 union { 919 USHORT format; /* Format identifier */ 920 LigatureSubstFormat1 format1; 921 } u; 922 }; 923 924 925 struct ContextSubst : Context {}; 926 927 struct ChainContextSubst : ChainContext {}; 928 929 struct ExtensionSubst : Extension<ExtensionSubst> 930 { 931 typedef struct SubstLookupSubTable LookupSubTable; 932 933 inline bool is_reverse (void) const; 934 }; 935 936 937 struct ReverseChainSingleSubstFormat1 938 { 939 inline void closure (hb_closure_context_t *c) const 940 { 941 TRACE_CLOSURE (this); 942 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 943 944 unsigned int count; 945 946 count = backtrack.len; 947 for (unsigned int i = 0; i < count; i++) 948 if (!(this+backtrack[i]).intersects (c->glyphs)) 949 return; 950 951 count = lookahead.len; 952 for (unsigned int i = 0; i < count; i++) 953 if (!(this+lookahead[i]).intersects (c->glyphs)) 954 return; 955 956 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 957 Coverage::Iter iter; 958 for (iter.init (this+coverage); iter.more (); iter.next ()) { 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 968 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 969 970 unsigned int count; 971 972 (this+coverage).add_coverage (c->input); 973 974 count = backtrack.len; 975 for (unsigned int i = 0; i < count; i++) 976 (this+backtrack[i]).add_coverage (c->before); 977 978 count = lookahead.len; 979 for (unsigned int i = 0; i < count; i++) 980 (this+lookahead[i]).add_coverage (c->after); 981 982 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 983 count = substitute.len; 984 for (unsigned int i = 0; i < count; i++) 985 c->output->add (substitute[i]); 986 } 987 988 inline const Coverage &get_coverage (void) const 989 { 990 return this+coverage; 991 } 992 993 inline bool would_apply (hb_would_apply_context_t *c) const 994 { 995 TRACE_WOULD_APPLY (this); 996 return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 997 } 998 999 inline bool apply (hb_apply_context_t *c) const 1000 { 1001 TRACE_APPLY (this); 1002 if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL)) 1003 return_trace (false); /* No chaining to this type */ 1004 1005 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1006 if (likely (index == NOT_COVERED)) return_trace (false); 1007 1008 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1009 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1010 1011 if (match_backtrack (c, 1012 backtrack.len, (USHORT *) backtrack.array, 1013 match_coverage, this) && 1014 match_lookahead (c, 1015 lookahead.len, (USHORT *) lookahead.array, 1016 match_coverage, this, 1017 1)) 1018 { 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 USHORT 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 USHORT 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 USHORT 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. This is specially important if one has 1275 * a reverse type! */ 1276 unsigned int type = get_subtable (0).u.extension.get_type (); 1277 unsigned int count = get_subtable_count (); 1278 for (unsigned int i = 1; i < count; i++) 1279 if (get_subtable (i).u.extension.get_type () != type) 1280 return_trace (false); 1281 } 1282 return_trace (true); 1283 } 1284 }; 1285 1286 typedef OffsetListOf<SubstLookup> SubstLookupList; 1287 1288 /* 1289 * GSUB -- The Glyph Substitution Table 1290 */ 1291 1292 struct GSUB : GSUBGPOS 1293 { 1294 static const hb_tag_t tableTag = HB_OT_TAG_GSUB; 1295 1296 inline const SubstLookup& get_lookup (unsigned int i) const 1297 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } 1298 1299 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); 1300 static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer); 1301 1302 inline bool sanitize (hb_sanitize_context_t *c) const 1303 { 1304 TRACE_SANITIZE (this); 1305 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); 1306 const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); 1307 return_trace (list.sanitize (c, this)); 1308 } 1309 public: 1310 DEFINE_SIZE_STATIC (10); 1311 }; 1312 1313 1314 void 1315 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) 1316 { 1317 _hb_buffer_assert_gsubgpos_vars (buffer); 1318 1319 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; 1320 unsigned int count = buffer->len; 1321 for (unsigned int i = 0; i < count; i++) 1322 { 1323 _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); 1324 _hb_glyph_info_clear_lig_props (&buffer->info[i]); 1325 buffer->info[i].syllable() = 0; 1326 } 1327 } 1328 1329 void 1330 GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) 1331 { 1332 } 1333 1334 1335 /* Out-of-class implementation for methods recursing */ 1336 1337 /*static*/ inline bool ExtensionSubst::is_reverse (void) const 1338 { 1339 unsigned int type = get_type (); 1340 if (unlikely (type == SubstLookupSubTable::Extension)) 1341 return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse (); 1342 return SubstLookup::lookup_type_is_reverse (type); 1343 } 1344 1345 template <typename context_t> 1346 /*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) 1347 { 1348 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1349 const SubstLookup &l = gsub.get_lookup (lookup_index); 1350 return l.dispatch (c); 1351 } 1352 1353 /*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) 1354 { 1355 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1356 const SubstLookup &l = gsub.get_lookup (lookup_index); 1357 unsigned int saved_lookup_props = c->lookup_props; 1358 unsigned int saved_lookup_index = c->lookup_index; 1359 c->set_lookup_index (lookup_index); 1360 c->set_lookup_props (l.get_props ()); 1361 bool ret = l.dispatch (c); 1362 c->set_lookup_index (saved_lookup_index); 1363 c->set_lookup_props (saved_lookup_props); 1364 return ret; 1365 } 1366 1367 1368 } /* namespace OT */ 1369 1370 1371 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */