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 NNOffsetTo<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<Types, Entry<Extra>>::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) + 1); 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 + 1); 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 ArrayOf<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 return (offset - ((const char *) array - (const char *) base)) / T::static_size; 682 } 683 template <typename T> byteOffsetToIndexAAT::ObsoleteTypes684 static unsigned int byteOffsetToIndex (unsigned int offset, 685 const void *base, 686 const T *array) 687 { 688 return offsetToIndex (offset, base, array); 689 } 690 template <typename T> wordOffsetToIndexAAT::ObsoleteTypes691 static unsigned int wordOffsetToIndex (unsigned int offset, 692 const void *base, 693 const T *array) 694 { 695 return offsetToIndex (2 * offset, base, array); 696 } 697 }; 698 struct ExtendedTypes 699 { 700 static constexpr bool extended = true; 701 typedef HBUINT32 HBUINT; 702 typedef HBUINT16 HBUSHORT; 703 typedef Lookup<HBUINT16> ClassTypeNarrow; 704 typedef Lookup<HBUINT16> ClassTypeWide; 705 706 template <typename T> offsetToIndexAAT::ExtendedTypes707 static unsigned int offsetToIndex (unsigned int offset, 708 const void *base HB_UNUSED, 709 const T *array HB_UNUSED) 710 { 711 return offset; 712 } 713 template <typename T> byteOffsetToIndexAAT::ExtendedTypes714 static unsigned int byteOffsetToIndex (unsigned int offset, 715 const void *base HB_UNUSED, 716 const T *array HB_UNUSED) 717 { 718 return offset / 2; 719 } 720 template <typename T> wordOffsetToIndexAAT::ExtendedTypes721 static unsigned int wordOffsetToIndex (unsigned int offset, 722 const void *base HB_UNUSED, 723 const T *array HB_UNUSED) 724 { 725 return offset; 726 } 727 }; 728 729 template <typename Types, typename EntryData> 730 struct StateTableDriver 731 { StateTableDriverAAT::StateTableDriver732 StateTableDriver (const StateTable<Types, EntryData> &machine_, 733 hb_buffer_t *buffer_, 734 hb_face_t *face_) : 735 machine (machine_), 736 buffer (buffer_), 737 num_glyphs (face_->get_num_glyphs ()) {} 738 739 template <typename context_t> driveAAT::StateTableDriver740 void drive (context_t *c) 741 { 742 if (!c->in_place) 743 buffer->clear_output (); 744 745 int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT; 746 for (buffer->idx = 0; buffer->successful;) 747 { 748 unsigned int klass = buffer->idx < buffer->len ? 749 machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : 750 (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT; 751 DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); 752 const Entry<EntryData> &entry = machine.get_entry (state, klass); 753 754 /* Unsafe-to-break before this if not in state 0, as things might 755 * go differently if we start from state 0 here. 756 * 757 * Ugh. The indexing here is ugly... */ 758 if (state && buffer->backtrack_len () && buffer->idx < buffer->len) 759 { 760 /* If there's no action and we're just epsilon-transitioning to state 0, 761 * safe to break. */ 762 if (c->is_actionable (this, entry) || 763 !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT && 764 entry.flags == context_t::DontAdvance)) 765 buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); 766 } 767 768 /* Unsafe-to-break if end-of-text would kick in here. */ 769 if (buffer->idx + 2 <= buffer->len) 770 { 771 const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT); 772 if (c->is_actionable (this, end_entry)) 773 buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); 774 } 775 776 c->transition (this, entry); 777 778 state = machine.new_state (entry.newState); 779 DEBUG_MSG (APPLY, nullptr, "s%d", state); 780 781 if (buffer->idx == buffer->len) 782 break; 783 784 if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) 785 buffer->next_glyph (); 786 } 787 788 if (!c->in_place) 789 { 790 for (; buffer->successful && buffer->idx < buffer->len;) 791 buffer->next_glyph (); 792 buffer->swap_buffers (); 793 } 794 } 795 796 public: 797 const StateTable<Types, EntryData> &machine; 798 hb_buffer_t *buffer; 799 unsigned int num_glyphs; 800 }; 801 802 803 struct ankr; 804 805 struct hb_aat_apply_context_t : 806 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> 807 { get_nameAAT::hb_aat_apply_context_t808 const char *get_name () { return "APPLY"; } 809 template <typename T> dispatchAAT::hb_aat_apply_context_t810 return_t dispatch (const T &obj) { return obj.apply (this); } default_return_valueAAT::hb_aat_apply_context_t811 static return_t default_return_value () { return false; } stop_sublookup_iterationAAT::hb_aat_apply_context_t812 bool stop_sublookup_iteration (return_t r) const { return r; } 813 814 const hb_ot_shape_plan_t *plan; 815 hb_font_t *font; 816 hb_face_t *face; 817 hb_buffer_t *buffer; 818 hb_sanitize_context_t sanitizer; 819 const ankr *ankr_table; 820 821 /* Unused. For debug tracing only. */ 822 unsigned int lookup_index; 823 unsigned int debug_depth; 824 825 HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, 826 hb_font_t *font_, 827 hb_buffer_t *buffer_, 828 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t))); 829 830 HB_INTERNAL ~hb_aat_apply_context_t (); 831 832 HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); 833 set_lookup_indexAAT::hb_aat_apply_context_t834 void set_lookup_index (unsigned int i) { lookup_index = i; } 835 }; 836 837 838 } /* namespace AAT */ 839 840 841 #endif /* HB_AAT_LAYOUT_COMMON_HH */ 842