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