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