1 /* 2 * Copyright © 2017 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_AAT_LAYOUT_MORX_TABLE_HH 28 #define HB_AAT_LAYOUT_MORX_TABLE_HH 29 30 #include "hb-open-type.hh" 31 #include "hb-aat-layout-common.hh" 32 #include "hb-ot-layout-common.hh" 33 #include "hb-ot-layout-gdef-table.hh" 34 #include "hb-aat-map.hh" 35 36 /* 37 * morx -- Extended Glyph Metamorphosis 38 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html 39 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html 40 */ 41 #define HB_AAT_TAG_morx HB_TAG('m','o','r','x') 42 #define HB_AAT_TAG_mort HB_TAG('m','o','r','t') 43 44 45 namespace AAT { 46 47 using namespace OT; 48 49 template <typename Types> 50 struct RearrangementSubtable 51 { 52 typedef typename Types::HBUINT HBUINT; 53 54 typedef void EntryData; 55 56 struct driver_context_t 57 { 58 static constexpr bool in_place = true; 59 enum Flags 60 { 61 MarkFirst = 0x8000, /* If set, make the current glyph the first 62 * glyph to be rearranged. */ 63 DontAdvance = 0x4000, /* If set, don't advance to the next glyph 64 * before going to the new state. This means 65 * that the glyph index doesn't change, even 66 * if the glyph at that index has changed. */ 67 MarkLast = 0x2000, /* If set, make the current glyph the last 68 * glyph to be rearranged. */ 69 Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */ 70 Verb = 0x000F, /* The type of rearrangement specified. */ 71 }; 72 driver_context_tAAT::RearrangementSubtable::driver_context_t73 driver_context_t (const RearrangementSubtable *table HB_UNUSED) : 74 ret (false), 75 start (0), end (0) {} 76 is_actionableAAT::RearrangementSubtable::driver_context_t77 bool is_actionable (hb_buffer_t *buffer HB_UNUSED, 78 StateTableDriver<Types, EntryData> *driver HB_UNUSED, 79 const Entry<EntryData> &entry) const 80 { 81 return (entry.flags & Verb) && start < end; 82 } transitionAAT::RearrangementSubtable::driver_context_t83 void transition (hb_buffer_t *buffer, 84 StateTableDriver<Types, EntryData> *driver, 85 const Entry<EntryData> &entry) 86 { 87 unsigned int flags = entry.flags; 88 89 if (flags & MarkFirst) 90 start = buffer->idx; 91 92 if (flags & MarkLast) 93 end = hb_min (buffer->idx + 1, buffer->len); 94 95 if ((flags & Verb) && start < end) 96 { 97 /* The following map has two nibbles, for start-side 98 * and end-side. Values of 0,1,2 mean move that many 99 * to the other side. Value of 3 means move 2 and 100 * flip them. */ 101 const unsigned char map[16] = 102 { 103 0x00, /* 0 no change */ 104 0x10, /* 1 Ax => xA */ 105 0x01, /* 2 xD => Dx */ 106 0x11, /* 3 AxD => DxA */ 107 0x20, /* 4 ABx => xAB */ 108 0x30, /* 5 ABx => xBA */ 109 0x02, /* 6 xCD => CDx */ 110 0x03, /* 7 xCD => DCx */ 111 0x12, /* 8 AxCD => CDxA */ 112 0x13, /* 9 AxCD => DCxA */ 113 0x21, /* 10 ABxD => DxAB */ 114 0x31, /* 11 ABxD => DxBA */ 115 0x22, /* 12 ABxCD => CDxAB */ 116 0x32, /* 13 ABxCD => CDxBA */ 117 0x23, /* 14 ABxCD => DCxAB */ 118 0x33, /* 15 ABxCD => DCxBA */ 119 }; 120 121 unsigned int m = map[flags & Verb]; 122 unsigned int l = hb_min (2u, m >> 4); 123 unsigned int r = hb_min (2u, m & 0x0F); 124 bool reverse_l = 3 == (m >> 4); 125 bool reverse_r = 3 == (m & 0x0F); 126 127 if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH) 128 { 129 buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len)); 130 buffer->merge_clusters (start, end); 131 132 hb_glyph_info_t *info = buffer->info; 133 hb_glyph_info_t buf[4]; 134 135 hb_memcpy (buf, info + start, l * sizeof (buf[0])); 136 hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); 137 138 if (l != r) 139 memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0])); 140 141 hb_memcpy (info + start, buf + 2, r * sizeof (buf[0])); 142 hb_memcpy (info + end - l, buf, l * sizeof (buf[0])); 143 if (reverse_l) 144 { 145 buf[0] = info[end - 1]; 146 info[end - 1] = info[end - 2]; 147 info[end - 2] = buf[0]; 148 } 149 if (reverse_r) 150 { 151 buf[0] = info[start]; 152 info[start] = info[start + 1]; 153 info[start + 1] = buf[0]; 154 } 155 } 156 } 157 } 158 159 public: 160 bool ret; 161 private: 162 unsigned int start; 163 unsigned int end; 164 }; 165 applyAAT::RearrangementSubtable166 bool apply (hb_aat_apply_context_t *c) const 167 { 168 TRACE_APPLY (this); 169 170 driver_context_t dc (this); 171 172 StateTableDriver<Types, EntryData> driver (machine, c->face); 173 174 if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 175 !c->buffer_digest.may_have (c->machine_glyph_set)) 176 return_trace (false); 177 178 driver.drive (&dc, c); 179 180 return_trace (dc.ret); 181 } 182 sanitizeAAT::RearrangementSubtable183 bool sanitize (hb_sanitize_context_t *c) const 184 { 185 TRACE_SANITIZE (this); 186 return_trace (machine.sanitize (c)); 187 } 188 189 public: 190 StateTable<Types, EntryData> machine; 191 public: 192 DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size)); 193 }; 194 195 template <typename Types> 196 struct ContextualSubtable 197 { 198 typedef typename Types::HBUINT HBUINT; 199 200 struct EntryData 201 { 202 HBUINT16 markIndex; /* Index of the substitution table for the 203 * marked glyph (use 0xFFFF for none). */ 204 HBUINT16 currentIndex; /* Index of the substitution table for the 205 * current glyph (use 0xFFFF for none). */ 206 public: 207 DEFINE_SIZE_STATIC (4); 208 }; 209 210 struct driver_context_t 211 { 212 static constexpr bool in_place = true; 213 enum Flags 214 { 215 SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ 216 DontAdvance = 0x4000, /* If set, don't advance to the next glyph before 217 * going to the new state. */ 218 Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */ 219 }; 220 driver_context_tAAT::ContextualSubtable::driver_context_t221 driver_context_t (const ContextualSubtable *table_, 222 hb_aat_apply_context_t *c_) : 223 ret (false), 224 c (c_), 225 gdef (*c->gdef_table), 226 mark_set (false), 227 has_glyph_classes (gdef.has_glyph_classes ()), 228 mark (0), 229 table (table_), 230 subs (table+table->substitutionTables) {} 231 is_actionableAAT::ContextualSubtable::driver_context_t232 bool is_actionable (hb_buffer_t *buffer, 233 StateTableDriver<Types, EntryData> *driver, 234 const Entry<EntryData> &entry) const 235 { 236 if (buffer->idx == buffer->len && !mark_set) 237 return false; 238 239 return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; 240 } transitionAAT::ContextualSubtable::driver_context_t241 void transition (hb_buffer_t *buffer, 242 StateTableDriver<Types, EntryData> *driver, 243 const Entry<EntryData> &entry) 244 { 245 /* Looks like CoreText applies neither mark nor current substitution for 246 * end-of-text if mark was not explicitly set. */ 247 if (buffer->idx == buffer->len && !mark_set) 248 return; 249 250 const HBGlyphID16 *replacement; 251 252 replacement = nullptr; 253 if (Types::extended) 254 { 255 if (entry.data.markIndex != 0xFFFF) 256 { 257 const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex]; 258 replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs); 259 } 260 } 261 else 262 { 263 unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; 264 const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs; 265 replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; 266 if (!(replacement->sanitize (&c->sanitizer) && 267 hb_barrier () && 268 *replacement)) 269 replacement = nullptr; 270 } 271 if (replacement) 272 { 273 buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); 274 buffer->info[mark].codepoint = *replacement; 275 c->buffer_digest.add (*replacement); 276 if (has_glyph_classes) 277 _hb_glyph_info_set_glyph_props (&buffer->info[mark], 278 gdef.get_glyph_props (*replacement)); 279 ret = true; 280 } 281 282 replacement = nullptr; 283 unsigned int idx = hb_min (buffer->idx, buffer->len - 1); 284 if (Types::extended) 285 { 286 if (entry.data.currentIndex != 0xFFFF) 287 { 288 const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex]; 289 replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs); 290 } 291 } 292 else 293 { 294 unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; 295 const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs; 296 replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; 297 if (!(replacement->sanitize (&c->sanitizer) && 298 hb_barrier () && 299 *replacement)) 300 replacement = nullptr; 301 } 302 if (replacement) 303 { 304 buffer->info[idx].codepoint = *replacement; 305 c->buffer_digest.add (*replacement); 306 if (has_glyph_classes) 307 _hb_glyph_info_set_glyph_props (&buffer->info[idx], 308 gdef.get_glyph_props (*replacement)); 309 ret = true; 310 } 311 312 if (entry.flags & SetMark) 313 { 314 mark_set = true; 315 mark = buffer->idx; 316 } 317 } 318 319 public: 320 bool ret; 321 private: 322 hb_aat_apply_context_t *c; 323 const OT::GDEF &gdef; 324 bool mark_set; 325 bool has_glyph_classes; 326 unsigned int mark; 327 const ContextualSubtable *table; 328 const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs; 329 }; 330 applyAAT::ContextualSubtable331 bool apply (hb_aat_apply_context_t *c) const 332 { 333 TRACE_APPLY (this); 334 335 driver_context_t dc (this, c); 336 337 StateTableDriver<Types, EntryData> driver (machine, c->face); 338 339 if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 340 !c->buffer_digest.may_have (c->machine_glyph_set)) 341 return_trace (false); 342 343 driver.drive (&dc, c); 344 345 return_trace (dc.ret); 346 } 347 sanitizeAAT::ContextualSubtable348 bool sanitize (hb_sanitize_context_t *c) const 349 { 350 TRACE_SANITIZE (this); 351 352 unsigned int num_entries = 0; 353 if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false); 354 hb_barrier (); 355 356 if (!Types::extended) 357 return_trace (substitutionTables.sanitize (c, this, 0)); 358 359 unsigned int num_lookups = 0; 360 361 const Entry<EntryData> *entries = machine.get_entries (); 362 for (unsigned int i = 0; i < num_entries; i++) 363 { 364 const EntryData &data = entries[i].data; 365 366 if (data.markIndex != 0xFFFF) 367 num_lookups = hb_max (num_lookups, 1u + data.markIndex); 368 if (data.currentIndex != 0xFFFF) 369 num_lookups = hb_max (num_lookups, 1u + data.currentIndex); 370 } 371 372 return_trace (substitutionTables.sanitize (c, this, num_lookups)); 373 } 374 375 public: 376 StateTable<Types, EntryData> 377 machine; 378 protected: 379 NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT> 380 substitutionTables; 381 public: 382 DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size)); 383 }; 384 385 386 template <bool extended> 387 struct LigatureEntry; 388 389 template <> 390 struct LigatureEntry<true> 391 { 392 enum Flags 393 { 394 SetComponent = 0x8000, /* Push this glyph onto the component stack for 395 * eventual processing. */ 396 DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the 397 next iteration. */ 398 PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature 399 * group. */ 400 Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ 401 }; 402 403 struct EntryData 404 { 405 HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry 406 * for processing this group, if indicated 407 * by the flags. */ 408 public: 409 DEFINE_SIZE_STATIC (2); 410 }; 411 performActionAAT::LigatureEntry412 static bool performAction (const Entry<EntryData> &entry) 413 { return entry.flags & PerformAction; } 414 ligActionIndexAAT::LigatureEntry415 static unsigned int ligActionIndex (const Entry<EntryData> &entry) 416 { return entry.data.ligActionIndex; } 417 }; 418 template <> 419 struct LigatureEntry<false> 420 { 421 enum Flags 422 { 423 SetComponent = 0x8000, /* Push this glyph onto the component stack for 424 * eventual processing. */ 425 DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the 426 next iteration. */ 427 Offset = 0x3FFF, /* Byte offset from beginning of subtable to the 428 * ligature action list. This value must be a 429 * multiple of 4. */ 430 }; 431 432 typedef void EntryData; 433 performActionAAT::LigatureEntry434 static bool performAction (const Entry<EntryData> &entry) 435 { return entry.flags & Offset; } 436 ligActionIndexAAT::LigatureEntry437 static unsigned int ligActionIndex (const Entry<EntryData> &entry) 438 { return entry.flags & Offset; } 439 }; 440 441 442 template <typename Types> 443 struct LigatureSubtable 444 { 445 typedef typename Types::HBUINT HBUINT; 446 447 typedef LigatureEntry<Types::extended> LigatureEntryT; 448 typedef typename LigatureEntryT::EntryData EntryData; 449 450 struct driver_context_t 451 { 452 static constexpr bool in_place = false; 453 enum 454 { 455 DontAdvance = LigatureEntryT::DontAdvance, 456 }; 457 enum LigActionFlags 458 { 459 LigActionLast = 0x80000000, /* This is the last action in the list. This also 460 * implies storage. */ 461 LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index 462 * in the ligature table in place of the marked 463 * (i.e. currently-popped) glyph. */ 464 LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits 465 * and added to the glyph ID, resulting in an index 466 * into the component table. */ 467 }; 468 driver_context_tAAT::LigatureSubtable::driver_context_t469 driver_context_t (const LigatureSubtable *table_, 470 hb_aat_apply_context_t *c_) : 471 ret (false), 472 c (c_), 473 table (table_), 474 ligAction (table+table->ligAction), 475 component (table+table->component), 476 ligature (table+table->ligature), 477 match_length (0) {} 478 is_actionableAAT::LigatureSubtable::driver_context_t479 bool is_actionable (hb_buffer_t *buffer HB_UNUSED, 480 StateTableDriver<Types, EntryData> *driver HB_UNUSED, 481 const Entry<EntryData> &entry) const 482 { 483 return LigatureEntryT::performAction (entry); 484 } transitionAAT::LigatureSubtable::driver_context_t485 void transition (hb_buffer_t *buffer, 486 StateTableDriver<Types, EntryData> *driver, 487 const Entry<EntryData> &entry) 488 { 489 DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); 490 if (entry.flags & LigatureEntryT::SetComponent) 491 { 492 /* Never mark same index twice, in case DontAdvance was used... */ 493 if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len) 494 match_length--; 495 496 match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len; 497 DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len); 498 } 499 500 if (LigatureEntryT::performAction (entry)) 501 { 502 DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length); 503 unsigned int end = buffer->out_len; 504 505 if (unlikely (!match_length)) 506 return; 507 508 if (buffer->idx >= buffer->len) 509 return; /* TODO Work on previous instead? */ 510 511 unsigned int cursor = match_length; 512 513 unsigned int action_idx = LigatureEntryT::ligActionIndex (entry); 514 action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ); 515 const HBUINT32 *actionData = &ligAction[action_idx]; 516 517 unsigned int ligature_idx = 0; 518 unsigned int action; 519 do 520 { 521 if (unlikely (!cursor)) 522 { 523 /* Stack underflow. Clear the stack. */ 524 DEBUG_MSG (APPLY, nullptr, "Stack underflow"); 525 match_length = 0; 526 break; 527 } 528 529 DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1); 530 if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return; 531 532 if (unlikely (!actionData->sanitize (&c->sanitizer))) break; 533 hb_barrier (); 534 action = *actionData; 535 536 uint32_t uoffset = action & LigActionOffset; 537 if (uoffset & 0x20000000) 538 uoffset |= 0xC0000000; /* Sign-extend. */ 539 int32_t offset = (int32_t) uoffset; 540 unsigned int component_idx = buffer->cur().codepoint + offset; 541 component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ); 542 const HBUINT16 &componentData = component[component_idx]; 543 if (unlikely (!componentData.sanitize (&c->sanitizer))) break; 544 hb_barrier (); 545 ligature_idx += componentData; 546 547 DEBUG_MSG (APPLY, nullptr, "Action store %d last %d", 548 bool (action & LigActionStore), 549 bool (action & LigActionLast)); 550 if (action & (LigActionStore | LigActionLast)) 551 { 552 ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); 553 const HBGlyphID16 &ligatureData = ligature[ligature_idx]; 554 if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; 555 hb_barrier (); 556 hb_codepoint_t lig = ligatureData; 557 558 DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); 559 if (unlikely (!buffer->replace_glyph (lig))) return; 560 561 unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u; 562 /* Now go and delete all subsequent components. */ 563 while (match_length - 1u > cursor) 564 { 565 DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); 566 if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; 567 buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE; 568 if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; 569 } 570 571 if (unlikely (!buffer->move_to (lig_end))) return; 572 buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len); 573 } 574 575 actionData++; 576 } 577 while (!(action & LigActionLast)); 578 if (unlikely (!buffer->move_to (end))) return; 579 } 580 } 581 582 public: 583 bool ret; 584 private: 585 hb_aat_apply_context_t *c; 586 const LigatureSubtable *table; 587 const UnsizedArrayOf<HBUINT32> &ligAction; 588 const UnsizedArrayOf<HBUINT16> &component; 589 const UnsizedArrayOf<HBGlyphID16> &ligature; 590 unsigned int match_length; 591 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 592 }; 593 applyAAT::LigatureSubtable594 bool apply (hb_aat_apply_context_t *c) const 595 { 596 TRACE_APPLY (this); 597 598 driver_context_t dc (this, c); 599 600 StateTableDriver<Types, EntryData> driver (machine, c->face); 601 602 if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 603 !c->buffer_digest.may_have (c->machine_glyph_set)) 604 return_trace (false); 605 606 driver.drive (&dc, c); 607 608 return_trace (dc.ret); 609 } 610 sanitizeAAT::LigatureSubtable611 bool sanitize (hb_sanitize_context_t *c) const 612 { 613 TRACE_SANITIZE (this); 614 /* The rest of array sanitizations are done at run-time. */ 615 return_trace (c->check_struct (this) && machine.sanitize (c) && 616 hb_barrier () && 617 ligAction && component && ligature); 618 } 619 620 public: 621 StateTable<Types, EntryData> 622 machine; 623 protected: 624 NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT> 625 ligAction; /* Offset to the ligature action table. */ 626 NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT> 627 component; /* Offset to the component table. */ 628 NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT> 629 ligature; /* Offset to the actual ligature lists. */ 630 public: 631 DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size)); 632 }; 633 634 template <typename Types> 635 struct NoncontextualSubtable 636 { applyAAT::NoncontextualSubtable637 bool apply (hb_aat_apply_context_t *c) const 638 { 639 TRACE_APPLY (this); 640 641 const OT::GDEF &gdef (*c->gdef_table); 642 bool has_glyph_classes = gdef.has_glyph_classes (); 643 644 bool ret = false; 645 unsigned int num_glyphs = c->face->get_num_glyphs (); 646 647 hb_glyph_info_t *info = c->buffer->info; 648 unsigned int count = c->buffer->len; 649 // If there's only one range, we already checked the flag. 650 auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr; 651 for (unsigned int i = 0; i < count; i++) 652 { 653 /* This block copied from StateTableDriver::drive. Keep in sync. */ 654 if (last_range) 655 { 656 auto *range = last_range; 657 { 658 unsigned cluster = info[i].cluster; 659 while (cluster < range->cluster_first) 660 range--; 661 while (cluster > range->cluster_last) 662 range++; 663 664 last_range = range; 665 } 666 if (!(range->flags & c->subtable_flags)) 667 continue; 668 } 669 670 const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); 671 if (replacement) 672 { 673 info[i].codepoint = *replacement; 674 c->buffer_digest.add (*replacement); 675 if (has_glyph_classes) 676 _hb_glyph_info_set_glyph_props (&info[i], 677 gdef.get_glyph_props (*replacement)); 678 ret = true; 679 } 680 } 681 682 return_trace (ret); 683 } 684 sanitizeAAT::NoncontextualSubtable685 bool sanitize (hb_sanitize_context_t *c) const 686 { 687 TRACE_SANITIZE (this); 688 return_trace (substitute.sanitize (c)); 689 } 690 691 protected: 692 Lookup<HBGlyphID16> substitute; 693 public: 694 DEFINE_SIZE_MIN (2); 695 }; 696 697 template <typename Types> 698 struct InsertionSubtable 699 { 700 typedef typename Types::HBUINT HBUINT; 701 702 struct EntryData 703 { 704 HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table. 705 * The number of glyphs to be inserted is contained 706 * in the currentInsertCount field in the flags. 707 * A value of 0xFFFF indicates no insertion is to 708 * be done. */ 709 HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table. 710 * The number of glyphs to be inserted is contained 711 * in the markedInsertCount field in the flags. 712 * A value of 0xFFFF indicates no insertion is to 713 * be done. */ 714 public: 715 DEFINE_SIZE_STATIC (4); 716 }; 717 718 struct driver_context_t 719 { 720 static constexpr bool in_place = false; 721 enum Flags 722 { 723 SetMark = 0x8000, /* If set, mark the current glyph. */ 724 DontAdvance = 0x4000, /* If set, don't advance to the next glyph before 725 * going to the new state. This does not mean 726 * that the glyph pointed to is the same one as 727 * before. If you've made insertions immediately 728 * downstream of the current glyph, the next glyph 729 * processed would in fact be the first one 730 * inserted. */ 731 CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, 732 * then the specified glyph list will be inserted 733 * as a kashida-like insertion, either before or 734 * after the current glyph (depending on the state 735 * of the currentInsertBefore flag). If clear, and 736 * the currentInsertList is nonzero, then the 737 * specified glyph list will be inserted as a 738 * split-vowel-like insertion, either before or 739 * after the current glyph (depending on the state 740 * of the currentInsertBefore flag). */ 741 MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, 742 * then the specified glyph list will be inserted 743 * as a kashida-like insertion, either before or 744 * after the marked glyph (depending on the state 745 * of the markedInsertBefore flag). If clear, and 746 * the markedInsertList is nonzero, then the 747 * specified glyph list will be inserted as a 748 * split-vowel-like insertion, either before or 749 * after the marked glyph (depending on the state 750 * of the markedInsertBefore flag). */ 751 CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made 752 * to the left of the current glyph. If clear, 753 * they're made to the right of the current glyph. */ 754 MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be 755 * made to the left of the marked glyph. If clear, 756 * they're made to the right of the marked glyph. */ 757 CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the 758 * number of glyphs to insert at the current 759 * position. Since zero means no insertions, the 760 * largest number of insertions at any given 761 * current location is 31 glyphs. */ 762 MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the 763 * number of glyphs to insert at the marked 764 * position. Since zero means no insertions, the 765 * largest number of insertions at any given 766 * marked location is 31 glyphs. */ 767 }; 768 driver_context_tAAT::InsertionSubtable::driver_context_t769 driver_context_t (const InsertionSubtable *table, 770 hb_aat_apply_context_t *c_) : 771 ret (false), 772 c (c_), 773 mark (0), 774 insertionAction (table+table->insertionAction) {} 775 is_actionableAAT::InsertionSubtable::driver_context_t776 bool is_actionable (hb_buffer_t *buffer HB_UNUSED, 777 StateTableDriver<Types, EntryData> *driver HB_UNUSED, 778 const Entry<EntryData> &entry) const 779 { 780 return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && 781 (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); 782 } transitionAAT::InsertionSubtable::driver_context_t783 void transition (hb_buffer_t *buffer, 784 StateTableDriver<Types, EntryData> *driver, 785 const Entry<EntryData> &entry) 786 { 787 unsigned int flags = entry.flags; 788 789 unsigned mark_loc = buffer->out_len; 790 791 if (entry.data.markedInsertIndex != 0xFFFF) 792 { 793 unsigned int count = (flags & MarkedInsertCount); 794 if (unlikely ((buffer->max_ops -= count) <= 0)) return; 795 unsigned int start = entry.data.markedInsertIndex; 796 const HBGlyphID16 *glyphs = &insertionAction[start]; 797 if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; 798 hb_barrier (); 799 800 bool before = flags & MarkedInsertBefore; 801 802 unsigned int end = buffer->out_len; 803 if (unlikely (!buffer->move_to (mark))) return; 804 805 if (buffer->idx < buffer->len && !before) 806 if (unlikely (!buffer->copy_glyph ())) return; 807 /* TODO We ignore KashidaLike setting. */ 808 if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 809 for (unsigned int i = 0; i < count; i++) 810 c->buffer_digest.add (glyphs[i]); 811 ret = true; 812 if (buffer->idx < buffer->len && !before) 813 buffer->skip_glyph (); 814 815 if (unlikely (!buffer->move_to (end + count))) return; 816 817 buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len)); 818 } 819 820 if (flags & SetMark) 821 mark = mark_loc; 822 823 if (entry.data.currentInsertIndex != 0xFFFF) 824 { 825 unsigned int count = (flags & CurrentInsertCount) >> 5; 826 if (unlikely ((buffer->max_ops -= count) <= 0)) return; 827 unsigned int start = entry.data.currentInsertIndex; 828 const HBGlyphID16 *glyphs = &insertionAction[start]; 829 if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; 830 hb_barrier (); 831 832 bool before = flags & CurrentInsertBefore; 833 834 unsigned int end = buffer->out_len; 835 836 if (buffer->idx < buffer->len && !before) 837 if (unlikely (!buffer->copy_glyph ())) return; 838 /* TODO We ignore KashidaLike setting. */ 839 if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 840 if (buffer->idx < buffer->len && !before) 841 buffer->skip_glyph (); 842 843 /* Humm. Not sure where to move to. There's this wording under 844 * DontAdvance flag: 845 * 846 * "If set, don't update the glyph index before going to the new state. 847 * This does not mean that the glyph pointed to is the same one as 848 * before. If you've made insertions immediately downstream of the 849 * current glyph, the next glyph processed would in fact be the first 850 * one inserted." 851 * 852 * This suggests that if DontAdvance is NOT set, we should move to 853 * end+count. If it *was*, then move to end, such that newly inserted 854 * glyphs are now visible. 855 * 856 * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417 857 */ 858 if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return; 859 } 860 } 861 862 public: 863 bool ret; 864 private: 865 hb_aat_apply_context_t *c; 866 unsigned int mark; 867 const UnsizedArrayOf<HBGlyphID16> &insertionAction; 868 }; 869 applyAAT::InsertionSubtable870 bool apply (hb_aat_apply_context_t *c) const 871 { 872 TRACE_APPLY (this); 873 874 driver_context_t dc (this, c); 875 876 StateTableDriver<Types, EntryData> driver (machine, c->face); 877 878 if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 879 !c->buffer_digest.may_have (c->machine_glyph_set)) 880 return_trace (false); 881 882 driver.drive (&dc, c); 883 884 return_trace (dc.ret); 885 } 886 sanitizeAAT::InsertionSubtable887 bool sanitize (hb_sanitize_context_t *c) const 888 { 889 TRACE_SANITIZE (this); 890 /* The rest of array sanitizations are done at run-time. */ 891 return_trace (c->check_struct (this) && machine.sanitize (c) && 892 hb_barrier () && 893 insertionAction); 894 } 895 896 public: 897 StateTable<Types, EntryData> 898 machine; 899 protected: 900 NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT> 901 insertionAction; /* Byte offset from stateHeader to the start of 902 * the insertion glyph table. */ 903 public: 904 DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size)); 905 }; 906 907 908 struct Feature 909 { sanitizeAAT::Feature910 bool sanitize (hb_sanitize_context_t *c) const 911 { 912 TRACE_SANITIZE (this); 913 return_trace (c->check_struct (this)); 914 } 915 916 public: 917 HBUINT16 featureType; /* The type of feature. */ 918 HBUINT16 featureSetting; /* The feature's setting (aka selector). */ 919 HBUINT32 enableFlags; /* Flags for the settings that this feature 920 * and setting enables. */ 921 HBUINT32 disableFlags; /* Complement of flags for the settings that this 922 * feature and setting disable. */ 923 924 public: 925 DEFINE_SIZE_STATIC (12); 926 }; 927 928 929 struct hb_accelerate_subtables_context_t : 930 hb_dispatch_context_t<hb_accelerate_subtables_context_t> 931 { 932 struct hb_applicable_t 933 { 934 friend struct hb_accelerate_subtables_context_t; 935 friend struct hb_aat_layout_lookup_accelerator_t; 936 937 public: 938 hb_set_digest_t digest; 939 940 template <typename T> init_AAT::hb_accelerate_subtables_context_t::hb_applicable_t941 auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN 942 ( 943 obj_.machine.collect_glyphs (this->digest, num_glyphs) 944 ) 945 946 template <typename T> 947 void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>) 948 { 949 digest = digest.full (); 950 } 951 952 template <typename T> initAAT::hb_accelerate_subtables_context_t::hb_applicable_t953 void init (const T &obj_, unsigned num_glyphs) 954 { 955 init_ (obj_, num_glyphs, hb_prioritize); 956 } 957 }; 958 959 /* Dispatch interface. */ 960 template <typename T> dispatchAAT::hb_accelerate_subtables_context_t961 return_t dispatch (const T &obj) 962 { 963 hb_applicable_t *entry = &array[i++]; 964 965 entry->init (obj, num_glyphs); 966 967 return hb_empty_t (); 968 } default_return_valueAAT::hb_accelerate_subtables_context_t969 static return_t default_return_value () { return hb_empty_t (); } 970 stop_sublookup_iterationAAT::hb_accelerate_subtables_context_t971 bool stop_sublookup_iteration (return_t r) const { return false; } 972 hb_accelerate_subtables_context_tAAT::hb_accelerate_subtables_context_t973 hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) : 974 hb_dispatch_context_t<hb_accelerate_subtables_context_t> (), 975 array (array_), num_glyphs (num_glyphs_) {} 976 977 hb_applicable_t *array; 978 unsigned num_glyphs; 979 unsigned i = 0; 980 }; 981 982 struct hb_aat_layout_chain_accelerator_t 983 { 984 template <typename TChain> createAAT::hb_aat_layout_chain_accelerator_t985 static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs) 986 { 987 unsigned count = chain.get_subtable_count (); 988 989 unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) - 990 HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) + 991 count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t); 992 993 /* The following is a calloc because when we are collecting subtables, 994 * some of them might be invalid and hence not collect; as a result, 995 * we might not fill in all the count entries of the subtables array. 996 * Zeroing it allows the set digest to gatekeep it without having to 997 * initialize it further. */ 998 auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size); 999 if (unlikely (!thiz)) 1000 return nullptr; 1001 1002 hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs); 1003 chain.dispatch (&c_accelerate_subtables); 1004 1005 return thiz; 1006 } 1007 1008 hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; 1009 }; 1010 1011 template <typename Types> 1012 struct ChainSubtable 1013 { 1014 typedef typename Types::HBUINT HBUINT; 1015 1016 template <typename T> 1017 friend struct Chain; 1018 get_sizeAAT::ChainSubtable1019 unsigned int get_size () const { return length; } get_typeAAT::ChainSubtable1020 unsigned int get_type () const { return coverage & 0xFF; } get_coverageAAT::ChainSubtable1021 unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); } 1022 1023 enum Coverage 1024 { 1025 Vertical = 0x80, /* If set, this subtable will only be applied 1026 * to vertical text. If clear, this subtable 1027 * will only be applied to horizontal text. */ 1028 Backwards = 0x40, /* If set, this subtable will process glyphs 1029 * in descending order. If clear, it will 1030 * process the glyphs in ascending order. */ 1031 AllDirections = 0x20, /* If set, this subtable will be applied to 1032 * both horizontal and vertical text (i.e. 1033 * the state of bit 0x80000000 is ignored). */ 1034 Logical = 0x10, /* If set, this subtable will process glyphs 1035 * in logical order (or reverse logical order, 1036 * depending on the value of bit 0x80000000). */ 1037 }; 1038 enum Type 1039 { 1040 Rearrangement = 0, 1041 Contextual = 1, 1042 Ligature = 2, 1043 Noncontextual = 4, 1044 Insertion = 5 1045 }; 1046 1047 template <typename context_t, typename ...Ts> dispatchAAT::ChainSubtable1048 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1049 { 1050 unsigned int subtable_type = get_type (); 1051 TRACE_DISPATCH (this, subtable_type); 1052 switch (subtable_type) { 1053 case Rearrangement: return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...)); 1054 case Contextual: return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...)); 1055 case Ligature: return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...)); 1056 case Noncontextual: return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...)); 1057 case Insertion: return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...)); 1058 default: return_trace (c->default_return_value ()); 1059 } 1060 } 1061 applyAAT::ChainSubtable1062 bool apply (hb_aat_apply_context_t *c) const 1063 { 1064 TRACE_APPLY (this); 1065 // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873 1066 //hb_sanitize_with_object_t with (&c->sanitizer, this); 1067 return_trace (dispatch (c)); 1068 } 1069 sanitizeAAT::ChainSubtable1070 bool sanitize (hb_sanitize_context_t *c) const 1071 { 1072 TRACE_SANITIZE (this); 1073 if (!(length.sanitize (c) && 1074 hb_barrier () && 1075 length >= min_size && 1076 c->check_range (this, length))) 1077 return_trace (false); 1078 1079 // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873 1080 //hb_sanitize_with_object_t with (c, this); 1081 return_trace (dispatch (c)); 1082 } 1083 1084 protected: 1085 HBUINT length; /* Total subtable length, including this header. */ 1086 HBUINT coverage; /* Coverage flags and subtable type. */ 1087 HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */ 1088 union { 1089 RearrangementSubtable<Types> rearrangement; 1090 ContextualSubtable<Types> contextual; 1091 LigatureSubtable<Types> ligature; 1092 NoncontextualSubtable<Types> noncontextual; 1093 InsertionSubtable<Types> insertion; 1094 } u; 1095 public: 1096 DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4); 1097 }; 1098 1099 template <typename Types> 1100 struct Chain 1101 { 1102 typedef typename Types::HBUINT HBUINT; 1103 get_subtable_countAAT::Chain1104 unsigned get_subtable_count () const { return subtableCount; } 1105 compile_flagsAAT::Chain1106 hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const 1107 { 1108 hb_mask_t flags = defaultFlags; 1109 { 1110 unsigned int count = featureCount; 1111 for (unsigned i = 0; i < count; i++) 1112 { 1113 const Feature &feature = featureZ[i]; 1114 hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType; 1115 hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting; 1116 retry: 1117 // Check whether this type/setting pair was requested in the map, and if so, apply its flags. 1118 // (The search here only looks at the type and setting fields of feature_info_t.) 1119 hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; 1120 if (map->current_features.bsearch (info)) 1121 { 1122 flags &= feature.disableFlags; 1123 flags |= feature.enableFlags; 1124 } 1125 else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS) 1126 { 1127 /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */ 1128 type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE; 1129 setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS; 1130 goto retry; 1131 } 1132 #ifndef HB_NO_AAT 1133 else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting && 1134 /* TODO: Rudimentary language matching. */ 1135 hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language)) 1136 { 1137 flags &= feature.disableFlags; 1138 flags |= feature.enableFlags; 1139 } 1140 #endif 1141 } 1142 } 1143 return flags; 1144 } 1145 applyAAT::Chain1146 void apply (hb_aat_apply_context_t *c, 1147 const hb_aat_layout_chain_accelerator_t *accel) const 1148 { 1149 const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1150 unsigned int count = subtableCount; 1151 for (unsigned int i = 0; i < count; i++) 1152 { 1153 bool reverse; 1154 1155 if (hb_none (hb_iter (c->range_flags) | 1156 hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) 1157 goto skip; 1158 c->subtable_flags = subtable->subFeatureFlags; 1159 c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full (); 1160 1161 if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) && 1162 HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != 1163 bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical)) 1164 goto skip; 1165 1166 /* Buffer contents is always in logical direction. Determine if 1167 * we need to reverse before applying this subtable. We reverse 1168 * back after if we did reverse indeed. 1169 * 1170 * Quoting the spac: 1171 * """ 1172 * Bits 28 and 30 of the coverage field control the order in which 1173 * glyphs are processed when the subtable is run by the layout engine. 1174 * Bit 28 is used to indicate if the glyph processing direction is 1175 * the same as logical order or layout order. Bit 30 is used to 1176 * indicate whether glyphs are processed forwards or backwards within 1177 * that order. 1178 1179 Bit 30 Bit 28 Interpretation for Horizontal Text 1180 0 0 The subtable is processed in layout order 1181 (the same order as the glyphs, which is 1182 always left-to-right). 1183 1 0 The subtable is processed in reverse layout order 1184 (the order opposite that of the glyphs, which is 1185 always right-to-left). 1186 0 1 The subtable is processed in logical order 1187 (the same order as the characters, which may be 1188 left-to-right or right-to-left). 1189 1 1 The subtable is processed in reverse logical order 1190 (the order opposite that of the characters, which 1191 may be right-to-left or left-to-right). 1192 */ 1193 reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ? 1194 bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) : 1195 bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) != 1196 HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); 1197 1198 if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) 1199 goto skip; 1200 1201 if (reverse) 1202 c->buffer->reverse (); 1203 1204 subtable->apply (c); 1205 1206 if (reverse) 1207 c->buffer->reverse (); 1208 1209 (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index); 1210 1211 if (unlikely (!c->buffer->successful)) return; 1212 1213 skip: 1214 subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1215 c->set_lookup_index (c->lookup_index + 1); 1216 } 1217 } 1218 get_sizeAAT::Chain1219 unsigned int get_size () const { return length; } 1220 1221 template <typename context_t, typename ...Ts> dispatchAAT::Chain1222 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1223 { 1224 const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1225 unsigned int count = subtableCount; 1226 for (unsigned int i = 0; i < count; i++) 1227 { 1228 typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...); 1229 if (c->stop_sublookup_iteration (ret)) 1230 return ret; 1231 subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1232 } 1233 return c->default_return_value (); 1234 } 1235 sanitizeAAT::Chain1236 bool sanitize (hb_sanitize_context_t *c, unsigned int version) const 1237 { 1238 TRACE_SANITIZE (this); 1239 if (!(length.sanitize (c) && 1240 hb_barrier () && 1241 length >= min_size && 1242 c->check_range (this, length))) 1243 return_trace (false); 1244 1245 if (!c->check_array (featureZ.arrayZ, featureCount)) 1246 return_trace (false); 1247 1248 const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1249 unsigned int count = subtableCount; 1250 for (unsigned int i = 0; i < count; i++) 1251 { 1252 if (!subtable->sanitize (c)) 1253 return_trace (false); 1254 hb_barrier (); 1255 subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1256 } 1257 1258 if (version >= 3) 1259 { 1260 const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable; 1261 if (!coverage->sanitize (c, count)) 1262 return_trace (false); 1263 } 1264 1265 return_trace (true); 1266 } 1267 1268 protected: 1269 HBUINT32 defaultFlags; /* The default specification for subtables. */ 1270 HBUINT32 length; /* Total byte count, including this header. */ 1271 HBUINT featureCount; /* Number of feature subtable entries. */ 1272 HBUINT subtableCount; /* The number of subtables in the chain. */ 1273 1274 UnsizedArrayOf<Feature> featureZ; /* Features. */ 1275 /*ChainSubtable firstSubtable;*//* Subtables. */ 1276 /*SubtableGlyphCoverage coverages*//* Only if version >= 3. */ 1277 1278 public: 1279 DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT)); 1280 }; 1281 1282 1283 /* 1284 * The 'mort'/'morx' Table 1285 */ 1286 1287 template <typename T, typename Types, hb_tag_t TAG> 1288 struct mortmorx 1289 { 1290 static constexpr hb_tag_t tableTag = TAG; 1291 has_dataAAT::mortmorx1292 bool has_data () const { return version != 0; } 1293 1294 struct accelerator_t 1295 { accelerator_tAAT::mortmorx::accelerator_t1296 accelerator_t (hb_face_t *face) 1297 { 1298 hb_sanitize_context_t sc; 1299 this->table = sc.reference_table<T> (face); 1300 1301 this->chain_count = table->get_chain_count (); 1302 1303 this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels)); 1304 if (unlikely (!this->accels)) 1305 { 1306 this->chain_count = 0; 1307 this->table.destroy (); 1308 this->table = hb_blob_get_empty (); 1309 } 1310 } ~accelerator_tAAT::mortmorx::accelerator_t1311 ~accelerator_t () 1312 { 1313 for (unsigned int i = 0; i < this->chain_count; i++) 1314 hb_free (this->accels[i]); 1315 hb_free (this->accels); 1316 this->table.destroy (); 1317 } 1318 get_blobAAT::mortmorx::accelerator_t1319 hb_blob_t *get_blob () const { return table.get_blob (); } 1320 1321 template <typename Chain> get_accelAAT::mortmorx::accelerator_t1322 hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const 1323 { 1324 if (unlikely (chain_index >= chain_count)) return nullptr; 1325 1326 retry: 1327 auto *accel = accels[chain_index].get_acquire (); 1328 if (unlikely (!accel)) 1329 { 1330 accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs); 1331 if (unlikely (!accel)) 1332 return nullptr; 1333 1334 if (unlikely (!accels[chain_index].cmpexch (nullptr, accel))) 1335 { 1336 hb_free (accel); 1337 goto retry; 1338 } 1339 } 1340 1341 return accel; 1342 } 1343 1344 hb_blob_ptr_t<T> table; 1345 unsigned int chain_count; 1346 hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels; 1347 }; 1348 1349 compile_flagsAAT::mortmorx1350 void compile_flags (const hb_aat_map_builder_t *mapper, 1351 hb_aat_map_t *map) const 1352 { 1353 const Chain<Types> *chain = &firstChain; 1354 unsigned int count = chainCount; 1355 if (unlikely (!map->chain_flags.resize (count))) 1356 return; 1357 for (unsigned int i = 0; i < count; i++) 1358 { 1359 map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper), 1360 mapper->range_first, 1361 mapper->range_last}); 1362 chain = &StructAfter<Chain<Types>> (*chain); 1363 } 1364 } 1365 get_chain_countAAT::mortmorx1366 unsigned get_chain_count () const 1367 { 1368 return chainCount; 1369 } 1370 applyAAT::mortmorx1371 void apply (hb_aat_apply_context_t *c, 1372 const hb_aat_map_t &map, 1373 const accelerator_t &accel) const 1374 { 1375 if (unlikely (!c->buffer->successful)) return; 1376 1377 c->buffer->unsafe_to_concat (); 1378 1379 if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD) 1380 c->buffer_digest = c->buffer->digest (); 1381 else 1382 c->buffer_digest = hb_set_digest_t::full (); 1383 1384 c->set_lookup_index (0); 1385 const Chain<Types> *chain = &firstChain; 1386 unsigned int count = chainCount; 1387 for (unsigned int i = 0; i < count; i++) 1388 { 1389 auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ()); 1390 c->range_flags = &map.chain_flags[i]; 1391 chain->apply (c, chain_accel); 1392 if (unlikely (!c->buffer->successful)) return; 1393 chain = &StructAfter<Chain<Types>> (*chain); 1394 } 1395 } 1396 sanitizeAAT::mortmorx1397 bool sanitize (hb_sanitize_context_t *c) const 1398 { 1399 TRACE_SANITIZE (this); 1400 if (!(version.sanitize (c) && 1401 hb_barrier () && 1402 version && 1403 chainCount.sanitize (c))) 1404 return_trace (false); 1405 1406 const Chain<Types> *chain = &firstChain; 1407 unsigned int count = chainCount; 1408 for (unsigned int i = 0; i < count; i++) 1409 { 1410 if (!chain->sanitize (c, version)) 1411 return_trace (false); 1412 hb_barrier (); 1413 chain = &StructAfter<Chain<Types>> (*chain); 1414 } 1415 1416 return_trace (true); 1417 } 1418 1419 protected: 1420 HBUINT16 version; /* Version number of the glyph metamorphosis table. 1421 * 1, 2, or 3. */ 1422 HBUINT16 unused; /* Set to 0. */ 1423 HBUINT32 chainCount; /* Number of metamorphosis chains contained in this 1424 * table. */ 1425 Chain<Types> firstChain; /* Chains. */ 1426 1427 public: 1428 DEFINE_SIZE_MIN (8); 1429 }; 1430 1431 struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {}; 1432 struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {}; 1433 1434 struct morx_accelerator_t : morx::accelerator_t { morx_accelerator_tAAT::morx_accelerator_t1435 morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {} 1436 }; 1437 struct mort_accelerator_t : mort::accelerator_t { mort_accelerator_tAAT::mort_accelerator_t1438 mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {} 1439 }; 1440 1441 1442 } /* namespace AAT */ 1443 1444 1445 #endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */ 1446