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: 51 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 57 bool sanitize (hb_sanitize_context_t *c) const 58 { 59 TRACE_SANITIZE (this); 60 return_trace (arrayZ.sanitize (c, c->get_num_glyphs ())); 61 } 62 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 enum { TerminationWordCount = 2 }; 81 82 int cmp (hb_codepoint_t g) const 83 { return g < first ? -1 : g <= last ? 0 : +1 ; } 84 85 bool sanitize (hb_sanitize_context_t *c) const 86 { 87 TRACE_SANITIZE (this); 88 return_trace (c->check_struct (this) && value.sanitize (c)); 89 } 90 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 GlyphID last; /* Last GlyphID in this segment */ 97 GlyphID 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: 109 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 115 bool sanitize (hb_sanitize_context_t *c) const 116 { 117 TRACE_SANITIZE (this); 118 return_trace (segments.sanitize (c)); 119 } 120 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 enum { TerminationWordCount = 2 }; 140 141 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 146 int cmp (hb_codepoint_t g) const 147 { return g < first ? -1 : g <= last ? 0 : +1; } 148 149 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 T2> 157 bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const 158 { 159 TRACE_SANITIZE (this); 160 return_trace (c->check_struct (this) && 161 first <= last && 162 valuesZ.sanitize (c, base, last - first + 1, user_data)); 163 } 164 165 GlyphID last; /* Last GlyphID in this segment */ 166 GlyphID first; /* First GlyphID in this segment */ 167 OffsetTo<UnsizedArrayOf<T>, HBUINT16, false> 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: 180 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 186 bool sanitize (hb_sanitize_context_t *c) const 187 { 188 TRACE_SANITIZE (this); 189 return_trace (segments.sanitize (c, this)); 190 } 191 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 enum { TerminationWordCount = 1 }; 211 212 int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } 213 214 bool sanitize (hb_sanitize_context_t *c) const 215 { 216 TRACE_SANITIZE (this); 217 return_trace (c->check_struct (this) && value.sanitize (c)); 218 } 219 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 GlyphID 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: 237 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 243 bool sanitize (hb_sanitize_context_t *c) const 244 { 245 TRACE_SANITIZE (this); 246 return_trace (entries.sanitize (c)); 247 } 248 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: 268 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 274 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 } 279 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 GlyphID 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: 303 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 318 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 GlyphID 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 { 342 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 354 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 365 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 373 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 } 387 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); /* No need to support format10 apparently */ 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 <> 422 /*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > () 423 { return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); } 424 template <> 425 /*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > () 426 { return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); } 427 template <> 428 /*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > () 429 { return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); } 430 namespace AAT { 431 432 enum { DELETED_GLYPH = 0xFFFF }; 433 434 /* 435 * (Extended) State Table 436 */ 437 438 template <typename T> 439 struct Entry 440 { 441 bool sanitize (hb_sanitize_context_t *c, unsigned int count) const 442 { 443 TRACE_SANITIZE (this); 444 /* Note, we don't recurse-sanitize data because we don't access it. 445 * That said, in our DEFINE_SIZE_STATIC we access T::static_size, 446 * which ensures that data has a simple sanitize(). To be determined 447 * if I need to remove that as well. 448 * 449 * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC 450 * assertion wouldn't be checked, hence the line below. */ 451 static_assert (T::static_size, ""); 452 453 return_trace (c->check_struct (this)); 454 } 455 456 public: 457 HBUINT16 newState; /* Byte offset from beginning of state table 458 * to the new state. Really?!?! Or just state 459 * number? The latter in morx for sure. */ 460 HBUINT16 flags; /* Table specific. */ 461 T data; /* Optional offsets to per-glyph tables. */ 462 public: 463 DEFINE_SIZE_STATIC (4 + T::static_size); 464 }; 465 466 template <> 467 struct Entry<void> 468 { 469 bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const 470 { 471 TRACE_SANITIZE (this); 472 return_trace (c->check_struct (this)); 473 } 474 475 public: 476 HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */ 477 HBUINT16 flags; /* Table specific. */ 478 public: 479 DEFINE_SIZE_STATIC (4); 480 }; 481 482 template <typename Types, typename Extra> 483 struct StateTable 484 { 485 typedef typename Types::HBUINT HBUINT; 486 typedef typename Types::HBUSHORT HBUSHORT; 487 typedef typename Types::ClassTypeNarrow ClassType; 488 489 enum State 490 { 491 STATE_START_OF_TEXT = 0, 492 STATE_START_OF_LINE = 1, 493 }; 494 enum Class 495 { 496 CLASS_END_OF_TEXT = 0, 497 CLASS_OUT_OF_BOUNDS = 1, 498 CLASS_DELETED_GLYPH = 2, 499 CLASS_END_OF_LINE = 3, 500 }; 501 502 int new_state (unsigned int newState) const 503 { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } 504 505 unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 506 { 507 if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; 508 return (this+classTable).get_class (glyph_id, num_glyphs, 1); 509 } 510 511 const Entry<Extra> *get_entries () const 512 { return (this+entryTable).arrayZ; } 513 514 const Entry<Extra> *get_entryZ (int state, unsigned int klass) const 515 { 516 if (unlikely (klass >= nClasses)) return nullptr; 517 518 const HBUSHORT *states = (this+stateArrayTable).arrayZ; 519 const Entry<Extra> *entries = (this+entryTable).arrayZ; 520 521 unsigned int entry = states[state * nClasses + klass]; 522 DEBUG_MSG (APPLY, nullptr, "e%u", entry); 523 524 return &entries[entry]; 525 } 526 527 bool sanitize (hb_sanitize_context_t *c, 528 unsigned int *num_entries_out = nullptr) const 529 { 530 TRACE_SANITIZE (this); 531 if (unlikely (!(c->check_struct (this) && 532 classTable.sanitize (c, this)))) return_trace (false); 533 534 const HBUSHORT *states = (this+stateArrayTable).arrayZ; 535 const Entry<Extra> *entries = (this+entryTable).arrayZ; 536 537 unsigned int num_classes = nClasses; 538 if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size))) 539 return_trace (false); 540 unsigned int row_stride = num_classes * states[0].static_size; 541 542 /* Apple 'kern' table has this peculiarity: 543 * 544 * "Because the stateTableOffset in the state table header is (strictly 545 * speaking) redundant, some 'kern' tables use it to record an initial 546 * state where that should not be StartOfText. To determine if this is 547 * done, calculate what the stateTableOffset should be. If it's different 548 * from the actual stateTableOffset, use it as the initial state." 549 * 550 * We implement this by calling the initial state zero, but allow *negative* 551 * states if the start state indeed was not the first state. Since the code 552 * is shared, this will also apply to 'mort' table. The 'kerx' / 'morx' 553 * tables are not affected since those address states by index, not offset. 554 */ 555 556 int min_state = 0; 557 int max_state = 0; 558 unsigned int num_entries = 0; 559 560 int state_pos = 0; 561 int state_neg = 0; 562 unsigned int entry = 0; 563 while (min_state < state_neg || state_pos <= max_state) 564 { 565 if (min_state < state_neg) 566 { 567 /* Negative states. */ 568 if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) 569 return_trace (false); 570 if (unlikely (!c->check_range (&states[min_state * num_classes], 571 -min_state, 572 row_stride))) 573 return_trace (false); 574 if ((c->max_ops -= state_neg - min_state) < 0) 575 return_trace (false); 576 { /* Sweep new states. */ 577 const HBUSHORT *stop = &states[min_state * num_classes]; 578 if (unlikely (stop > states)) 579 return_trace (false); 580 for (const HBUSHORT *p = states; stop < p; p--) 581 num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1); 582 state_neg = min_state; 583 } 584 } 585 586 if (state_pos <= max_state) 587 { 588 /* Positive states. */ 589 if (unlikely (!c->check_range (states, 590 max_state + 1, 591 row_stride))) 592 return_trace (false); 593 if ((c->max_ops -= max_state - state_pos + 1) < 0) 594 return_trace (false); 595 { /* Sweep new states. */ 596 if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes))) 597 return_trace (false); 598 const HBUSHORT *stop = &states[(max_state + 1) * num_classes]; 599 if (unlikely (stop < states)) 600 return_trace (false); 601 for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++) 602 num_entries = MAX<unsigned int> (num_entries, *p + 1); 603 state_pos = max_state + 1; 604 } 605 } 606 607 if (unlikely (!c->check_array (entries, num_entries))) 608 return_trace (false); 609 if ((c->max_ops -= num_entries - entry) < 0) 610 return_trace (false); 611 { /* Sweep new entries. */ 612 const Entry<Extra> *stop = &entries[num_entries]; 613 for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) 614 { 615 int newState = new_state (p->newState); 616 min_state = MIN (min_state, newState); 617 max_state = MAX (max_state, newState); 618 } 619 entry = num_entries; 620 } 621 } 622 623 if (num_entries_out) 624 *num_entries_out = num_entries; 625 626 return_trace (true); 627 } 628 629 protected: 630 HBUINT nClasses; /* Number of classes, which is the number of indices 631 * in a single line in the state array. */ 632 OffsetTo<ClassType, HBUINT, false> 633 classTable; /* Offset to the class table. */ 634 OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false> 635 stateArrayTable;/* Offset to the state array. */ 636 OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false> 637 entryTable; /* Offset to the entry array. */ 638 639 public: 640 DEFINE_SIZE_STATIC (4 * sizeof (HBUINT)); 641 }; 642 643 template <typename HBUCHAR> 644 struct ClassTable 645 { 646 unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const 647 { 648 unsigned int i = glyph_id - firstGlyph; 649 return i >= classArray.len ? outOfRange : classArray.arrayZ[i]; 650 } 651 unsigned int get_class (hb_codepoint_t glyph_id, 652 unsigned int num_glyphs HB_UNUSED, 653 unsigned int outOfRange) const 654 { 655 return get_class (glyph_id, outOfRange); 656 } 657 bool sanitize (hb_sanitize_context_t *c) const 658 { 659 TRACE_SANITIZE (this); 660 return_trace (c->check_struct (this) && classArray.sanitize (c)); 661 } 662 protected: 663 GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ 664 ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus 665 * firstGlyph). */ 666 public: 667 DEFINE_SIZE_ARRAY (4, classArray); 668 }; 669 670 struct ObsoleteTypes 671 { 672 enum { extended = false }; 673 typedef HBUINT16 HBUINT; 674 typedef HBUINT8 HBUSHORT; 675 typedef ClassTable<HBUINT8> ClassTypeNarrow; 676 typedef ClassTable<HBUINT16> ClassTypeWide; 677 678 template <typename T> 679 static unsigned int offsetToIndex (unsigned int offset, 680 const void *base, 681 const T *array) 682 { 683 return (offset - ((const char *) array - (const char *) base)) / sizeof (T); 684 } 685 template <typename T> 686 static unsigned int byteOffsetToIndex (unsigned int offset, 687 const void *base, 688 const T *array) 689 { 690 return offsetToIndex (offset, base, array); 691 } 692 template <typename T> 693 static unsigned int wordOffsetToIndex (unsigned int offset, 694 const void *base, 695 const T *array) 696 { 697 return offsetToIndex (2 * offset, base, array); 698 } 699 }; 700 struct ExtendedTypes 701 { 702 enum { extended = true }; 703 typedef HBUINT32 HBUINT; 704 typedef HBUINT16 HBUSHORT; 705 typedef Lookup<HBUINT16> ClassTypeNarrow; 706 typedef Lookup<HBUINT16> ClassTypeWide; 707 708 template <typename T> 709 static unsigned int offsetToIndex (unsigned int offset, 710 const void *base, 711 const T *array) 712 { 713 return offset; 714 } 715 template <typename T> 716 static unsigned int byteOffsetToIndex (unsigned int offset, 717 const void *base, 718 const T *array) 719 { 720 return offset / 2; 721 } 722 template <typename T> 723 static unsigned int wordOffsetToIndex (unsigned int offset, 724 const void *base, 725 const T *array) 726 { 727 return offset; 728 } 729 }; 730 731 template <typename Types, typename EntryData> 732 struct StateTableDriver 733 { 734 StateTableDriver (const StateTable<Types, EntryData> &machine_, 735 hb_buffer_t *buffer_, 736 hb_face_t *face_) : 737 machine (machine_), 738 buffer (buffer_), 739 num_glyphs (face_->get_num_glyphs ()) {} 740 741 template <typename context_t> 742 void drive (context_t *c) 743 { 744 if (!c->in_place) 745 buffer->clear_output (); 746 747 int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT; 748 bool last_was_dont_advance = false; 749 for (buffer->idx = 0; buffer->successful;) 750 { 751 unsigned int klass = buffer->idx < buffer->len ? 752 machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : 753 (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT; 754 DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); 755 const Entry<EntryData> *entry = machine.get_entryZ (state, klass); 756 if (unlikely (!entry)) 757 break; 758 759 /* Unsafe-to-break before this if not in state 0, as things might 760 * go differently if we start from state 0 here. 761 * 762 * Ugh. The indexing here is ugly... */ 763 if (state && buffer->backtrack_len () && buffer->idx < buffer->len) 764 { 765 /* If there's no action and we're just epsilon-transitioning to state 0, 766 * safe to break. */ 767 if (c->is_actionable (this, entry) || 768 !(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT && 769 entry->flags == context_t::DontAdvance)) 770 buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); 771 } 772 773 /* Unsafe-to-break if end-of-text would kick in here. */ 774 if (buffer->idx + 2 <= buffer->len) 775 { 776 const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0); 777 if (c->is_actionable (this, end_entry)) 778 buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); 779 } 780 781 if (unlikely (!c->transition (this, entry))) 782 break; 783 784 last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0; 785 786 state = machine.new_state (entry->newState); 787 DEBUG_MSG (APPLY, nullptr, "s%d", state); 788 789 if (buffer->idx == buffer->len) 790 break; 791 792 if (!last_was_dont_advance) 793 buffer->next_glyph (); 794 } 795 796 if (!c->in_place) 797 { 798 for (; buffer->successful && buffer->idx < buffer->len;) 799 buffer->next_glyph (); 800 buffer->swap_buffers (); 801 } 802 } 803 804 public: 805 const StateTable<Types, EntryData> &machine; 806 hb_buffer_t *buffer; 807 unsigned int num_glyphs; 808 }; 809 810 811 struct ankr; 812 813 struct hb_aat_apply_context_t : 814 hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> 815 { 816 const char *get_name () { return "APPLY"; } 817 template <typename T> 818 return_t dispatch (const T &obj) { return obj.apply (this); } 819 static return_t default_return_value () { return false; } 820 bool stop_sublookup_iteration (return_t r) const { return r; } 821 822 const hb_ot_shape_plan_t *plan; 823 hb_font_t *font; 824 hb_face_t *face; 825 hb_buffer_t *buffer; 826 hb_sanitize_context_t sanitizer; 827 const ankr *ankr_table; 828 const char *ankr_end; 829 830 /* Unused. For debug tracing only. */ 831 unsigned int lookup_index; 832 unsigned int debug_depth; 833 834 HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, 835 hb_font_t *font_, 836 hb_buffer_t *buffer_, 837 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t))); 838 839 HB_INTERNAL ~hb_aat_apply_context_t (); 840 841 HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_, const char *ankr_end_); 842 843 void set_lookup_index (unsigned int i) { lookup_index = i; } 844 }; 845 846 847 } /* namespace AAT */ 848 849 850 #endif /* HB_AAT_LAYOUT_COMMON_HH */ 851