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_COMMON_HH 28 #define HB_AAT_LAYOUT_COMMON_HH 29 30 #include "hb-aat-layout.hh" 31 #include "hb-open-type.hh" 32 33 34 namespace AAT { 35 36 using namespace OT; 37 38 39 /* 40 * Lookup Table 41 */ 42 43 template <typename T> struct Lookup; 44 45 template <typename T> 46 struct LookupFormat0 47 { 48 friend struct Lookup<T>; 49 50 private: get_valueAAT::LookupFormat051 const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 52 { 53 if (unlikely (glyph_id >= num_glyphs)) return nullptr; 54 return &arrayZ[glyph_id]; 55 } 56 sanitizeAAT::LookupFormat057 bool sanitize (hb_sanitize_context_t *c) const 58 { 59 TRACE_SANITIZE (this); 60 return_trace (arrayZ.sanitize (c, c->get_num_glyphs ())); 61 } sanitizeAAT::LookupFormat062 bool sanitize (hb_sanitize_context_t *c, const void *base) const 63 { 64 TRACE_SANITIZE (this); 65 return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base)); 66 } 67 68 protected: 69 HBUINT16 format; /* Format identifier--format = 0 */ 70 UnsizedArrayOf<T> 71 arrayZ; /* Array of lookup values, indexed by glyph index. */ 72 public: 73 DEFINE_SIZE_UNBOUNDED (2); 74 }; 75 76 77 template <typename T> 78 struct LookupSegmentSingle 79 { 80 static constexpr unsigned TerminationWordCount = 2u; 81 cmpAAT::LookupSegmentSingle82 int cmp (hb_codepoint_t g) const 83 { return g < first ? -1 : g <= last ? 0 : +1 ; } 84 sanitizeAAT::LookupSegmentSingle85 bool sanitize (hb_sanitize_context_t *c) const 86 { 87 TRACE_SANITIZE (this); 88 return_trace (c->check_struct (this) && value.sanitize (c)); 89 } sanitizeAAT::LookupSegmentSingle90 bool sanitize (hb_sanitize_context_t *c, const void *base) const 91 { 92 TRACE_SANITIZE (this); 93 return_trace (c->check_struct (this) && value.sanitize (c, base)); 94 } 95 96 HBGlyphID last; /* Last GlyphID in this segment */ 97 HBGlyphID first; /* First GlyphID in this segment */ 98 T value; /* The lookup value (only one) */ 99 public: 100 DEFINE_SIZE_STATIC (4 + T::static_size); 101 }; 102 103 template <typename T> 104 struct LookupFormat2 105 { 106 friend struct Lookup<T>; 107 108 private: get_valueAAT::LookupFormat2109 const T* get_value (hb_codepoint_t glyph_id) const 110 { 111 const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id); 112 return v ? &v->value : nullptr; 113 } 114 sanitizeAAT::LookupFormat2115 bool sanitize (hb_sanitize_context_t *c) const 116 { 117 TRACE_SANITIZE (this); 118 return_trace (segments.sanitize (c)); 119 } sanitizeAAT::LookupFormat2120 bool sanitize (hb_sanitize_context_t *c, const void *base) const 121 { 122 TRACE_SANITIZE (this); 123 return_trace (segments.sanitize (c, base)); 124 } 125 126 protected: 127 HBUINT16 format; /* Format identifier--format = 2 */ 128 VarSizedBinSearchArrayOf<LookupSegmentSingle<T>> 129 segments; /* The actual segments. These must already be sorted, 130 * according to the first word in each one (the last 131 * glyph in each segment). */ 132 public: 133 DEFINE_SIZE_ARRAY (8, segments); 134 }; 135 136 template <typename T> 137 struct LookupSegmentArray 138 { 139 static constexpr unsigned TerminationWordCount = 2u; 140 get_valueAAT::LookupSegmentArray141 const T* get_value (hb_codepoint_t glyph_id, const void *base) const 142 { 143 return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; 144 } 145 cmpAAT::LookupSegmentArray146 int cmp (hb_codepoint_t g) const 147 { return g < first ? -1 : g <= last ? 0 : +1; } 148 sanitizeAAT::LookupSegmentArray149 bool sanitize (hb_sanitize_context_t *c, const void *base) const 150 { 151 TRACE_SANITIZE (this); 152 return_trace (c->check_struct (this) && 153 first <= last && 154 valuesZ.sanitize (c, base, last - first + 1)); 155 } 156 template <typename ...Ts> sanitizeAAT::LookupSegmentArray157 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 158 { 159 TRACE_SANITIZE (this); 160 return_trace (c->check_struct (this) && 161 first <= last && 162 valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...)); 163 } 164 165 HBGlyphID last; /* Last GlyphID in this segment */ 166 HBGlyphID first; /* First GlyphID in this segment */ 167 NNOffset16To<UnsizedArrayOf<T>> 168 valuesZ; /* A 16-bit offset from the start of 169 * the table to the data. */ 170 public: 171 DEFINE_SIZE_STATIC (6); 172 }; 173 174 template <typename T> 175 struct LookupFormat4 176 { 177 friend struct Lookup<T>; 178 179 private: get_valueAAT::LookupFormat4180 const T* get_value (hb_codepoint_t glyph_id) const 181 { 182 const LookupSegmentArray<T> *v = segments.bsearch (glyph_id); 183 return v ? v->get_value (glyph_id, this) : nullptr; 184 } 185 sanitizeAAT::LookupFormat4186 bool sanitize (hb_sanitize_context_t *c) const 187 { 188 TRACE_SANITIZE (this); 189 return_trace (segments.sanitize (c, this)); 190 } sanitizeAAT::LookupFormat4191 bool sanitize (hb_sanitize_context_t *c, const void *base) const 192 { 193 TRACE_SANITIZE (this); 194 return_trace (segments.sanitize (c, this, base)); 195 } 196 197 protected: 198 HBUINT16 format; /* Format identifier--format = 4 */ 199 VarSizedBinSearchArrayOf<LookupSegmentArray<T>> 200 segments; /* The actual segments. These must already be sorted, 201 * according to the first word in each one (the last 202 * glyph in each segment). */ 203 public: 204 DEFINE_SIZE_ARRAY (8, segments); 205 }; 206 207 template <typename T> 208 struct LookupSingle 209 { 210 static constexpr unsigned TerminationWordCount = 1u; 211 cmpAAT::LookupSingle212 int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } 213 sanitizeAAT::LookupSingle214 bool sanitize (hb_sanitize_context_t *c) const 215 { 216 TRACE_SANITIZE (this); 217 return_trace (c->check_struct (this) && value.sanitize (c)); 218 } sanitizeAAT::LookupSingle219 bool sanitize (hb_sanitize_context_t *c, const void *base) const 220 { 221 TRACE_SANITIZE (this); 222 return_trace (c->check_struct (this) && value.sanitize (c, base)); 223 } 224 225 HBGlyphID glyph; /* Last GlyphID */ 226 T value; /* The lookup value (only one) */ 227 public: 228 DEFINE_SIZE_STATIC (2 + T::static_size); 229 }; 230 231 template <typename T> 232 struct LookupFormat6 233 { 234 friend struct Lookup<T>; 235 236 private: get_valueAAT::LookupFormat6237 const T* get_value (hb_codepoint_t glyph_id) const 238 { 239 const LookupSingle<T> *v = entries.bsearch (glyph_id); 240 return v ? &v->value : nullptr; 241 } 242 sanitizeAAT::LookupFormat6243 bool sanitize (hb_sanitize_context_t *c) const 244 { 245 TRACE_SANITIZE (this); 246 return_trace (entries.sanitize (c)); 247 } sanitizeAAT::LookupFormat6248 bool sanitize (hb_sanitize_context_t *c, const void *base) const 249 { 250 TRACE_SANITIZE (this); 251 return_trace (entries.sanitize (c, base)); 252 } 253 254 protected: 255 HBUINT16 format; /* Format identifier--format = 6 */ 256 VarSizedBinSearchArrayOf<LookupSingle<T>> 257 entries; /* The actual entries, sorted by glyph index. */ 258 public: 259 DEFINE_SIZE_ARRAY (8, entries); 260 }; 261 262 template <typename T> 263 struct LookupFormat8 264 { 265 friend struct Lookup<T>; 266 267 private: get_valueAAT::LookupFormat8268 const T* get_value (hb_codepoint_t glyph_id) const 269 { 270 return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? 271 &valueArrayZ[glyph_id - firstGlyph] : nullptr; 272 } 273 sanitizeAAT::LookupFormat8274 bool sanitize (hb_sanitize_context_t *c) const 275 { 276 TRACE_SANITIZE (this); 277 return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount)); 278 } sanitizeAAT::LookupFormat8279 bool sanitize (hb_sanitize_context_t *c, const void *base) const 280 { 281 TRACE_SANITIZE (this); 282 return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base)); 283 } 284 285 protected: 286 HBUINT16 format; /* Format identifier--format = 8 */ 287 HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */ 288 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last 289 * glyph minus the value of firstGlyph plus 1). */ 290 UnsizedArrayOf<T> 291 valueArrayZ; /* The lookup values (indexed by the glyph index 292 * minus the value of firstGlyph). */ 293 public: 294 DEFINE_SIZE_ARRAY (6, valueArrayZ); 295 }; 296 297 template <typename T> 298 struct LookupFormat10 299 { 300 friend struct Lookup<T>; 301 302 private: get_value_or_nullAAT::LookupFormat10303 const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const 304 { 305 if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount)) 306 return Null (T); 307 308 const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize]; 309 310 unsigned int v = 0; 311 unsigned int count = valueSize; 312 for (unsigned int i = 0; i < count; i++) 313 v = (v << 8) | *p++; 314 315 return v; 316 } 317 sanitizeAAT::LookupFormat10318 bool sanitize (hb_sanitize_context_t *c) const 319 { 320 TRACE_SANITIZE (this); 321 return_trace (c->check_struct (this) && 322 valueSize <= 4 && 323 valueArrayZ.sanitize (c, glyphCount * valueSize)); 324 } 325 326 protected: 327 HBUINT16 format; /* Format identifier--format = 8 */ 328 HBUINT16 valueSize; /* Byte size of each value. */ 329 HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */ 330 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last 331 * glyph minus the value of firstGlyph plus 1). */ 332 UnsizedArrayOf<HBUINT8> 333 valueArrayZ; /* The lookup values (indexed by the glyph index 334 * minus the value of firstGlyph). */ 335 public: 336 DEFINE_SIZE_ARRAY (8, valueArrayZ); 337 }; 338 339 template <typename T> 340 struct Lookup 341 { get_valueAAT::Lookup342 const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 343 { 344 switch (u.format) { 345 case 0: return u.format0.get_value (glyph_id, num_glyphs); 346 case 2: return u.format2.get_value (glyph_id); 347 case 4: return u.format4.get_value (glyph_id); 348 case 6: return u.format6.get_value (glyph_id); 349 case 8: return u.format8.get_value (glyph_id); 350 default:return nullptr; 351 } 352 } 353 get_value_or_nullAAT::Lookup354 const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 355 { 356 switch (u.format) { 357 /* Format 10 cannot return a pointer. */ 358 case 10: return u.format10.get_value_or_null (glyph_id); 359 default: 360 const T *v = get_value (glyph_id, num_glyphs); 361 return v ? *v : Null (T); 362 } 363 } 364 get_classAAT::Lookup365 typename T::type get_class (hb_codepoint_t glyph_id, 366 unsigned int num_glyphs, 367 unsigned int outOfRange) const 368 { 369 const T *v = get_value (glyph_id, num_glyphs); 370 return v ? *v : outOfRange; 371 } 372 sanitizeAAT::Lookup373 bool sanitize (hb_sanitize_context_t *c) const 374 { 375 TRACE_SANITIZE (this); 376 if (!u.format.sanitize (c)) return_trace (false); 377 switch (u.format) { 378 case 0: return_trace (u.format0.sanitize (c)); 379 case 2: return_trace (u.format2.sanitize (c)); 380 case 4: return_trace (u.format4.sanitize (c)); 381 case 6: return_trace (u.format6.sanitize (c)); 382 case 8: return_trace (u.format8.sanitize (c)); 383 case 10: return_trace (u.format10.sanitize (c)); 384 default:return_trace (true); 385 } 386 } sanitizeAAT::Lookup387 bool sanitize (hb_sanitize_context_t *c, const void *base) const 388 { 389 TRACE_SANITIZE (this); 390 if (!u.format.sanitize (c)) return_trace (false); 391 switch (u.format) { 392 case 0: return_trace (u.format0.sanitize (c, base)); 393 case 2: return_trace (u.format2.sanitize (c, base)); 394 case 4: return_trace (u.format4.sanitize (c, base)); 395 case 6: return_trace (u.format6.sanitize (c, base)); 396 case 8: return_trace (u.format8.sanitize (c, base)); 397 case 10: return_trace (false); /* We don't support format10 here currently. */ 398 default:return_trace (true); 399 } 400 } 401 402 protected: 403 union { 404 HBUINT16 format; /* Format identifier */ 405 LookupFormat0<T> format0; 406 LookupFormat2<T> format2; 407 LookupFormat4<T> format4; 408 LookupFormat6<T> format6; 409 LookupFormat8<T> format8; 410 LookupFormat10<T> format10; 411 } u; 412 public: 413 DEFINE_SIZE_UNION (2, format); 414 }; 415 /* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined 416 * special NULL objects for Lookup<> objects, but since it's template our macros 417 * don't work. So we have to hand-code them here. UGLY. */ 418 } /* Close namespace. */ 419 /* Ugly hand-coded null objects for template Lookup<> :(. */ 420 extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2]; 421 template <typename T> 422 struct Null<AAT::Lookup<T>> { get_nullNull423 static AAT::Lookup<T> const & get_null () 424 { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); } 425 }; 426 namespace AAT { 427 428 enum { DELETED_GLYPH = 0xFFFF }; 429 430 /* 431 * (Extended) State Table 432 */ 433 434 template <typename T> 435 struct Entry 436 { sanitizeAAT::Entry437 bool sanitize (hb_sanitize_context_t *c, unsigned int count) const 438 { 439 TRACE_SANITIZE (this); 440 /* Note, we don't recurse-sanitize data because we don't access it. 441 * That said, in our DEFINE_SIZE_STATIC we access T::static_size, 442 * which ensures that data has a simple sanitize(). To be determined 443 * if I need to remove that as well. 444 * 445 * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC 446 * assertion wouldn't be checked, hence the line below. */ 447 static_assert (T::static_size, ""); 448 449 return_trace (c->check_struct (this)); 450 } 451 452 public: 453 HBUINT16 newState; /* Byte offset from beginning of state table 454 * to the new state. Really?!?! Or just state 455 * number? The latter in morx for sure. */ 456 HBUINT16 flags; /* Table specific. */ 457 T data; /* Optional offsets to per-glyph tables. */ 458 public: 459 DEFINE_SIZE_STATIC (4 + T::static_size); 460 }; 461 462 template <> 463 struct Entry<void> 464 { sanitizeAAT::Entry465 bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const 466 { 467 TRACE_SANITIZE (this); 468 return_trace (c->check_struct (this)); 469 } 470 471 public: 472 HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */ 473 HBUINT16 flags; /* Table specific. */ 474 public: 475 DEFINE_SIZE_STATIC (4); 476 }; 477 478 template <typename Types, typename Extra> 479 struct StateTable 480 { 481 typedef typename Types::HBUINT HBUINT; 482 typedef typename Types::HBUSHORT HBUSHORT; 483 typedef typename Types::ClassTypeNarrow ClassType; 484 485 enum State 486 { 487 STATE_START_OF_TEXT = 0, 488 STATE_START_OF_LINE = 1, 489 }; 490 enum Class 491 { 492 CLASS_END_OF_TEXT = 0, 493 CLASS_OUT_OF_BOUNDS = 1, 494 CLASS_DELETED_GLYPH = 2, 495 CLASS_END_OF_LINE = 3, 496 }; 497 new_stateAAT::StateTable498 int new_state (unsigned int newState) const 499 { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } 500 get_classAAT::StateTable501 unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 502 { 503 if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; 504 return (this+classTable).get_class (glyph_id, num_glyphs, 1); 505 } 506 get_entriesAAT::StateTable507 const Entry<Extra> *get_entries () const 508 { return (this+entryTable).arrayZ; } 509 get_entryAAT::StateTable510 const Entry<Extra> &get_entry (int state, unsigned int klass) const 511 { 512 if (unlikely (klass >= nClasses)) 513 klass = StateTable::CLASS_OUT_OF_BOUNDS; 514 515 const HBUSHORT *states = (this+stateArrayTable).arrayZ; 516 const Entry<Extra> *entries = (this+entryTable).arrayZ; 517 518 unsigned int entry = states[state * nClasses + klass]; 519 DEBUG_MSG (APPLY, nullptr, "e%u", entry); 520 521 return entries[entry]; 522 } 523 sanitizeAAT::StateTable524 bool sanitize (hb_sanitize_context_t *c, 525 unsigned int *num_entries_out = nullptr) const 526 { 527 TRACE_SANITIZE (this); 528 if (unlikely (!(c->check_struct (this) && 529 nClasses >= 4 /* Ensure pre-defined classes fit. */ && 530 classTable.sanitize (c, this)))) return_trace (false); 531 532 const HBUSHORT *states = (this+stateArrayTable).arrayZ; 533 const Entry<Extra> *entries = (this+entryTable).arrayZ; 534 535 unsigned int num_classes = nClasses; 536 if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size))) 537 return_trace (false); 538 unsigned int row_stride = num_classes * states[0].static_size; 539 540 /* Apple 'kern' table has this peculiarity: 541 * 542 * "Because the stateTableOffset in the state table header is (strictly 543 * speaking) redundant, some 'kern' tables use it to record an initial 544 * state where that should not be StartOfText. To determine if this is 545 * done, calculate what the stateTableOffset should be. If it's different 546 * from the actual stateTableOffset, use it as the initial state." 547 * 548 * We implement this by calling the initial state zero, but allow *negative* 549 * states if the start state indeed was not the first state. Since the code 550 * is shared, this will also apply to 'mort' table. The 'kerx' / 'morx' 551 * tables are not affected since those address states by index, not offset. 552 */ 553 554 int min_state = 0; 555 int max_state = 0; 556 unsigned int num_entries = 0; 557 558 int state_pos = 0; 559 int state_neg = 0; 560 unsigned int entry = 0; 561 while (min_state < state_neg || state_pos <= max_state) 562 { 563 if (min_state < state_neg) 564 { 565 /* Negative states. */ 566 if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) 567 return_trace (false); 568 if (unlikely (!c->check_range (&states[min_state * num_classes], 569 -min_state, 570 row_stride))) 571 return_trace (false); 572 if ((c->max_ops -= state_neg - min_state) <= 0) 573 return_trace (false); 574 { /* Sweep new states. */ 575 const HBUSHORT *stop = &states[min_state * num_classes]; 576 if (unlikely (stop > states)) 577 return_trace (false); 578 for (const HBUSHORT *p = states; stop < p; p--) 579 num_entries = hb_max (num_entries, *(p - 1) + 1u); 580 state_neg = min_state; 581 } 582 } 583 584 if (state_pos <= max_state) 585 { 586 /* Positive states. */ 587 if (unlikely (!c->check_range (states, 588 max_state + 1, 589 row_stride))) 590 return_trace (false); 591 if ((c->max_ops -= max_state - state_pos + 1) <= 0) 592 return_trace (false); 593 { /* Sweep new states. */ 594 if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes))) 595 return_trace (false); 596 const HBUSHORT *stop = &states[(max_state + 1) * num_classes]; 597 if (unlikely (stop < states)) 598 return_trace (false); 599 for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++) 600 num_entries = hb_max (num_entries, *p + 1u); 601 state_pos = max_state + 1; 602 } 603 } 604 605 if (unlikely (!c->check_array (entries, num_entries))) 606 return_trace (false); 607 if ((c->max_ops -= num_entries - entry) <= 0) 608 return_trace (false); 609 { /* Sweep new entries. */ 610 const Entry<Extra> *stop = &entries[num_entries]; 611 for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) 612 { 613 int newState = new_state (p->newState); 614 min_state = hb_min (min_state, newState); 615 max_state = hb_max (max_state, newState); 616 } 617 entry = num_entries; 618 } 619 } 620 621 if (num_entries_out) 622 *num_entries_out = num_entries; 623 624 return_trace (true); 625 } 626 627 protected: 628 HBUINT nClasses; /* Number of classes, which is the number of indices 629 * in a single line in the state array. */ 630 NNOffsetTo<ClassType, HBUINT> 631 classTable; /* Offset to the class table. */ 632 NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT> 633 stateArrayTable;/* Offset to the state array. */ 634 NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT> 635 entryTable; /* Offset to the entry array. */ 636 637 public: 638 DEFINE_SIZE_STATIC (4 * sizeof (HBUINT)); 639 }; 640 641 template <typename HBUCHAR> 642 struct ClassTable 643 { get_classAAT::ClassTable644 unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const 645 { 646 unsigned int i = glyph_id - firstGlyph; 647 return i >= classArray.len ? outOfRange : classArray.arrayZ[i]; 648 } get_classAAT::ClassTable649 unsigned int get_class (hb_codepoint_t glyph_id, 650 unsigned int num_glyphs HB_UNUSED, 651 unsigned int outOfRange) const 652 { 653 return get_class (glyph_id, outOfRange); 654 } sanitizeAAT::ClassTable655 bool sanitize (hb_sanitize_context_t *c) const 656 { 657 TRACE_SANITIZE (this); 658 return_trace (c->check_struct (this) && classArray.sanitize (c)); 659 } 660 protected: 661 HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */ 662 Array16Of<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus 663 * firstGlyph). */ 664 public: 665 DEFINE_SIZE_ARRAY (4, classArray); 666 }; 667 668 struct ObsoleteTypes 669 { 670 static constexpr bool extended = false; 671 typedef HBUINT16 HBUINT; 672 typedef HBUINT8 HBUSHORT; 673 typedef ClassTable<HBUINT8> ClassTypeNarrow; 674 typedef ClassTable<HBUINT16> ClassTypeWide; 675 676 template <typename T> offsetToIndexAAT::ObsoleteTypes677 static unsigned int offsetToIndex (unsigned int offset, 678 const void *base, 679 const T *array) 680 { 681 /* https://github.com/harfbuzz/harfbuzz/issues/2816 */ 682 return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size; 683 } 684 template <typename T> byteOffsetToIndexAAT::ObsoleteTypes685 static unsigned int byteOffsetToIndex (unsigned int offset, 686 const void *base, 687 const T *array) 688 { 689 return offsetToIndex (offset, base, array); 690 } 691 template <typename T> wordOffsetToIndexAAT::ObsoleteTypes692 static unsigned int wordOffsetToIndex (unsigned int offset, 693 const void *base, 694 const T *array) 695 { 696 return offsetToIndex (2 * offset, base, array); 697 } 698 }; 699 struct ExtendedTypes 700 { 701 static constexpr bool extended = true; 702 typedef HBUINT32 HBUINT; 703 typedef HBUINT16 HBUSHORT; 704 typedef Lookup<HBUINT16> ClassTypeNarrow; 705 typedef Lookup<HBUINT16> ClassTypeWide; 706 707 template <typename T> offsetToIndexAAT::ExtendedTypes708 static unsigned int offsetToIndex (unsigned int offset, 709 const void *base HB_UNUSED, 710 const T *array HB_UNUSED) 711 { 712 return offset; 713 } 714 template <typename T> byteOffsetToIndexAAT::ExtendedTypes715 static unsigned int byteOffsetToIndex (unsigned int offset, 716 const void *base HB_UNUSED, 717 const T *array HB_UNUSED) 718 { 719 return offset / 2; 720 } 721 template <typename T> wordOffsetToIndexAAT::ExtendedTypes722 static unsigned int wordOffsetToIndex (unsigned int offset, 723 const void *base HB_UNUSED, 724 const T *array HB_UNUSED) 725 { 726 return offset; 727 } 728 }; 729 730 template <typename Types, typename EntryData> 731 struct StateTableDriver 732 { 733 using StateTableT = StateTable<Types, EntryData>; 734 using EntryT = Entry<EntryData>; 735 StateTableDriverAAT::StateTableDriver736 StateTableDriver (const StateTableT &machine_, 737 hb_buffer_t *buffer_, 738 hb_face_t *face_) : 739 machine (machine_), 740 buffer (buffer_), 741 num_glyphs (face_->get_num_glyphs ()) {} 742 743 template <typename context_t> driveAAT::StateTableDriver744 void drive (context_t *c) 745 { 746 if (!c->in_place) 747 buffer->clear_output (); 748 749 int state = StateTableT::STATE_START_OF_TEXT; 750 for (buffer->idx = 0; buffer->successful;) 751 { 752 unsigned int klass = buffer->idx < buffer->len ? 753 machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : 754 (unsigned) StateTableT::CLASS_END_OF_TEXT; 755 DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); 756 const EntryT &entry = machine.get_entry (state, klass); 757 const int next_state = machine.new_state (entry.newState); 758 759 /* Conditions under which it's guaranteed safe-to-break before current glyph: 760 * 761 * 1. There was no action in this transition; and 762 * 763 * 2. If we break before current glyph, the results will be the same. That 764 * is guaranteed if: 765 * 766 * 2a. We were already in start-of-text state; or 767 * 768 * 2b. We are epsilon-transitioning to start-of-text state; or 769 * 770 * 2c. Starting from start-of-text state seeing current glyph: 771 * 772 * 2c'. There won't be any actions; and 773 * 774 * 2c". We would end up in the same state that we were going to end up 775 * in now, including whether epsilon-transitioning. 776 * 777 * and 778 * 779 * 3. If we break before current glyph, there won't be any end-of-text action 780 * after previous glyph. 781 * 782 * This triples the transitions we need to look up, but is worth returning 783 * granular unsafe-to-break results. See eg.: 784 * 785 * https://github.com/harfbuzz/harfbuzz/issues/2860 786 */ 787 const EntryT *wouldbe_entry; 788 bool safe_to_break = 789 /* 1. */ 790 !c->is_actionable (this, entry) 791 && 792 /* 2. */ 793 ( 794 /* 2a. */ 795 state == StateTableT::STATE_START_OF_TEXT 796 || 797 /* 2b. */ 798 ( 799 (entry.flags & context_t::DontAdvance) && 800 next_state == StateTableT::STATE_START_OF_TEXT 801 ) 802 || 803 /* 2c. */ 804 ( 805 wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass) 806 , 807 /* 2c'. */ 808 !c->is_actionable (this, *wouldbe_entry) 809 && 810 /* 2c". */ 811 ( 812 next_state == machine.new_state (wouldbe_entry->newState) 813 && 814 (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance) 815 ) 816 ) 817 ) 818 && 819 /* 3. */ 820 !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT)) 821 ; 822 823 if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len) 824 buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); 825 826 c->transition (this, entry); 827 828 state = next_state; 829 DEBUG_MSG (APPLY, nullptr, "s%d", state); 830 831 if (buffer->idx == buffer->len || unlikely (!buffer->successful)) 832 break; 833 834 if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) 835 (void) buffer->next_glyph (); 836 } 837 838 if (!c->in_place) 839 buffer->swap_buffers (); 840 } 841 842 public: 843 const StateTableT &machine; 844 hb_buffer_t *buffer; 845 unsigned int num_glyphs; 846 }; 847 848 849 struct ankr; 850 851 struct hb_aat_apply_context_t : 852 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> 853 { get_nameAAT::hb_aat_apply_context_t854 const char *get_name () { return "APPLY"; } 855 template <typename T> dispatchAAT::hb_aat_apply_context_t856 return_t dispatch (const T &obj) { return obj.apply (this); } default_return_valueAAT::hb_aat_apply_context_t857 static return_t default_return_value () { return false; } stop_sublookup_iterationAAT::hb_aat_apply_context_t858 bool stop_sublookup_iteration (return_t r) const { return r; } 859 860 const hb_ot_shape_plan_t *plan; 861 hb_font_t *font; 862 hb_face_t *face; 863 hb_buffer_t *buffer; 864 hb_sanitize_context_t sanitizer; 865 const ankr *ankr_table; 866 867 /* Unused. For debug tracing only. */ 868 unsigned int lookup_index; 869 870 HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, 871 hb_font_t *font_, 872 hb_buffer_t *buffer_, 873 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t))); 874 875 HB_INTERNAL ~hb_aat_apply_context_t (); 876 877 HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); 878 set_lookup_indexAAT::hb_aat_apply_context_t879 void set_lookup_index (unsigned int i) { lookup_index = i; } 880 }; 881 882 883 } /* namespace AAT */ 884 885 886 #endif /* HB_AAT_LAYOUT_COMMON_HH */ 887