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-aat-map.hh" 32 #include "hb-open-type.hh" 33 34 namespace OT { 35 struct GDEF; 36 }; 37 38 namespace AAT { 39 40 using namespace OT; 41 42 #define HB_AAT_BUFFER_DIGEST_THRESHOLD 32 43 44 struct ankr; 45 46 struct hb_aat_apply_context_t : 47 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> 48 { get_nameAAT::hb_aat_apply_context_t49 const char *get_name () { return "APPLY"; } 50 template <typename T, typename ...Ts> dispatchAAT::hb_aat_apply_context_t51 return_t dispatch (const T &obj, Ts&&... ds) 52 { return obj.apply (this, std::forward<Ts> (ds)...); } default_return_valueAAT::hb_aat_apply_context_t53 static return_t default_return_value () { return false; } stop_sublookup_iterationAAT::hb_aat_apply_context_t54 bool stop_sublookup_iteration (return_t r) const { return r; } 55 56 const hb_ot_shape_plan_t *plan; 57 hb_font_t *font; 58 hb_face_t *face; 59 hb_buffer_t *buffer; 60 hb_sanitize_context_t sanitizer; 61 const ankr *ankr_table; 62 const OT::GDEF *gdef_table; 63 const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr; 64 hb_set_digest_t buffer_digest = hb_set_digest_t::full (); 65 hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); 66 hb_set_digest_t left_set = hb_set_digest_t::full (); 67 hb_set_digest_t right_set = hb_set_digest_t::full (); 68 hb_mask_t subtable_flags = 0; 69 70 /* Unused. For debug tracing only. */ 71 unsigned int lookup_index; 72 73 HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, 74 hb_font_t *font_, 75 hb_buffer_t *buffer_, 76 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t))); 77 78 HB_INTERNAL ~hb_aat_apply_context_t (); 79 80 HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); 81 set_lookup_indexAAT::hb_aat_apply_context_t82 void set_lookup_index (unsigned int i) { lookup_index = i; } 83 }; 84 85 86 /* 87 * Lookup Table 88 */ 89 90 enum { DELETED_GLYPH = 0xFFFF }; 91 92 template <typename T> struct Lookup; 93 94 template <typename T> 95 struct LookupFormat0 96 { 97 friend struct Lookup<T>; 98 99 private: get_valueAAT::LookupFormat0100 const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 101 { 102 if (unlikely (glyph_id >= num_glyphs)) return nullptr; 103 return &arrayZ[glyph_id]; 104 } 105 106 template <typename set_t> collect_glyphsAAT::LookupFormat0107 void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const 108 { 109 glyphs.add_range (0, num_glyphs - 1); 110 } 111 sanitizeAAT::LookupFormat0112 bool sanitize (hb_sanitize_context_t *c) const 113 { 114 TRACE_SANITIZE (this); 115 return_trace (arrayZ.sanitize (c, c->get_num_glyphs ())); 116 } sanitizeAAT::LookupFormat0117 bool sanitize (hb_sanitize_context_t *c, const void *base) const 118 { 119 TRACE_SANITIZE (this); 120 return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base)); 121 } 122 123 protected: 124 HBUINT16 format; /* Format identifier--format = 0 */ 125 UnsizedArrayOf<T> 126 arrayZ; /* Array of lookup values, indexed by glyph index. */ 127 public: 128 DEFINE_SIZE_UNBOUNDED (2); 129 }; 130 131 132 template <typename T> 133 struct LookupSegmentSingle 134 { 135 static constexpr unsigned TerminationWordCount = 2u; 136 cmpAAT::LookupSegmentSingle137 int cmp (hb_codepoint_t g) const 138 { return g < first ? -1 : g <= last ? 0 : +1 ; } 139 140 template <typename set_t> collect_glyphsAAT::LookupSegmentSingle141 void collect_glyphs (set_t &glyphs) const 142 { 143 if (first == DELETED_GLYPH) 144 return; 145 glyphs.add_range (first, last); 146 } 147 sanitizeAAT::LookupSegmentSingle148 bool sanitize (hb_sanitize_context_t *c) const 149 { 150 TRACE_SANITIZE (this); 151 return_trace (c->check_struct (this) && value.sanitize (c)); 152 } sanitizeAAT::LookupSegmentSingle153 bool sanitize (hb_sanitize_context_t *c, const void *base) const 154 { 155 TRACE_SANITIZE (this); 156 return_trace (c->check_struct (this) && value.sanitize (c, base)); 157 } 158 159 HBGlyphID16 last; /* Last GlyphID in this segment */ 160 HBGlyphID16 first; /* First GlyphID in this segment */ 161 T value; /* The lookup value (only one) */ 162 public: 163 DEFINE_SIZE_STATIC (4 + T::static_size); 164 }; 165 166 template <typename T> 167 struct LookupFormat2 168 { 169 friend struct Lookup<T>; 170 171 private: get_valueAAT::LookupFormat2172 const T* get_value (hb_codepoint_t glyph_id) const 173 { 174 const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id); 175 return v ? &v->value : nullptr; 176 } 177 178 template <typename set_t> collect_glyphsAAT::LookupFormat2179 void collect_glyphs (set_t &glyphs) const 180 { 181 unsigned count = segments.get_length (); 182 for (unsigned int i = 0; i < count; i++) 183 segments[i].collect_glyphs (glyphs); 184 } 185 sanitizeAAT::LookupFormat2186 bool sanitize (hb_sanitize_context_t *c) const 187 { 188 TRACE_SANITIZE (this); 189 return_trace (segments.sanitize (c)); 190 } sanitizeAAT::LookupFormat2191 bool sanitize (hb_sanitize_context_t *c, const void *base) const 192 { 193 TRACE_SANITIZE (this); 194 return_trace (segments.sanitize (c, base)); 195 } 196 197 protected: 198 HBUINT16 format; /* Format identifier--format = 2 */ 199 VarSizedBinSearchArrayOf<LookupSegmentSingle<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 LookupSegmentArray 209 { 210 static constexpr unsigned TerminationWordCount = 2u; 211 get_valueAAT::LookupSegmentArray212 const T* get_value (hb_codepoint_t glyph_id, const void *base) const 213 { 214 return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; 215 } 216 217 template <typename set_t> collect_glyphsAAT::LookupSegmentArray218 void collect_glyphs (set_t &glyphs) const 219 { 220 if (first == DELETED_GLYPH) 221 return; 222 glyphs.add_range (first, last); 223 } 224 cmpAAT::LookupSegmentArray225 int cmp (hb_codepoint_t g) const 226 { return g < first ? -1 : g <= last ? 0 : +1; } 227 sanitizeAAT::LookupSegmentArray228 bool sanitize (hb_sanitize_context_t *c, const void *base) const 229 { 230 TRACE_SANITIZE (this); 231 return_trace (c->check_struct (this) && 232 hb_barrier () && 233 first <= last && 234 valuesZ.sanitize (c, base, last - first + 1)); 235 } 236 template <typename ...Ts> sanitizeAAT::LookupSegmentArray237 bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 238 { 239 TRACE_SANITIZE (this); 240 return_trace (c->check_struct (this) && 241 hb_barrier () && 242 first <= last && 243 valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...)); 244 } 245 246 HBGlyphID16 last; /* Last GlyphID in this segment */ 247 HBGlyphID16 first; /* First GlyphID in this segment */ 248 NNOffset16To<UnsizedArrayOf<T>> 249 valuesZ; /* A 16-bit offset from the start of 250 * the table to the data. */ 251 public: 252 DEFINE_SIZE_STATIC (6); 253 }; 254 255 template <typename T> 256 struct LookupFormat4 257 { 258 friend struct Lookup<T>; 259 260 private: get_valueAAT::LookupFormat4261 const T* get_value (hb_codepoint_t glyph_id) const 262 { 263 const LookupSegmentArray<T> *v = segments.bsearch (glyph_id); 264 return v ? v->get_value (glyph_id, this) : nullptr; 265 } 266 267 template <typename set_t> collect_glyphsAAT::LookupFormat4268 void collect_glyphs (set_t &glyphs) const 269 { 270 unsigned count = segments.get_length (); 271 for (unsigned i = 0; i < count; i++) 272 segments[i].collect_glyphs (glyphs); 273 } 274 sanitizeAAT::LookupFormat4275 bool sanitize (hb_sanitize_context_t *c) const 276 { 277 TRACE_SANITIZE (this); 278 return_trace (segments.sanitize (c, this)); 279 } sanitizeAAT::LookupFormat4280 bool sanitize (hb_sanitize_context_t *c, const void *base) const 281 { 282 TRACE_SANITIZE (this); 283 return_trace (segments.sanitize (c, this, base)); 284 } 285 286 protected: 287 HBUINT16 format; /* Format identifier--format = 4 */ 288 VarSizedBinSearchArrayOf<LookupSegmentArray<T>> 289 segments; /* The actual segments. These must already be sorted, 290 * according to the first word in each one (the last 291 * glyph in each segment). */ 292 public: 293 DEFINE_SIZE_ARRAY (8, segments); 294 }; 295 296 template <typename T> 297 struct LookupSingle 298 { 299 static constexpr unsigned TerminationWordCount = 1u; 300 cmpAAT::LookupSingle301 int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } 302 303 template <typename set_t> collect_glyphsAAT::LookupSingle304 void collect_glyphs (set_t &glyphs) const 305 { 306 if (glyph == DELETED_GLYPH) 307 return; 308 glyphs.add (glyph); 309 } 310 sanitizeAAT::LookupSingle311 bool sanitize (hb_sanitize_context_t *c) const 312 { 313 TRACE_SANITIZE (this); 314 return_trace (c->check_struct (this) && value.sanitize (c)); 315 } sanitizeAAT::LookupSingle316 bool sanitize (hb_sanitize_context_t *c, const void *base) const 317 { 318 TRACE_SANITIZE (this); 319 return_trace (c->check_struct (this) && value.sanitize (c, base)); 320 } 321 322 HBGlyphID16 glyph; /* Last GlyphID */ 323 T value; /* The lookup value (only one) */ 324 public: 325 DEFINE_SIZE_STATIC (2 + T::static_size); 326 }; 327 328 template <typename T> 329 struct LookupFormat6 330 { 331 friend struct Lookup<T>; 332 333 private: get_valueAAT::LookupFormat6334 const T* get_value (hb_codepoint_t glyph_id) const 335 { 336 const LookupSingle<T> *v = entries.bsearch (glyph_id); 337 return v ? &v->value : nullptr; 338 } 339 340 template <typename set_t> collect_glyphsAAT::LookupFormat6341 void collect_glyphs (set_t &glyphs) const 342 { 343 unsigned count = entries.get_length (); 344 for (unsigned i = 0; i < count; i++) 345 entries[i].collect_glyphs (glyphs); 346 } 347 sanitizeAAT::LookupFormat6348 bool sanitize (hb_sanitize_context_t *c) const 349 { 350 TRACE_SANITIZE (this); 351 return_trace (entries.sanitize (c)); 352 } sanitizeAAT::LookupFormat6353 bool sanitize (hb_sanitize_context_t *c, const void *base) const 354 { 355 TRACE_SANITIZE (this); 356 return_trace (entries.sanitize (c, base)); 357 } 358 359 protected: 360 HBUINT16 format; /* Format identifier--format = 6 */ 361 VarSizedBinSearchArrayOf<LookupSingle<T>> 362 entries; /* The actual entries, sorted by glyph index. */ 363 public: 364 DEFINE_SIZE_ARRAY (8, entries); 365 }; 366 367 template <typename T> 368 struct LookupFormat8 369 { 370 friend struct Lookup<T>; 371 372 private: get_valueAAT::LookupFormat8373 const T* get_value (hb_codepoint_t glyph_id) const 374 { 375 return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? 376 &valueArrayZ[glyph_id - firstGlyph] : nullptr; 377 } 378 379 template <typename set_t> collect_glyphsAAT::LookupFormat8380 void collect_glyphs (set_t &glyphs) const 381 { 382 if (unlikely (!glyphCount)) 383 return; 384 if (firstGlyph == DELETED_GLYPH) 385 return; 386 glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); 387 } 388 sanitizeAAT::LookupFormat8389 bool sanitize (hb_sanitize_context_t *c) const 390 { 391 TRACE_SANITIZE (this); 392 return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount)); 393 } sanitizeAAT::LookupFormat8394 bool sanitize (hb_sanitize_context_t *c, const void *base) const 395 { 396 TRACE_SANITIZE (this); 397 return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base)); 398 } 399 400 protected: 401 HBUINT16 format; /* Format identifier--format = 8 */ 402 HBGlyphID16 firstGlyph; /* First glyph index included in the trimmed array. */ 403 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last 404 * glyph minus the value of firstGlyph plus 1). */ 405 UnsizedArrayOf<T> 406 valueArrayZ; /* The lookup values (indexed by the glyph index 407 * minus the value of firstGlyph). */ 408 public: 409 DEFINE_SIZE_ARRAY (6, valueArrayZ); 410 }; 411 412 template <typename T> 413 struct LookupFormat10 414 { 415 friend struct Lookup<T>; 416 417 private: get_value_or_nullAAT::LookupFormat10418 const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const 419 { 420 if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount)) 421 return Null (T); 422 423 const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize]; 424 425 unsigned int v = 0; 426 unsigned int count = valueSize; 427 for (unsigned int i = 0; i < count; i++) 428 v = (v << 8) | *p++; 429 430 return v; 431 } 432 433 template <typename set_t> collect_glyphsAAT::LookupFormat10434 void collect_glyphs (set_t &glyphs) const 435 { 436 if (unlikely (!glyphCount)) 437 return; 438 if (firstGlyph == DELETED_GLYPH) 439 return; 440 glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); 441 } 442 sanitizeAAT::LookupFormat10443 bool sanitize (hb_sanitize_context_t *c) const 444 { 445 TRACE_SANITIZE (this); 446 return_trace (c->check_struct (this) && 447 hb_barrier () && 448 valueSize <= 4 && 449 valueArrayZ.sanitize (c, glyphCount * valueSize)); 450 } 451 452 protected: 453 HBUINT16 format; /* Format identifier--format = 8 */ 454 HBUINT16 valueSize; /* Byte size of each value. */ 455 HBGlyphID16 firstGlyph; /* First glyph index included in the trimmed array. */ 456 HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last 457 * glyph minus the value of firstGlyph plus 1). */ 458 UnsizedArrayOf<HBUINT8> 459 valueArrayZ; /* The lookup values (indexed by the glyph index 460 * minus the value of firstGlyph). */ 461 public: 462 DEFINE_SIZE_ARRAY (8, valueArrayZ); 463 }; 464 465 template <typename T> 466 struct Lookup 467 { get_valueAAT::Lookup468 const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 469 { 470 switch (u.format) { 471 case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs); 472 case 2: hb_barrier (); return u.format2.get_value (glyph_id); 473 case 4: hb_barrier (); return u.format4.get_value (glyph_id); 474 case 6: hb_barrier (); return u.format6.get_value (glyph_id); 475 case 8: hb_barrier (); return u.format8.get_value (glyph_id); 476 default:return nullptr; 477 } 478 } 479 get_value_or_nullAAT::Lookup480 const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 481 { 482 switch (u.format) { 483 /* Format 10 cannot return a pointer. */ 484 case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id); 485 default: 486 const T *v = get_value (glyph_id, num_glyphs); 487 return v ? *v : Null (T); 488 } 489 } 490 491 template <typename set_t> collect_glyphsAAT::Lookup492 void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const 493 { 494 switch (u.format) { 495 case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return; 496 case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return; 497 case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return; 498 case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return; 499 case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return; 500 case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return; 501 default:return; 502 } 503 } 504 get_classAAT::Lookup505 typename T::type get_class (hb_codepoint_t glyph_id, 506 unsigned int num_glyphs, 507 unsigned int outOfRange) const 508 { 509 const T *v = get_value (glyph_id, num_glyphs); 510 return v ? *v : outOfRange; 511 } 512 sanitizeAAT::Lookup513 bool sanitize (hb_sanitize_context_t *c) const 514 { 515 TRACE_SANITIZE (this); 516 if (!u.format.sanitize (c)) return_trace (false); 517 hb_barrier (); 518 switch (u.format) { 519 case 0: hb_barrier (); return_trace (u.format0.sanitize (c)); 520 case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); 521 case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); 522 case 6: hb_barrier (); return_trace (u.format6.sanitize (c)); 523 case 8: hb_barrier (); return_trace (u.format8.sanitize (c)); 524 case 10: hb_barrier (); return_trace (u.format10.sanitize (c)); 525 default:return_trace (true); 526 } 527 } sanitizeAAT::Lookup528 bool sanitize (hb_sanitize_context_t *c, const void *base) const 529 { 530 TRACE_SANITIZE (this); 531 if (!u.format.sanitize (c)) return_trace (false); 532 hb_barrier (); 533 switch (u.format) { 534 case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base)); 535 case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base)); 536 case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base)); 537 case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base)); 538 case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base)); 539 case 10: return_trace (false); /* We don't support format10 here currently. */ 540 default:return_trace (true); 541 } 542 } 543 544 protected: 545 union { 546 HBUINT16 format; /* Format identifier */ 547 LookupFormat0<T> format0; 548 LookupFormat2<T> format2; 549 LookupFormat4<T> format4; 550 LookupFormat6<T> format6; 551 LookupFormat8<T> format8; 552 LookupFormat10<T> format10; 553 } u; 554 public: 555 DEFINE_SIZE_UNION (2, format); 556 }; 557 DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); 558 559 /* 560 * (Extended) State Table 561 */ 562 563 template <typename T> 564 struct Entry 565 { 566 // This does seem like it's ever called. sanitizeAAT::Entry567 bool sanitize (hb_sanitize_context_t *c) const 568 { 569 TRACE_SANITIZE (this); 570 /* Note, we don't recurse-sanitize data because we don't access it. 571 * That said, in our DEFINE_SIZE_STATIC we access T::static_size, 572 * which ensures that data has a simple sanitize(). To be determined 573 * if I need to remove that as well. 574 * 575 * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC 576 * assertion wouldn't be checked, hence the line below. */ 577 static_assert (T::static_size, ""); 578 579 return_trace (c->check_struct (this)); 580 } 581 582 public: 583 HBUINT16 newState; /* Byte offset from beginning of state table 584 * to the new state. Really?!?! Or just state 585 * number? The latter in morx for sure. */ 586 HBUINT16 flags; /* Table specific. */ 587 T data; /* Optional offsets to per-glyph tables. */ 588 public: 589 DEFINE_SIZE_STATIC (4 + T::static_size); 590 }; 591 592 template <> 593 struct Entry<void> 594 { 595 // This does seem like it's ever called. sanitizeAAT::Entry596 bool sanitize (hb_sanitize_context_t *c) const 597 { 598 TRACE_SANITIZE (this); 599 return_trace (c->check_struct (this)); 600 } 601 602 public: 603 HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */ 604 HBUINT16 flags; /* Table specific. */ 605 public: 606 DEFINE_SIZE_STATIC (4); 607 }; 608 609 enum Class 610 { 611 CLASS_END_OF_TEXT = 0, 612 CLASS_OUT_OF_BOUNDS = 1, 613 CLASS_DELETED_GLYPH = 2, 614 CLASS_END_OF_LINE = 3, 615 }; 616 617 template <typename Types, typename Extra> 618 struct StateTable 619 { 620 typedef typename Types::HBUINT HBUINT; 621 typedef typename Types::HBUSHORT HBUSHORT; 622 typedef typename Types::ClassTypeNarrow ClassType; 623 624 enum State 625 { 626 STATE_START_OF_TEXT = 0, 627 STATE_START_OF_LINE = 1, 628 }; 629 630 template <typename set_t> collect_glyphsAAT::StateTable631 void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const 632 { 633 (this+classTable).collect_glyphs (glyphs, num_glyphs); 634 } 635 new_stateAAT::StateTable636 int new_state (unsigned int newState) const 637 { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } 638 639 template <typename set_t> get_classAAT::StateTable640 unsigned int get_class (hb_codepoint_t glyph_id, 641 unsigned int num_glyphs, 642 const set_t &glyphs) const 643 { 644 if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; 645 if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS; 646 return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS); 647 } 648 get_entriesAAT::StateTable649 const Entry<Extra> *get_entries () const 650 { return (this+entryTable).arrayZ; } 651 get_entryAAT::StateTable652 const Entry<Extra> &get_entry (int state, unsigned int klass) const 653 { 654 if (unlikely (klass >= nClasses)) 655 klass = CLASS_OUT_OF_BOUNDS; 656 657 const HBUSHORT *states = (this+stateArrayTable).arrayZ; 658 const Entry<Extra> *entries = (this+entryTable).arrayZ; 659 660 unsigned int entry = states[state * nClasses + klass]; 661 DEBUG_MSG (APPLY, nullptr, "e%u", entry); 662 663 return entries[entry]; 664 } 665 sanitizeAAT::StateTable666 bool sanitize (hb_sanitize_context_t *c, 667 unsigned int *num_entries_out = nullptr) const 668 { 669 TRACE_SANITIZE (this); 670 if (unlikely (!(c->check_struct (this) && 671 hb_barrier () && 672 nClasses >= 4 /* Ensure pre-defined classes fit. */ && 673 classTable.sanitize (c, this)))) return_trace (false); 674 675 const HBUSHORT *states = (this+stateArrayTable).arrayZ; 676 const Entry<Extra> *entries = (this+entryTable).arrayZ; 677 678 unsigned int num_classes = nClasses; 679 if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size))) 680 return_trace (false); 681 unsigned int row_stride = num_classes * states[0].static_size; 682 683 /* Apple 'kern' table has this peculiarity: 684 * 685 * "Because the stateTableOffset in the state table header is (strictly 686 * speaking) redundant, some 'kern' tables use it to record an initial 687 * state where that should not be StartOfText. To determine if this is 688 * done, calculate what the stateTableOffset should be. If it's different 689 * from the actual stateTableOffset, use it as the initial state." 690 * 691 * We implement this by calling the initial state zero, but allow *negative* 692 * states if the start state indeed was not the first state. Since the code 693 * is shared, this will also apply to 'mort' table. The 'kerx' / 'morx' 694 * tables are not affected since those address states by index, not offset. 695 */ 696 697 int min_state = 0; 698 int max_state = 0; 699 unsigned int num_entries = 0; 700 701 int state_pos = 0; 702 int state_neg = 0; 703 unsigned int entry = 0; 704 while (min_state < state_neg || state_pos <= max_state) 705 { 706 if (min_state < state_neg) 707 { 708 /* Negative states. */ 709 if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) 710 return_trace (false); 711 if (unlikely (!c->check_range (&states[min_state * num_classes], 712 -min_state, 713 row_stride))) 714 return_trace (false); 715 if ((c->max_ops -= state_neg - min_state) <= 0) 716 return_trace (false); 717 { /* Sweep new states. */ 718 const HBUSHORT *stop = &states[min_state * num_classes]; 719 if (unlikely (stop > states)) 720 return_trace (false); 721 for (const HBUSHORT *p = states; stop < p; p--) 722 num_entries = hb_max (num_entries, *(p - 1) + 1u); 723 state_neg = min_state; 724 } 725 } 726 727 if (state_pos <= max_state) 728 { 729 /* Positive states. */ 730 if (unlikely (!c->check_range (states, 731 max_state + 1, 732 row_stride))) 733 return_trace (false); 734 if ((c->max_ops -= max_state - state_pos + 1) <= 0) 735 return_trace (false); 736 { /* Sweep new states. */ 737 if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes))) 738 return_trace (false); 739 const HBUSHORT *stop = &states[(max_state + 1) * num_classes]; 740 if (unlikely (stop < states)) 741 return_trace (false); 742 for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++) 743 num_entries = hb_max (num_entries, *p + 1u); 744 state_pos = max_state + 1; 745 } 746 } 747 748 if (unlikely (!c->check_array (entries, num_entries))) 749 return_trace (false); 750 if ((c->max_ops -= num_entries - entry) <= 0) 751 return_trace (false); 752 { /* Sweep new entries. */ 753 const Entry<Extra> *stop = &entries[num_entries]; 754 for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) 755 { 756 int newState = new_state (p->newState); 757 min_state = hb_min (min_state, newState); 758 max_state = hb_max (max_state, newState); 759 } 760 entry = num_entries; 761 } 762 } 763 764 if (num_entries_out) 765 *num_entries_out = num_entries; 766 767 return_trace (true); 768 } 769 770 protected: 771 HBUINT nClasses; /* Number of classes, which is the number of indices 772 * in a single line in the state array. */ 773 NNOffsetTo<ClassType, HBUINT> 774 classTable; /* Offset to the class table. */ 775 NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT> 776 stateArrayTable;/* Offset to the state array. */ 777 NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT> 778 entryTable; /* Offset to the entry array. */ 779 780 public: 781 DEFINE_SIZE_STATIC (4 * sizeof (HBUINT)); 782 }; 783 784 template <typename HBUCHAR> 785 struct ClassTable 786 { get_classAAT::ClassTable787 unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const 788 { 789 unsigned int i = glyph_id - firstGlyph; 790 return i >= classArray.len ? outOfRange : classArray.arrayZ[i]; 791 } get_classAAT::ClassTable792 unsigned int get_class (hb_codepoint_t glyph_id, 793 unsigned int num_glyphs HB_UNUSED, 794 unsigned int outOfRange) const 795 { 796 return get_class (glyph_id, outOfRange); 797 } 798 799 template <typename set_t> collect_glyphsAAT::ClassTable800 void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const 801 { 802 for (unsigned i = 0; i < classArray.len; i++) 803 if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS) 804 glyphs.add (firstGlyph + i); 805 } 806 sanitizeAAT::ClassTable807 bool sanitize (hb_sanitize_context_t *c) const 808 { 809 TRACE_SANITIZE (this); 810 return_trace (c->check_struct (this) && classArray.sanitize (c)); 811 } 812 protected: 813 HBGlyphID16 firstGlyph; /* First glyph index included in the trimmed array. */ 814 Array16Of<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus 815 * firstGlyph). */ 816 public: 817 DEFINE_SIZE_ARRAY (4, classArray); 818 }; 819 820 struct SubtableGlyphCoverage 821 { sanitizeAAT::SubtableGlyphCoverage822 bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const 823 { 824 TRACE_SANITIZE (this); 825 826 if (unlikely (!c->check_array (&subtableOffsets, subtable_count))) 827 return_trace (false); 828 829 unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT; 830 for (unsigned i = 0; i < subtable_count; i++) 831 { 832 uint32_t offset = (uint32_t) subtableOffsets[i]; 833 if (offset == 0 || offset == 0xFFFFFFFF) 834 continue; 835 if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes))) 836 return_trace (false); 837 } 838 839 return_trace (true); 840 } 841 protected: 842 UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets; 843 /* Array of offsets from the beginning of the 844 * subtable glyph coverage table to the glyph 845 * coverage bitfield for a given subtable; there 846 * is one offset for each subtable in the chain */ 847 /* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */ 848 public: 849 DEFINE_SIZE_ARRAY (0, subtableOffsets); 850 }; 851 852 struct ObsoleteTypes 853 { 854 static constexpr bool extended = false; 855 typedef HBUINT16 HBUINT; 856 typedef HBUINT8 HBUSHORT; 857 typedef ClassTable<HBUINT8> ClassTypeNarrow; 858 typedef ClassTable<HBUINT16> ClassTypeWide; 859 860 template <typename T> offsetToIndexAAT::ObsoleteTypes861 static unsigned int offsetToIndex (unsigned int offset, 862 const void *base, 863 const T *array) 864 { 865 /* https://github.com/harfbuzz/harfbuzz/issues/3483 */ 866 /* If offset is less than base, return an offset that would 867 * result in an address half a 32bit address-space away, 868 * to make sure sanitize fails even on 32bit builds. */ 869 if (unlikely (offset < unsigned ((const char *) array - (const char *) base))) 870 return INT_MAX / T::static_size; 871 872 /* https://github.com/harfbuzz/harfbuzz/issues/2816 */ 873 return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size; 874 } 875 template <typename T> byteOffsetToIndexAAT::ObsoleteTypes876 static unsigned int byteOffsetToIndex (unsigned int offset, 877 const void *base, 878 const T *array) 879 { 880 return offsetToIndex (offset, base, array); 881 } 882 template <typename T> wordOffsetToIndexAAT::ObsoleteTypes883 static unsigned int wordOffsetToIndex (unsigned int offset, 884 const void *base, 885 const T *array) 886 { 887 return offsetToIndex (2 * offset, base, array); 888 } 889 }; 890 struct ExtendedTypes 891 { 892 static constexpr bool extended = true; 893 typedef HBUINT32 HBUINT; 894 typedef HBUINT16 HBUSHORT; 895 typedef Lookup<HBUINT16> ClassTypeNarrow; 896 typedef Lookup<HBUINT16> ClassTypeWide; 897 898 template <typename T> offsetToIndexAAT::ExtendedTypes899 static unsigned int offsetToIndex (unsigned int offset, 900 const void *base HB_UNUSED, 901 const T *array HB_UNUSED) 902 { 903 return offset; 904 } 905 template <typename T> byteOffsetToIndexAAT::ExtendedTypes906 static unsigned int byteOffsetToIndex (unsigned int offset, 907 const void *base HB_UNUSED, 908 const T *array HB_UNUSED) 909 { 910 return offset / 2; 911 } 912 template <typename T> wordOffsetToIndexAAT::ExtendedTypes913 static unsigned int wordOffsetToIndex (unsigned int offset, 914 const void *base HB_UNUSED, 915 const T *array HB_UNUSED) 916 { 917 return offset; 918 } 919 }; 920 921 template <typename Types, typename EntryData> 922 struct StateTableDriver 923 { 924 using StateTableT = StateTable<Types, EntryData>; 925 using EntryT = Entry<EntryData>; 926 StateTableDriverAAT::StateTableDriver927 StateTableDriver (const StateTableT &machine_, 928 hb_face_t *face_) : 929 machine (machine_), 930 num_glyphs (face_->get_num_glyphs ()) {} 931 932 template <typename context_t> is_idempotent_on_all_out_of_boundsAAT::StateTableDriver933 bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac) 934 { 935 const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS); 936 return !c->is_actionable (ac->buffer, this, entry) && 937 machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT; 938 } 939 940 template <typename context_t> driveAAT::StateTableDriver941 void drive (context_t *c, hb_aat_apply_context_t *ac) 942 { 943 hb_buffer_t *buffer = ac->buffer; 944 945 if (!c->in_place) 946 buffer->clear_output (); 947 948 int state = StateTableT::STATE_START_OF_TEXT; 949 // If there's only one range, we already checked the flag. 950 auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr; 951 for (buffer->idx = 0; buffer->successful;) 952 { 953 /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ 954 if (last_range) 955 { 956 auto *range = last_range; 957 if (buffer->idx < buffer->len) 958 { 959 unsigned cluster = buffer->cur().cluster; 960 while (cluster < range->cluster_first) 961 range--; 962 while (cluster > range->cluster_last) 963 range++; 964 965 966 last_range = range; 967 } 968 if (!(range->flags & ac->subtable_flags)) 969 { 970 if (buffer->idx == buffer->len || unlikely (!buffer->successful)) 971 break; 972 973 state = StateTableT::STATE_START_OF_TEXT; 974 (void) buffer->next_glyph (); 975 continue; 976 } 977 } 978 979 unsigned int klass = likely (buffer->idx < buffer->len) ? 980 machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) : 981 (unsigned) CLASS_END_OF_TEXT; 982 DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); 983 const EntryT &entry = machine.get_entry (state, klass); 984 const int next_state = machine.new_state (entry.newState); 985 986 /* Conditions under which it's guaranteed safe-to-break before current glyph: 987 * 988 * 1. There was no action in this transition; and 989 * 990 * 2. If we break before current glyph, the results will be the same. That 991 * is guaranteed if: 992 * 993 * 2a. We were already in start-of-text state; or 994 * 995 * 2b. We are epsilon-transitioning to start-of-text state; or 996 * 997 * 2c. Starting from start-of-text state seeing current glyph: 998 * 999 * 2c'. There won't be any actions; and 1000 * 1001 * 2c". We would end up in the same state that we were going to end up 1002 * in now, including whether epsilon-transitioning. 1003 * 1004 * and 1005 * 1006 * 3. If we break before current glyph, there won't be any end-of-text action 1007 * after previous glyph. 1008 * 1009 * This triples the transitions we need to look up, but is worth returning 1010 * granular unsafe-to-break results. See eg.: 1011 * 1012 * https://github.com/harfbuzz/harfbuzz/issues/2860 1013 */ 1014 1015 const auto is_safe_to_break_extra = [&]() 1016 { 1017 /* 2c. */ 1018 const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass); 1019 1020 /* 2c'. */ 1021 if (c->is_actionable (buffer, this, wouldbe_entry)) 1022 return false; 1023 1024 /* 2c". */ 1025 return next_state == machine.new_state(wouldbe_entry.newState) 1026 && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance); 1027 }; 1028 1029 const auto is_safe_to_break = [&]() 1030 { 1031 /* 1. */ 1032 if (c->is_actionable (buffer, this, entry)) 1033 return false; 1034 1035 /* 2. */ 1036 // This one is meh, I know... 1037 const auto ok = 1038 state == StateTableT::STATE_START_OF_TEXT 1039 || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT) 1040 || is_safe_to_break_extra(); 1041 if (!ok) 1042 return false; 1043 1044 /* 3. */ 1045 return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT)); 1046 }; 1047 1048 if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len) 1049 buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); 1050 1051 c->transition (buffer, this, entry); 1052 1053 state = next_state; 1054 DEBUG_MSG (APPLY, nullptr, "s%d", state); 1055 1056 if (buffer->idx == buffer->len || unlikely (!buffer->successful)) 1057 break; 1058 1059 if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) 1060 (void) buffer->next_glyph (); 1061 } 1062 1063 if (!c->in_place) 1064 buffer->sync (); 1065 } 1066 1067 public: 1068 const StateTableT &machine; 1069 unsigned int num_glyphs; 1070 }; 1071 1072 1073 } /* namespace AAT */ 1074 1075 1076 #endif /* HB_AAT_LAYOUT_COMMON_HH */ 1077