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