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-aat-map.hh" 34 35 /* 36 * morx -- Extended Glyph Metamorphosis 37 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html 38 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html 39 */ 40 #define HB_AAT_TAG_morx HB_TAG('m','o','r','x') 41 #define HB_AAT_TAG_mort HB_TAG('m','o','r','t') 42 43 44 namespace AAT { 45 46 using namespace OT; 47 48 template <typename Types> 49 struct RearrangementSubtable 50 { 51 typedef typename Types::HBUINT HBUINT; 52 53 typedef void EntryData; 54 55 struct driver_context_t 56 { 57 static constexpr bool in_place = true; 58 enum Flags 59 { 60 MarkFirst = 0x8000, /* If set, make the current glyph the first 61 * glyph to be rearranged. */ 62 DontAdvance = 0x4000, /* If set, don't advance to the next glyph 63 * before going to the new state. This means 64 * that the glyph index doesn't change, even 65 * if the glyph at that index has changed. */ 66 MarkLast = 0x2000, /* If set, make the current glyph the last 67 * glyph to be rearranged. */ 68 Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */ 69 Verb = 0x000F, /* The type of rearrangement specified. */ 70 }; 71 driver_context_tAAT::RearrangementSubtable::driver_context_t72 driver_context_t (const RearrangementSubtable *table HB_UNUSED) : 73 ret (false), 74 start (0), end (0) {} 75 is_actionableAAT::RearrangementSubtable::driver_context_t76 bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, 77 const Entry<EntryData> &entry) 78 { 79 return (entry.flags & Verb) && start < end; 80 } transitionAAT::RearrangementSubtable::driver_context_t81 void transition (StateTableDriver<Types, EntryData> *driver, 82 const Entry<EntryData> &entry) 83 { 84 hb_buffer_t *buffer = driver->buffer; 85 unsigned int flags = entry.flags; 86 87 if (flags & MarkFirst) 88 start = buffer->idx; 89 90 if (flags & MarkLast) 91 end = hb_min (buffer->idx + 1, buffer->len); 92 93 if ((flags & Verb) && start < end) 94 { 95 /* The following map has two nibbles, for start-side 96 * and end-side. Values of 0,1,2 mean move that many 97 * to the other side. Value of 3 means move 2 and 98 * flip them. */ 99 const unsigned char map[16] = 100 { 101 0x00, /* 0 no change */ 102 0x10, /* 1 Ax => xA */ 103 0x01, /* 2 xD => Dx */ 104 0x11, /* 3 AxD => DxA */ 105 0x20, /* 4 ABx => xAB */ 106 0x30, /* 5 ABx => xBA */ 107 0x02, /* 6 xCD => CDx */ 108 0x03, /* 7 xCD => DCx */ 109 0x12, /* 8 AxCD => CDxA */ 110 0x13, /* 9 AxCD => DCxA */ 111 0x21, /* 10 ABxD => DxAB */ 112 0x31, /* 11 ABxD => DxBA */ 113 0x22, /* 12 ABxCD => CDxAB */ 114 0x32, /* 13 ABxCD => CDxBA */ 115 0x23, /* 14 ABxCD => DCxAB */ 116 0x33, /* 15 ABxCD => DCxBA */ 117 }; 118 119 unsigned int m = map[flags & Verb]; 120 unsigned int l = hb_min (2u, m >> 4); 121 unsigned int r = hb_min (2u, m & 0x0F); 122 bool reverse_l = 3 == (m >> 4); 123 bool reverse_r = 3 == (m & 0x0F); 124 125 if (end - start >= l + r) 126 { 127 buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len)); 128 buffer->merge_clusters (start, end); 129 130 hb_glyph_info_t *info = buffer->info; 131 hb_glyph_info_t buf[4]; 132 133 memcpy (buf, info + start, l * sizeof (buf[0])); 134 memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); 135 136 if (l != r) 137 memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0])); 138 139 memcpy (info + start, buf + 2, r * sizeof (buf[0])); 140 memcpy (info + end - l, buf, l * sizeof (buf[0])); 141 if (reverse_l) 142 { 143 buf[0] = info[end - 1]; 144 info[end - 1] = info[end - 2]; 145 info[end - 2] = buf[0]; 146 } 147 if (reverse_r) 148 { 149 buf[0] = info[start]; 150 info[start] = info[start + 1]; 151 info[start + 1] = buf[0]; 152 } 153 } 154 } 155 } 156 157 public: 158 bool ret; 159 private: 160 unsigned int start; 161 unsigned int end; 162 }; 163 applyAAT::RearrangementSubtable164 bool apply (hb_aat_apply_context_t *c) const 165 { 166 TRACE_APPLY (this); 167 168 driver_context_t dc (this); 169 170 StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); 171 driver.drive (&dc); 172 173 return_trace (dc.ret); 174 } 175 sanitizeAAT::RearrangementSubtable176 bool sanitize (hb_sanitize_context_t *c) const 177 { 178 TRACE_SANITIZE (this); 179 return_trace (machine.sanitize (c)); 180 } 181 182 protected: 183 StateTable<Types, EntryData> machine; 184 public: 185 DEFINE_SIZE_STATIC (16); 186 }; 187 188 template <typename Types> 189 struct ContextualSubtable 190 { 191 typedef typename Types::HBUINT HBUINT; 192 193 struct EntryData 194 { 195 HBUINT16 markIndex; /* Index of the substitution table for the 196 * marked glyph (use 0xFFFF for none). */ 197 HBUINT16 currentIndex; /* Index of the substitution table for the 198 * current glyph (use 0xFFFF for none). */ 199 public: 200 DEFINE_SIZE_STATIC (4); 201 }; 202 203 struct driver_context_t 204 { 205 static constexpr bool in_place = true; 206 enum Flags 207 { 208 SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ 209 DontAdvance = 0x4000, /* If set, don't advance to the next glyph before 210 * going to the new state. */ 211 Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */ 212 }; 213 driver_context_tAAT::ContextualSubtable::driver_context_t214 driver_context_t (const ContextualSubtable *table_, 215 hb_aat_apply_context_t *c_) : 216 ret (false), 217 c (c_), 218 mark_set (false), 219 mark (0), 220 table (table_), 221 subs (table+table->substitutionTables) {} 222 is_actionableAAT::ContextualSubtable::driver_context_t223 bool is_actionable (StateTableDriver<Types, EntryData> *driver, 224 const Entry<EntryData> &entry) 225 { 226 hb_buffer_t *buffer = driver->buffer; 227 228 if (buffer->idx == buffer->len && !mark_set) 229 return false; 230 231 return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; 232 } transitionAAT::ContextualSubtable::driver_context_t233 void transition (StateTableDriver<Types, EntryData> *driver, 234 const Entry<EntryData> &entry) 235 { 236 hb_buffer_t *buffer = driver->buffer; 237 238 /* Looks like CoreText applies neither mark nor current substitution for 239 * end-of-text if mark was not explicitly set. */ 240 if (buffer->idx == buffer->len && !mark_set) 241 return; 242 243 const HBGlyphID *replacement; 244 245 replacement = nullptr; 246 if (Types::extended) 247 { 248 if (entry.data.markIndex != 0xFFFF) 249 { 250 const Lookup<HBGlyphID> &lookup = subs[entry.data.markIndex]; 251 replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs); 252 } 253 } 254 else 255 { 256 unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; 257 const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs; 258 replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; 259 if (!replacement->sanitize (&c->sanitizer) || !*replacement) 260 replacement = nullptr; 261 } 262 if (replacement) 263 { 264 buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); 265 buffer->info[mark].codepoint = *replacement; 266 ret = true; 267 } 268 269 replacement = nullptr; 270 unsigned int idx = hb_min (buffer->idx, buffer->len - 1); 271 if (Types::extended) 272 { 273 if (entry.data.currentIndex != 0xFFFF) 274 { 275 const Lookup<HBGlyphID> &lookup = subs[entry.data.currentIndex]; 276 replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs); 277 } 278 } 279 else 280 { 281 unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; 282 const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs; 283 replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; 284 if (!replacement->sanitize (&c->sanitizer) || !*replacement) 285 replacement = nullptr; 286 } 287 if (replacement) 288 { 289 buffer->info[idx].codepoint = *replacement; 290 ret = true; 291 } 292 293 if (entry.flags & SetMark) 294 { 295 mark_set = true; 296 mark = buffer->idx; 297 } 298 } 299 300 public: 301 bool ret; 302 private: 303 hb_aat_apply_context_t *c; 304 bool mark_set; 305 unsigned int mark; 306 const ContextualSubtable *table; 307 const UnsizedListOfOffset16To<Lookup<HBGlyphID>, HBUINT, false> &subs; 308 }; 309 applyAAT::ContextualSubtable310 bool apply (hb_aat_apply_context_t *c) const 311 { 312 TRACE_APPLY (this); 313 314 driver_context_t dc (this, c); 315 316 StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); 317 driver.drive (&dc); 318 319 return_trace (dc.ret); 320 } 321 sanitizeAAT::ContextualSubtable322 bool sanitize (hb_sanitize_context_t *c) const 323 { 324 TRACE_SANITIZE (this); 325 326 unsigned int num_entries = 0; 327 if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false); 328 329 if (!Types::extended) 330 return_trace (substitutionTables.sanitize (c, this, 0)); 331 332 unsigned int num_lookups = 0; 333 334 const Entry<EntryData> *entries = machine.get_entries (); 335 for (unsigned int i = 0; i < num_entries; i++) 336 { 337 const EntryData &data = entries[i].data; 338 339 if (data.markIndex != 0xFFFF) 340 num_lookups = hb_max (num_lookups, 1u + data.markIndex); 341 if (data.currentIndex != 0xFFFF) 342 num_lookups = hb_max (num_lookups, 1u + data.currentIndex); 343 } 344 345 return_trace (substitutionTables.sanitize (c, this, num_lookups)); 346 } 347 348 protected: 349 StateTable<Types, EntryData> 350 machine; 351 NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID>, HBUINT, false>, HBUINT> 352 substitutionTables; 353 public: 354 DEFINE_SIZE_STATIC (20); 355 }; 356 357 358 template <bool extended> 359 struct LigatureEntry; 360 361 template <> 362 struct LigatureEntry<true> 363 { 364 enum Flags 365 { 366 SetComponent = 0x8000, /* Push this glyph onto the component stack for 367 * eventual processing. */ 368 DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the 369 next iteration. */ 370 PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature 371 * group. */ 372 Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ 373 }; 374 375 struct EntryData 376 { 377 HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry 378 * for processing this group, if indicated 379 * by the flags. */ 380 public: 381 DEFINE_SIZE_STATIC (2); 382 }; 383 performActionAAT::LigatureEntry384 static bool performAction (const Entry<EntryData> &entry) 385 { return entry.flags & PerformAction; } 386 ligActionIndexAAT::LigatureEntry387 static unsigned int ligActionIndex (const Entry<EntryData> &entry) 388 { return entry.data.ligActionIndex; } 389 }; 390 template <> 391 struct LigatureEntry<false> 392 { 393 enum Flags 394 { 395 SetComponent = 0x8000, /* Push this glyph onto the component stack for 396 * eventual processing. */ 397 DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the 398 next iteration. */ 399 Offset = 0x3FFF, /* Byte offset from beginning of subtable to the 400 * ligature action list. This value must be a 401 * multiple of 4. */ 402 }; 403 404 typedef void EntryData; 405 performActionAAT::LigatureEntry406 static bool performAction (const Entry<EntryData> &entry) 407 { return entry.flags & Offset; } 408 ligActionIndexAAT::LigatureEntry409 static unsigned int ligActionIndex (const Entry<EntryData> &entry) 410 { return entry.flags & Offset; } 411 }; 412 413 414 template <typename Types> 415 struct LigatureSubtable 416 { 417 typedef typename Types::HBUINT HBUINT; 418 419 typedef LigatureEntry<Types::extended> LigatureEntryT; 420 typedef typename LigatureEntryT::EntryData EntryData; 421 422 struct driver_context_t 423 { 424 static constexpr bool in_place = false; 425 enum 426 { 427 DontAdvance = LigatureEntryT::DontAdvance, 428 }; 429 enum LigActionFlags 430 { 431 LigActionLast = 0x80000000, /* This is the last action in the list. This also 432 * implies storage. */ 433 LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index 434 * in the ligature table in place of the marked 435 * (i.e. currently-popped) glyph. */ 436 LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits 437 * and added to the glyph ID, resulting in an index 438 * into the component table. */ 439 }; 440 driver_context_tAAT::LigatureSubtable::driver_context_t441 driver_context_t (const LigatureSubtable *table_, 442 hb_aat_apply_context_t *c_) : 443 ret (false), 444 c (c_), 445 table (table_), 446 ligAction (table+table->ligAction), 447 component (table+table->component), 448 ligature (table+table->ligature), 449 match_length (0) {} 450 is_actionableAAT::LigatureSubtable::driver_context_t451 bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, 452 const Entry<EntryData> &entry) 453 { 454 return LigatureEntryT::performAction (entry); 455 } transitionAAT::LigatureSubtable::driver_context_t456 void transition (StateTableDriver<Types, EntryData> *driver, 457 const Entry<EntryData> &entry) 458 { 459 hb_buffer_t *buffer = driver->buffer; 460 461 DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); 462 if (entry.flags & LigatureEntryT::SetComponent) 463 { 464 /* Never mark same index twice, in case DontAdvance was used... */ 465 if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len) 466 match_length--; 467 468 match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len; 469 DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len); 470 } 471 472 if (LigatureEntryT::performAction (entry)) 473 { 474 DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length); 475 unsigned int end = buffer->out_len; 476 477 if (unlikely (!match_length)) 478 return; 479 480 if (buffer->idx >= buffer->len) 481 return; /* TODO Work on previous instead? */ 482 483 unsigned int cursor = match_length; 484 485 unsigned int action_idx = LigatureEntryT::ligActionIndex (entry); 486 action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ); 487 const HBUINT32 *actionData = &ligAction[action_idx]; 488 489 unsigned int ligature_idx = 0; 490 unsigned int action; 491 do 492 { 493 if (unlikely (!cursor)) 494 { 495 /* Stack underflow. Clear the stack. */ 496 DEBUG_MSG (APPLY, nullptr, "Stack underflow"); 497 match_length = 0; 498 break; 499 } 500 501 DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1); 502 if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return; 503 504 if (unlikely (!actionData->sanitize (&c->sanitizer))) break; 505 action = *actionData; 506 507 uint32_t uoffset = action & LigActionOffset; 508 if (uoffset & 0x20000000) 509 uoffset |= 0xC0000000; /* Sign-extend. */ 510 int32_t offset = (int32_t) uoffset; 511 unsigned int component_idx = buffer->cur().codepoint + offset; 512 component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ); 513 const HBUINT16 &componentData = component[component_idx]; 514 if (unlikely (!componentData.sanitize (&c->sanitizer))) break; 515 ligature_idx += componentData; 516 517 DEBUG_MSG (APPLY, nullptr, "Action store %u last %u", 518 bool (action & LigActionStore), 519 bool (action & LigActionLast)); 520 if (action & (LigActionStore | LigActionLast)) 521 { 522 ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); 523 const HBGlyphID &ligatureData = ligature[ligature_idx]; 524 if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; 525 hb_codepoint_t lig = ligatureData; 526 527 DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); 528 if (unlikely (!buffer->replace_glyph (lig))) return; 529 530 unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u; 531 /* Now go and delete all subsequent components. */ 532 while (match_length - 1u > cursor) 533 { 534 DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); 535 if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; 536 if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; 537 } 538 539 if (unlikely (!buffer->move_to (lig_end))) return; 540 buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len); 541 } 542 543 actionData++; 544 } 545 while (!(action & LigActionLast)); 546 if (unlikely (!buffer->move_to (end))) return; 547 } 548 } 549 550 public: 551 bool ret; 552 private: 553 hb_aat_apply_context_t *c; 554 const LigatureSubtable *table; 555 const UnsizedArrayOf<HBUINT32> &ligAction; 556 const UnsizedArrayOf<HBUINT16> &component; 557 const UnsizedArrayOf<HBGlyphID> &ligature; 558 unsigned int match_length; 559 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 560 }; 561 applyAAT::LigatureSubtable562 bool apply (hb_aat_apply_context_t *c) const 563 { 564 TRACE_APPLY (this); 565 566 driver_context_t dc (this, c); 567 568 StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); 569 driver.drive (&dc); 570 571 return_trace (dc.ret); 572 } 573 sanitizeAAT::LigatureSubtable574 bool sanitize (hb_sanitize_context_t *c) const 575 { 576 TRACE_SANITIZE (this); 577 /* The rest of array sanitizations are done at run-time. */ 578 return_trace (c->check_struct (this) && machine.sanitize (c) && 579 ligAction && component && ligature); 580 } 581 582 protected: 583 StateTable<Types, EntryData> 584 machine; 585 NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT> 586 ligAction; /* Offset to the ligature action table. */ 587 NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT> 588 component; /* Offset to the component table. */ 589 NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT> 590 ligature; /* Offset to the actual ligature lists. */ 591 public: 592 DEFINE_SIZE_STATIC (28); 593 }; 594 595 template <typename Types> 596 struct NoncontextualSubtable 597 { applyAAT::NoncontextualSubtable598 bool apply (hb_aat_apply_context_t *c) const 599 { 600 TRACE_APPLY (this); 601 602 bool ret = false; 603 unsigned int num_glyphs = c->face->get_num_glyphs (); 604 605 hb_glyph_info_t *info = c->buffer->info; 606 unsigned int count = c->buffer->len; 607 for (unsigned int i = 0; i < count; i++) 608 { 609 const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs); 610 if (replacement) 611 { 612 info[i].codepoint = *replacement; 613 ret = true; 614 } 615 } 616 617 return_trace (ret); 618 } 619 sanitizeAAT::NoncontextualSubtable620 bool sanitize (hb_sanitize_context_t *c) const 621 { 622 TRACE_SANITIZE (this); 623 return_trace (substitute.sanitize (c)); 624 } 625 626 protected: 627 Lookup<HBGlyphID> substitute; 628 public: 629 DEFINE_SIZE_MIN (2); 630 }; 631 632 template <typename Types> 633 struct InsertionSubtable 634 { 635 typedef typename Types::HBUINT HBUINT; 636 637 struct EntryData 638 { 639 HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table. 640 * The number of glyphs to be inserted is contained 641 * in the currentInsertCount field in the flags. 642 * A value of 0xFFFF indicates no insertion is to 643 * be done. */ 644 HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table. 645 * The number of glyphs to be inserted is contained 646 * in the markedInsertCount field in the flags. 647 * A value of 0xFFFF indicates no insertion is to 648 * be done. */ 649 public: 650 DEFINE_SIZE_STATIC (4); 651 }; 652 653 struct driver_context_t 654 { 655 static constexpr bool in_place = false; 656 enum Flags 657 { 658 SetMark = 0x8000, /* If set, mark the current glyph. */ 659 DontAdvance = 0x4000, /* If set, don't advance to the next glyph before 660 * going to the new state. This does not mean 661 * that the glyph pointed to is the same one as 662 * before. If you've made insertions immediately 663 * downstream of the current glyph, the next glyph 664 * processed would in fact be the first one 665 * inserted. */ 666 CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, 667 * then the specified glyph list will be inserted 668 * as a kashida-like insertion, either before or 669 * after the current glyph (depending on the state 670 * of the currentInsertBefore flag). If clear, and 671 * the currentInsertList is nonzero, then the 672 * specified glyph list will be inserted as a 673 * split-vowel-like insertion, either before or 674 * after the current glyph (depending on the state 675 * of the currentInsertBefore flag). */ 676 MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, 677 * then the specified glyph list will be inserted 678 * as a kashida-like insertion, either before or 679 * after the marked glyph (depending on the state 680 * of the markedInsertBefore flag). If clear, and 681 * the markedInsertList is nonzero, then the 682 * specified glyph list will be inserted as a 683 * split-vowel-like insertion, either before or 684 * after the marked glyph (depending on the state 685 * of the markedInsertBefore flag). */ 686 CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made 687 * to the left of the current glyph. If clear, 688 * they're made to the right of the current glyph. */ 689 MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be 690 * made to the left of the marked glyph. If clear, 691 * they're made to the right of the marked glyph. */ 692 CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the 693 * number of glyphs to insert at the current 694 * position. Since zero means no insertions, the 695 * largest number of insertions at any given 696 * current location is 31 glyphs. */ 697 MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the 698 * number of glyphs to insert at the marked 699 * position. Since zero means no insertions, the 700 * largest number of insertions at any given 701 * marked location is 31 glyphs. */ 702 }; 703 driver_context_tAAT::InsertionSubtable::driver_context_t704 driver_context_t (const InsertionSubtable *table, 705 hb_aat_apply_context_t *c_) : 706 ret (false), 707 c (c_), 708 mark (0), 709 insertionAction (table+table->insertionAction) {} 710 is_actionableAAT::InsertionSubtable::driver_context_t711 bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED, 712 const Entry<EntryData> &entry) 713 { 714 return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && 715 (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); 716 } transitionAAT::InsertionSubtable::driver_context_t717 void transition (StateTableDriver<Types, EntryData> *driver, 718 const Entry<EntryData> &entry) 719 { 720 hb_buffer_t *buffer = driver->buffer; 721 unsigned int flags = entry.flags; 722 723 unsigned mark_loc = buffer->out_len; 724 725 if (entry.data.markedInsertIndex != 0xFFFF) 726 { 727 unsigned int count = (flags & MarkedInsertCount); 728 if (unlikely ((buffer->max_ops -= count) <= 0)) return; 729 unsigned int start = entry.data.markedInsertIndex; 730 const HBGlyphID *glyphs = &insertionAction[start]; 731 if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; 732 733 bool before = flags & MarkedInsertBefore; 734 735 unsigned int end = buffer->out_len; 736 if (unlikely (!buffer->move_to (mark))) return; 737 738 if (buffer->idx < buffer->len && !before) 739 if (unlikely (!buffer->copy_glyph ())) return; 740 /* TODO We ignore KashidaLike setting. */ 741 if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 742 if (buffer->idx < buffer->len && !before) 743 buffer->skip_glyph (); 744 745 if (unlikely (!buffer->move_to (end + count))) return; 746 747 buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len)); 748 } 749 750 if (flags & SetMark) 751 mark = mark_loc; 752 753 if (entry.data.currentInsertIndex != 0xFFFF) 754 { 755 unsigned int count = (flags & CurrentInsertCount) >> 5; 756 if (unlikely ((buffer->max_ops -= count) <= 0)) return; 757 unsigned int start = entry.data.currentInsertIndex; 758 const HBGlyphID *glyphs = &insertionAction[start]; 759 if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; 760 761 bool before = flags & CurrentInsertBefore; 762 763 unsigned int end = buffer->out_len; 764 765 if (buffer->idx < buffer->len && !before) 766 if (unlikely (!buffer->copy_glyph ())) return; 767 /* TODO We ignore KashidaLike setting. */ 768 if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 769 if (buffer->idx < buffer->len && !before) 770 buffer->skip_glyph (); 771 772 /* Humm. Not sure where to move to. There's this wording under 773 * DontAdvance flag: 774 * 775 * "If set, don't update the glyph index before going to the new state. 776 * This does not mean that the glyph pointed to is the same one as 777 * before. If you've made insertions immediately downstream of the 778 * current glyph, the next glyph processed would in fact be the first 779 * one inserted." 780 * 781 * This suggests that if DontAdvance is NOT set, we should move to 782 * end+count. If it *was*, then move to end, such that newly inserted 783 * glyphs are now visible. 784 * 785 * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417 786 */ 787 if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return; 788 } 789 } 790 791 public: 792 bool ret; 793 private: 794 hb_aat_apply_context_t *c; 795 unsigned int mark; 796 const UnsizedArrayOf<HBGlyphID> &insertionAction; 797 }; 798 applyAAT::InsertionSubtable799 bool apply (hb_aat_apply_context_t *c) const 800 { 801 TRACE_APPLY (this); 802 803 driver_context_t dc (this, c); 804 805 StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face); 806 driver.drive (&dc); 807 808 return_trace (dc.ret); 809 } 810 sanitizeAAT::InsertionSubtable811 bool sanitize (hb_sanitize_context_t *c) const 812 { 813 TRACE_SANITIZE (this); 814 /* The rest of array sanitizations are done at run-time. */ 815 return_trace (c->check_struct (this) && machine.sanitize (c) && 816 insertionAction); 817 } 818 819 protected: 820 StateTable<Types, EntryData> 821 machine; 822 NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT> 823 insertionAction; /* Byte offset from stateHeader to the start of 824 * the insertion glyph table. */ 825 public: 826 DEFINE_SIZE_STATIC (20); 827 }; 828 829 830 struct Feature 831 { sanitizeAAT::Feature832 bool sanitize (hb_sanitize_context_t *c) const 833 { 834 TRACE_SANITIZE (this); 835 return_trace (c->check_struct (this)); 836 } 837 838 public: 839 HBUINT16 featureType; /* The type of feature. */ 840 HBUINT16 featureSetting; /* The feature's setting (aka selector). */ 841 HBUINT32 enableFlags; /* Flags for the settings that this feature 842 * and setting enables. */ 843 HBUINT32 disableFlags; /* Complement of flags for the settings that this 844 * feature and setting disable. */ 845 846 public: 847 DEFINE_SIZE_STATIC (12); 848 }; 849 850 template <typename Types> 851 struct ChainSubtable 852 { 853 typedef typename Types::HBUINT HBUINT; 854 855 template <typename T> 856 friend struct Chain; 857 get_sizeAAT::ChainSubtable858 unsigned int get_size () const { return length; } get_typeAAT::ChainSubtable859 unsigned int get_type () const { return coverage & 0xFF; } get_coverageAAT::ChainSubtable860 unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); } 861 862 enum Coverage 863 { 864 Vertical = 0x80, /* If set, this subtable will only be applied 865 * to vertical text. If clear, this subtable 866 * will only be applied to horizontal text. */ 867 Backwards = 0x40, /* If set, this subtable will process glyphs 868 * in descending order. If clear, it will 869 * process the glyphs in ascending order. */ 870 AllDirections = 0x20, /* If set, this subtable will be applied to 871 * both horizontal and vertical text (i.e. 872 * the state of bit 0x80000000 is ignored). */ 873 Logical = 0x10, /* If set, this subtable will process glyphs 874 * in logical order (or reverse logical order, 875 * depending on the value of bit 0x80000000). */ 876 }; 877 enum Type 878 { 879 Rearrangement = 0, 880 Contextual = 1, 881 Ligature = 2, 882 Noncontextual = 4, 883 Insertion = 5 884 }; 885 886 template <typename context_t, typename ...Ts> dispatchAAT::ChainSubtable887 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 888 { 889 unsigned int subtable_type = get_type (); 890 TRACE_DISPATCH (this, subtable_type); 891 switch (subtable_type) { 892 case Rearrangement: return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...)); 893 case Contextual: return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...)); 894 case Ligature: return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...)); 895 case Noncontextual: return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...)); 896 case Insertion: return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...)); 897 default: return_trace (c->default_return_value ()); 898 } 899 } 900 applyAAT::ChainSubtable901 bool apply (hb_aat_apply_context_t *c) const 902 { 903 TRACE_APPLY (this); 904 hb_sanitize_with_object_t with (&c->sanitizer, this); 905 return_trace (dispatch (c)); 906 } 907 sanitizeAAT::ChainSubtable908 bool sanitize (hb_sanitize_context_t *c) const 909 { 910 TRACE_SANITIZE (this); 911 if (!length.sanitize (c) || 912 length <= min_size || 913 !c->check_range (this, length)) 914 return_trace (false); 915 916 hb_sanitize_with_object_t with (c, this); 917 return_trace (dispatch (c)); 918 } 919 920 protected: 921 HBUINT length; /* Total subtable length, including this header. */ 922 HBUINT coverage; /* Coverage flags and subtable type. */ 923 HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */ 924 union { 925 RearrangementSubtable<Types> rearrangement; 926 ContextualSubtable<Types> contextual; 927 LigatureSubtable<Types> ligature; 928 NoncontextualSubtable<Types> noncontextual; 929 InsertionSubtable<Types> insertion; 930 } u; 931 public: 932 DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4); 933 }; 934 935 template <typename Types> 936 struct Chain 937 { 938 typedef typename Types::HBUINT HBUINT; 939 compile_flagsAAT::Chain940 hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const 941 { 942 hb_mask_t flags = defaultFlags; 943 { 944 unsigned int count = featureCount; 945 for (unsigned i = 0; i < count; i++) 946 { 947 const Feature &feature = featureZ[i]; 948 hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType; 949 hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting; 950 retry: 951 // Check whether this type/setting pair was requested in the map, and if so, apply its flags. 952 // (The search here only looks at the type and setting fields of feature_info_t.) 953 hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; 954 if (map->features.bsearch (info)) 955 { 956 flags &= feature.disableFlags; 957 flags |= feature.enableFlags; 958 } 959 else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS) 960 { 961 /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */ 962 type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE; 963 setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS; 964 goto retry; 965 } 966 } 967 } 968 return flags; 969 } 970 applyAAT::Chain971 void apply (hb_aat_apply_context_t *c, 972 hb_mask_t flags) const 973 { 974 const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 975 unsigned int count = subtableCount; 976 for (unsigned int i = 0; i < count; i++) 977 { 978 bool reverse; 979 980 if (!(subtable->subFeatureFlags & flags)) 981 goto skip; 982 983 if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) && 984 HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != 985 bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical)) 986 goto skip; 987 988 /* Buffer contents is always in logical direction. Determine if 989 * we need to reverse before applying this subtable. We reverse 990 * back after if we did reverse indeed. 991 * 992 * Quoting the spac: 993 * """ 994 * Bits 28 and 30 of the coverage field control the order in which 995 * glyphs are processed when the subtable is run by the layout engine. 996 * Bit 28 is used to indicate if the glyph processing direction is 997 * the same as logical order or layout order. Bit 30 is used to 998 * indicate whether glyphs are processed forwards or backwards within 999 * that order. 1000 1001 Bit 30 Bit 28 Interpretation for Horizontal Text 1002 0 0 The subtable is processed in layout order 1003 (the same order as the glyphs, which is 1004 always left-to-right). 1005 1 0 The subtable is processed in reverse layout order 1006 (the order opposite that of the glyphs, which is 1007 always right-to-left). 1008 0 1 The subtable is processed in logical order 1009 (the same order as the characters, which may be 1010 left-to-right or right-to-left). 1011 1 1 The subtable is processed in reverse logical order 1012 (the order opposite that of the characters, which 1013 may be right-to-left or left-to-right). 1014 */ 1015 reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ? 1016 bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) : 1017 bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) != 1018 HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); 1019 1020 if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index)) 1021 goto skip; 1022 1023 if (reverse) 1024 c->buffer->reverse (); 1025 1026 subtable->apply (c); 1027 1028 if (reverse) 1029 c->buffer->reverse (); 1030 1031 (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); 1032 1033 if (unlikely (!c->buffer->successful)) return; 1034 1035 skip: 1036 subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1037 c->set_lookup_index (c->lookup_index + 1); 1038 } 1039 } 1040 get_sizeAAT::Chain1041 unsigned int get_size () const { return length; } 1042 sanitizeAAT::Chain1043 bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const 1044 { 1045 TRACE_SANITIZE (this); 1046 if (!length.sanitize (c) || 1047 length < min_size || 1048 !c->check_range (this, length)) 1049 return_trace (false); 1050 1051 if (!c->check_array (featureZ.arrayZ, featureCount)) 1052 return_trace (false); 1053 1054 const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1055 unsigned int count = subtableCount; 1056 for (unsigned int i = 0; i < count; i++) 1057 { 1058 if (!subtable->sanitize (c)) 1059 return_trace (false); 1060 subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1061 } 1062 1063 return_trace (true); 1064 } 1065 1066 protected: 1067 HBUINT32 defaultFlags; /* The default specification for subtables. */ 1068 HBUINT32 length; /* Total byte count, including this header. */ 1069 HBUINT featureCount; /* Number of feature subtable entries. */ 1070 HBUINT subtableCount; /* The number of subtables in the chain. */ 1071 1072 UnsizedArrayOf<Feature> featureZ; /* Features. */ 1073 /*ChainSubtable firstSubtable;*//* Subtables. */ 1074 /*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */ 1075 1076 public: 1077 DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT)); 1078 }; 1079 1080 1081 /* 1082 * The 'mort'/'morx' Table 1083 */ 1084 1085 template <typename Types, hb_tag_t TAG> 1086 struct mortmorx 1087 { 1088 static constexpr hb_tag_t tableTag = TAG; 1089 has_dataAAT::mortmorx1090 bool has_data () const { return version != 0; } 1091 compile_flagsAAT::mortmorx1092 void compile_flags (const hb_aat_map_builder_t *mapper, 1093 hb_aat_map_t *map) const 1094 { 1095 const Chain<Types> *chain = &firstChain; 1096 unsigned int count = chainCount; 1097 for (unsigned int i = 0; i < count; i++) 1098 { 1099 map->chain_flags.push (chain->compile_flags (mapper)); 1100 chain = &StructAfter<Chain<Types>> (*chain); 1101 } 1102 } 1103 applyAAT::mortmorx1104 void apply (hb_aat_apply_context_t *c) const 1105 { 1106 if (unlikely (!c->buffer->successful)) return; 1107 c->set_lookup_index (0); 1108 const Chain<Types> *chain = &firstChain; 1109 unsigned int count = chainCount; 1110 for (unsigned int i = 0; i < count; i++) 1111 { 1112 chain->apply (c, c->plan->aat_map.chain_flags[i]); 1113 if (unlikely (!c->buffer->successful)) return; 1114 chain = &StructAfter<Chain<Types>> (*chain); 1115 } 1116 } 1117 sanitizeAAT::mortmorx1118 bool sanitize (hb_sanitize_context_t *c) const 1119 { 1120 TRACE_SANITIZE (this); 1121 if (!version.sanitize (c) || !version || !chainCount.sanitize (c)) 1122 return_trace (false); 1123 1124 const Chain<Types> *chain = &firstChain; 1125 unsigned int count = chainCount; 1126 for (unsigned int i = 0; i < count; i++) 1127 { 1128 if (!chain->sanitize (c, version)) 1129 return_trace (false); 1130 chain = &StructAfter<Chain<Types>> (*chain); 1131 } 1132 1133 return_trace (true); 1134 } 1135 1136 protected: 1137 HBUINT16 version; /* Version number of the glyph metamorphosis table. 1138 * 1, 2, or 3. */ 1139 HBUINT16 unused; /* Set to 0. */ 1140 HBUINT32 chainCount; /* Number of metamorphosis chains contained in this 1141 * table. */ 1142 Chain<Types> firstChain; /* Chains. */ 1143 1144 public: 1145 DEFINE_SIZE_MIN (8); 1146 }; 1147 1148 struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {}; 1149 struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {}; 1150 1151 1152 } /* namespace AAT */ 1153 1154 1155 #endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */ 1156