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