GDEF.hh (31999B)
1 /* 2 * Copyright © 2007,2008,2009 Red Hat, Inc. 3 * Copyright © 2010,2011,2012 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Red Hat Author(s): Behdad Esfahbod 26 * Google Author(s): Behdad Esfahbod 27 */ 28 29 #ifndef OT_LAYOUT_GDEF_GDEF_HH 30 #define OT_LAYOUT_GDEF_GDEF_HH 31 32 #include "../../../hb-ot-var-common.hh" 33 34 #include "../../../hb-font.hh" 35 #include "../../../hb-cache.hh" 36 37 38 namespace OT { 39 40 41 /* 42 * Attachment List Table 43 */ 44 45 /* Array of contour point indices--in increasing numerical order */ 46 struct AttachPoint : Array16Of<HBUINT16> 47 { 48 bool subset (hb_subset_context_t *c) const 49 { 50 TRACE_SUBSET (this); 51 auto *out = c->serializer->start_embed (*this); 52 return_trace (out->serialize (c->serializer, + iter ())); 53 } 54 }; 55 56 struct AttachList 57 { 58 unsigned int get_attach_points (hb_codepoint_t glyph_id, 59 unsigned int start_offset, 60 unsigned int *point_count /* IN/OUT */, 61 unsigned int *point_array /* OUT */) const 62 { 63 unsigned int index = (this+coverage).get_coverage (glyph_id); 64 if (index == NOT_COVERED) 65 { 66 if (point_count) 67 *point_count = 0; 68 return 0; 69 } 70 71 const AttachPoint &points = this+attachPoint[index]; 72 73 if (point_count) 74 { 75 + points.as_array ().sub_array (start_offset, point_count) 76 | hb_sink (hb_array (point_array, *point_count)) 77 ; 78 } 79 80 return points.len; 81 } 82 83 bool subset (hb_subset_context_t *c) const 84 { 85 TRACE_SUBSET (this); 86 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 87 const hb_map_t &glyph_map = *c->plan->glyph_map; 88 89 auto *out = c->serializer->start_embed (*this); 90 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 91 92 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 93 + hb_zip (this+coverage, attachPoint) 94 | hb_filter (glyphset, hb_first) 95 | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second) 96 | hb_map (hb_first) 97 | hb_map (glyph_map) 98 | hb_sink (new_coverage) 99 ; 100 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); 101 return_trace (bool (new_coverage)); 102 } 103 104 bool sanitize (hb_sanitize_context_t *c) const 105 { 106 TRACE_SANITIZE (this); 107 return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); 108 } 109 110 protected: 111 Offset16To<Coverage> 112 coverage; /* Offset to Coverage table -- from 113 * beginning of AttachList table */ 114 Array16OfOffset16To<AttachPoint> 115 attachPoint; /* Array of AttachPoint tables 116 * in Coverage Index order */ 117 public: 118 DEFINE_SIZE_ARRAY (4, attachPoint); 119 }; 120 121 /* 122 * Ligature Caret Table 123 */ 124 125 struct CaretValueFormat1 126 { 127 friend struct CaretValue; 128 bool subset (hb_subset_context_t *c) const 129 { 130 TRACE_SUBSET (this); 131 auto *out = c->serializer->embed (this); 132 if (unlikely (!out)) return_trace (false); 133 return_trace (true); 134 } 135 136 private: 137 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const 138 { 139 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); 140 } 141 142 bool sanitize (hb_sanitize_context_t *c) const 143 { 144 TRACE_SANITIZE (this); 145 return_trace (c->check_struct (this)); 146 } 147 148 protected: 149 HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ 150 FWORD coordinate; /* X or Y value, in design units */ 151 public: 152 DEFINE_SIZE_STATIC (4); 153 }; 154 155 struct CaretValueFormat2 156 { 157 friend struct CaretValue; 158 bool subset (hb_subset_context_t *c) const 159 { 160 TRACE_SUBSET (this); 161 auto *out = c->serializer->embed (this); 162 if (unlikely (!out)) return_trace (false); 163 return_trace (true); 164 } 165 166 private: 167 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const 168 { 169 hb_position_t x, y; 170 font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); 171 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; 172 } 173 174 bool sanitize (hb_sanitize_context_t *c) const 175 { 176 TRACE_SANITIZE (this); 177 return_trace (c->check_struct (this)); 178 } 179 180 protected: 181 HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ 182 HBUINT16 caretValuePoint; /* Contour point index on glyph */ 183 public: 184 DEFINE_SIZE_STATIC (4); 185 }; 186 187 struct CaretValueFormat3 188 { 189 friend struct CaretValue; 190 191 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, 192 const ItemVariationStore &var_store) const 193 { 194 return HB_DIRECTION_IS_HORIZONTAL (direction) ? 195 font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : 196 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); 197 } 198 199 bool subset (hb_subset_context_t *c) const 200 { 201 TRACE_SUBSET (this); 202 auto *out = c->serializer->start_embed (*this); 203 if (!c->serializer->embed (caretValueFormat)) return_trace (false); 204 if (!c->serializer->embed (coordinate)) return_trace (false); 205 206 unsigned varidx = (this+deviceTable).get_variation_index (); 207 hb_pair_t<unsigned, int> *new_varidx_delta; 208 if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) { 209 uint32_t new_varidx = hb_first (*new_varidx_delta); 210 int delta = hb_second (*new_varidx_delta); 211 if (delta != 0) 212 { 213 if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 214 return_trace (false); 215 } 216 217 if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX) 218 return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); 219 } 220 221 if (!c->serializer->embed (deviceTable)) 222 return_trace (false); 223 224 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), 225 hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map)); 226 } 227 228 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 229 { (this+deviceTable).collect_variation_indices (c); } 230 231 bool sanitize (hb_sanitize_context_t *c) const 232 { 233 TRACE_SANITIZE (this); 234 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); 235 } 236 237 protected: 238 HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ 239 FWORD coordinate; /* X or Y value, in design units */ 240 Offset16To<Device> 241 deviceTable; /* Offset to Device table for X or Y 242 * value--from beginning of CaretValue 243 * table */ 244 public: 245 DEFINE_SIZE_STATIC (6); 246 }; 247 248 struct CaretValue 249 { 250 hb_position_t get_caret_value (hb_font_t *font, 251 hb_direction_t direction, 252 hb_codepoint_t glyph_id, 253 const ItemVariationStore &var_store) const 254 { 255 switch (u.format.v) { 256 case 1: return u.format1.get_caret_value (font, direction); 257 case 2: return u.format2.get_caret_value (font, direction, glyph_id); 258 case 3: return u.format3.get_caret_value (font, direction, var_store); 259 default:return 0; 260 } 261 } 262 263 template <typename context_t, typename ...Ts> 264 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 265 { 266 if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value (); 267 TRACE_DISPATCH (this, u.format.v); 268 switch (u.format.v) { 269 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 270 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); 271 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...)); 272 default:return_trace (c->default_return_value ()); 273 } 274 } 275 276 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 277 { 278 switch (u.format.v) { 279 case 1: 280 case 2: 281 return; 282 case 3: 283 u.format3.collect_variation_indices (c); 284 return; 285 default: return; 286 } 287 } 288 289 bool sanitize (hb_sanitize_context_t *c) const 290 { 291 TRACE_SANITIZE (this); 292 if (!u.format.v.sanitize (c)) return_trace (false); 293 hb_barrier (); 294 switch (u.format.v) { 295 case 1: return_trace (u.format1.sanitize (c)); 296 case 2: return_trace (u.format2.sanitize (c)); 297 case 3: return_trace (u.format3.sanitize (c)); 298 default:return_trace (true); 299 } 300 } 301 302 protected: 303 union { 304 struct { HBUINT16 v; } format; /* Format identifier */ 305 CaretValueFormat1 format1; 306 CaretValueFormat2 format2; 307 CaretValueFormat3 format3; 308 } u; 309 public: 310 DEFINE_SIZE_UNION (2, format.v); 311 }; 312 313 struct LigGlyph 314 { 315 unsigned get_lig_carets (hb_font_t *font, 316 hb_direction_t direction, 317 hb_codepoint_t glyph_id, 318 const ItemVariationStore &var_store, 319 unsigned start_offset, 320 unsigned *caret_count /* IN/OUT */, 321 hb_position_t *caret_array /* OUT */) const 322 { 323 if (caret_count) 324 { 325 + carets.as_array ().sub_array (start_offset, caret_count) 326 | hb_map (hb_add (this)) 327 | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); }) 328 | hb_sink (hb_array (caret_array, *caret_count)) 329 ; 330 } 331 332 return carets.len; 333 } 334 335 bool subset (hb_subset_context_t *c) const 336 { 337 TRACE_SUBSET (this); 338 auto *out = c->serializer->start_embed (*this); 339 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 340 341 + hb_iter (carets) 342 | hb_apply (subset_offset_array (c, out->carets, this)) 343 ; 344 345 return_trace (bool (out->carets)); 346 } 347 348 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 349 { 350 for (const Offset16To<CaretValue>& offset : carets.iter ()) 351 (this+offset).collect_variation_indices (c); 352 } 353 354 bool sanitize (hb_sanitize_context_t *c) const 355 { 356 TRACE_SANITIZE (this); 357 return_trace (carets.sanitize (c, this)); 358 } 359 360 protected: 361 Array16OfOffset16To<CaretValue> 362 carets; /* Offset array of CaretValue tables 363 * --from beginning of LigGlyph table 364 * --in increasing coordinate order */ 365 public: 366 DEFINE_SIZE_ARRAY (2, carets); 367 }; 368 369 struct LigCaretList 370 { 371 unsigned int get_lig_carets (hb_font_t *font, 372 hb_direction_t direction, 373 hb_codepoint_t glyph_id, 374 const ItemVariationStore &var_store, 375 unsigned int start_offset, 376 unsigned int *caret_count /* IN/OUT */, 377 hb_position_t *caret_array /* OUT */) const 378 { 379 unsigned int index = (this+coverage).get_coverage (glyph_id); 380 if (index == NOT_COVERED) 381 { 382 if (caret_count) 383 *caret_count = 0; 384 return 0; 385 } 386 const LigGlyph &lig_glyph = this+ligGlyph[index]; 387 return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); 388 } 389 390 bool subset (hb_subset_context_t *c) const 391 { 392 TRACE_SUBSET (this); 393 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 394 const hb_map_t &glyph_map = *c->plan->glyph_map; 395 396 auto *out = c->serializer->start_embed (*this); 397 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 398 399 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 400 + hb_zip (this+coverage, ligGlyph) 401 | hb_filter (glyphset, hb_first) 402 | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) 403 | hb_map (hb_first) 404 | hb_map (glyph_map) 405 | hb_sink (new_coverage) 406 ; 407 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); 408 return_trace (bool (new_coverage)); 409 } 410 411 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 412 { 413 + hb_zip (this+coverage, ligGlyph) 414 | hb_filter (c->glyph_set, hb_first) 415 | hb_map (hb_second) 416 | hb_map (hb_add (this)) 417 | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) 418 ; 419 } 420 421 bool sanitize (hb_sanitize_context_t *c) const 422 { 423 TRACE_SANITIZE (this); 424 return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); 425 } 426 427 protected: 428 Offset16To<Coverage> 429 coverage; /* Offset to Coverage table--from 430 * beginning of LigCaretList table */ 431 Array16OfOffset16To<LigGlyph> 432 ligGlyph; /* Array of LigGlyph tables 433 * in Coverage Index order */ 434 public: 435 DEFINE_SIZE_ARRAY (4, ligGlyph); 436 }; 437 438 439 struct MarkGlyphSetsFormat1 440 { 441 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 442 { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } 443 444 void collect_used_mark_sets (const hb_set_t& glyph_set, 445 hb_set_t& used_mark_sets /* OUT */) const 446 { 447 unsigned i = 0; 448 for (const auto &offset : coverage) 449 { 450 const auto &cov = this+offset; 451 if (cov.intersects (&glyph_set)) 452 used_mark_sets.add (i); 453 454 i++; 455 } 456 } 457 458 template <typename set_t> 459 void collect_coverage (hb_vector_t<set_t> &sets) const 460 { 461 for (const auto &offset : coverage) 462 { 463 const auto &cov = this+offset; 464 cov.collect_coverage (sets.push ()); 465 } 466 } 467 468 bool subset (hb_subset_context_t *c) const 469 { 470 TRACE_SUBSET (this); 471 auto *out = c->serializer->start_embed (*this); 472 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 473 out->format = format; 474 475 bool ret = true; 476 for (const Offset32To<Coverage>& offset : coverage.iter ()) 477 { 478 auto snap = c->serializer->snapshot (); 479 auto *o = out->coverage.serialize_append (c->serializer); 480 if (unlikely (!o)) 481 { 482 ret = false; 483 break; 484 } 485 486 //skip empty coverage 487 c->serializer->push (); 488 bool res = false; 489 if (offset) res = c->dispatch (this+offset); 490 if (!res) 491 { 492 c->serializer->pop_discard (); 493 c->serializer->revert (snap); 494 (out->coverage.len)--; 495 continue; 496 } 497 c->serializer->add_link (*o, c->serializer->pop_pack ()); 498 } 499 500 return_trace (ret && out->coverage.len); 501 } 502 503 bool sanitize (hb_sanitize_context_t *c) const 504 { 505 TRACE_SANITIZE (this); 506 return_trace (coverage.sanitize (c, this)); 507 } 508 509 protected: 510 HBUINT16 format; /* Format identifier--format = 1 */ 511 Array16Of<Offset32To<Coverage>> 512 coverage; /* Array of long offsets to mark set 513 * coverage tables */ 514 public: 515 DEFINE_SIZE_ARRAY (4, coverage); 516 }; 517 518 struct MarkGlyphSets 519 { 520 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 521 { 522 switch (u.format.v) { 523 case 1: return u.format1.covers (set_index, glyph_id); 524 default:return false; 525 } 526 } 527 528 template <typename set_t> 529 void collect_coverage (hb_vector_t<set_t> &sets) const 530 { 531 switch (u.format.v) { 532 case 1: u.format1.collect_coverage (sets); return; 533 default:return; 534 } 535 } 536 537 void collect_used_mark_sets (const hb_set_t& glyph_set, 538 hb_set_t& used_mark_sets /* OUT */) const 539 { 540 switch (u.format.v) { 541 case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return; 542 default:return; 543 } 544 } 545 546 bool subset (hb_subset_context_t *c) const 547 { 548 TRACE_SUBSET (this); 549 switch (u.format.v) { 550 case 1: return_trace (u.format1.subset (c)); 551 default:return_trace (false); 552 } 553 } 554 555 bool sanitize (hb_sanitize_context_t *c) const 556 { 557 TRACE_SANITIZE (this); 558 if (!u.format.v.sanitize (c)) return_trace (false); 559 hb_barrier (); 560 switch (u.format.v) { 561 case 1: return_trace (u.format1.sanitize (c)); 562 default:return_trace (true); 563 } 564 } 565 566 protected: 567 union { 568 struct { HBUINT16 v; } format; /* Format identifier */ 569 MarkGlyphSetsFormat1 format1; 570 } u; 571 public: 572 DEFINE_SIZE_UNION (2, format.v); 573 }; 574 575 576 /* 577 * GDEF -- Glyph Definition 578 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef 579 */ 580 581 582 template <typename Types> 583 struct GDEFVersion1_2 584 { 585 friend struct GDEF; 586 587 protected: 588 FixedVersion<>version; /* Version of the GDEF table--currently 589 * 0x00010003u */ 590 typename Types::template OffsetTo<ClassDef> 591 glyphClassDef; /* Offset to class definition table 592 * for glyph type--from beginning of 593 * GDEF header (may be Null) */ 594 typename Types::template OffsetTo<AttachList> 595 attachList; /* Offset to list of glyphs with 596 * attachment points--from beginning 597 * of GDEF header (may be Null) */ 598 typename Types::template OffsetTo<LigCaretList> 599 ligCaretList; /* Offset to list of positioning points 600 * for ligature carets--from beginning 601 * of GDEF header (may be Null) */ 602 typename Types::template OffsetTo<ClassDef> 603 markAttachClassDef; /* Offset to class definition table for 604 * mark attachment type--from beginning 605 * of GDEF header (may be Null) */ 606 typename Types::template OffsetTo<MarkGlyphSets> 607 markGlyphSetsDef; /* Offset to the table of mark set 608 * definitions--from beginning of GDEF 609 * header (may be NULL). Introduced 610 * in version 0x00010002. */ 611 Offset32To<ItemVariationStore> 612 varStore; /* Offset to the table of Item Variation 613 * Store--from beginning of GDEF 614 * header (may be NULL). Introduced 615 * in version 0x00010003. */ 616 public: 617 DEFINE_SIZE_MIN (4 + 4 * Types::size); 618 619 unsigned int get_size () const 620 { 621 return min_size + 622 (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + 623 (version.to_int () >= 0x00010003u ? varStore.static_size : 0); 624 } 625 626 bool sanitize (hb_sanitize_context_t *c) const 627 { 628 TRACE_SANITIZE (this); 629 return_trace (version.sanitize (c) && 630 glyphClassDef.sanitize (c, this) && 631 attachList.sanitize (c, this) && 632 ligCaretList.sanitize (c, this) && 633 markAttachClassDef.sanitize (c, this) && 634 hb_barrier () && 635 ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) && 636 ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this))); 637 } 638 639 static void remap_varidx_after_instantiation (const hb_map_t& varidx_map, 640 hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */) 641 { 642 /* varidx_map is empty which means varstore is empty after instantiation, 643 * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX. 644 * varidx_map doesn't have original varidx, indicating delta row is all 645 * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */ 646 for (auto _ : layout_variation_idx_delta_map.iter_ref ()) 647 { 648 /* old_varidx->(varidx, delta) mapping generated for subsetting, then this 649 * varidx is used as key of varidx_map during instantiation */ 650 uint32_t varidx = _.second.first; 651 uint32_t *new_varidx; 652 if (varidx_map.has (varidx, &new_varidx)) 653 _.second.first = *new_varidx; 654 else 655 _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX; 656 } 657 } 658 659 bool subset (hb_subset_context_t *c) const 660 { 661 TRACE_SUBSET (this); 662 auto *out = c->serializer->start_embed (*this); 663 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 664 665 // Push var store first (if it's needed) so that it's last in the 666 // serialization order. Some font consumers assume that varstore runs to 667 // the end of the GDEF table. 668 // See: https://github.com/harfbuzz/harfbuzz/issues/4636 669 auto snapshot_version0 = c->serializer->snapshot (); 670 if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef))) 671 return_trace (false); 672 673 bool subset_varstore = false; 674 unsigned varstore_index = (unsigned) -1; 675 auto snapshot_version2 = c->serializer->snapshot (); 676 if (version.to_int () >= 0x00010003u && hb_barrier ()) 677 { 678 if (unlikely (!c->serializer->embed (varStore))) return_trace (false); 679 if (c->plan->all_axes_pinned) 680 out->varStore = 0; 681 else if (c->plan->normalized_coords) 682 { 683 if (varStore) 684 { 685 item_variations_t item_vars; 686 if (item_vars.instantiate (this+varStore, c->plan, true, true, 687 c->plan->gdef_varstore_inner_maps.as_array ())) { 688 subset_varstore = out->varStore.serialize_serialize (c->serializer, 689 item_vars.has_long_word (), 690 c->plan->axis_tags, 691 item_vars.get_region_list (), 692 item_vars.get_vardata_encodings ()); 693 varstore_index = c->serializer->last_added_child_index(); 694 } 695 remap_varidx_after_instantiation (item_vars.get_varidx_map (), 696 c->plan->layout_variation_idx_delta_map); 697 } 698 } 699 else 700 { 701 subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); 702 varstore_index = c->serializer->last_added_child_index(); 703 } 704 } 705 706 out->version.major = version.major; 707 out->version.minor = version.minor; 708 709 if (!subset_varstore && version.to_int () >= 0x00010002u) { 710 c->serializer->revert (snapshot_version2); 711 } 712 713 bool subset_markglyphsetsdef = false; 714 if (version.to_int () >= 0x00010002u && hb_barrier ()) 715 { 716 subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); 717 } 718 719 if (subset_varstore) 720 { 721 out->version.minor = 3; 722 c->plan->has_gdef_varstore = true; 723 } else if (subset_markglyphsetsdef) { 724 out->version.minor = 2; 725 } else { 726 out->version.minor = 0; 727 c->serializer->revert (snapshot_version0); 728 } 729 730 bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); 731 bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); 732 bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); 733 bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); 734 735 if (subset_varstore && varstore_index != (unsigned) -1) { 736 c->serializer->repack_last(varstore_index); 737 } 738 739 return_trace (subset_glyphclassdef || subset_attachlist || 740 subset_ligcaretlist || subset_markattachclassdef || 741 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || 742 (out->version.to_int () >= 0x00010003u && subset_varstore)); 743 } 744 }; 745 746 struct GDEF 747 { 748 static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; 749 750 enum GlyphClasses { 751 UnclassifiedGlyph = 0, 752 BaseGlyph = 1, 753 LigatureGlyph = 2, 754 MarkGlyph = 3, 755 ComponentGlyph = 4 756 }; 757 758 unsigned int get_size () const 759 { 760 switch (u.version.major) { 761 case 1: return u.version1.get_size (); 762 #ifndef HB_NO_BEYOND_64K 763 case 2: return u.version2.get_size (); 764 #endif 765 default: return u.version.static_size; 766 } 767 } 768 769 bool sanitize (hb_sanitize_context_t *c) const 770 { 771 TRACE_SANITIZE (this); 772 if (unlikely (!u.version.sanitize (c))) return_trace (false); 773 hb_barrier (); 774 switch (u.version.major) { 775 case 1: return_trace (u.version1.sanitize (c)); 776 #ifndef HB_NO_BEYOND_64K 777 case 2: return_trace (u.version2.sanitize (c)); 778 #endif 779 default: return_trace (true); 780 } 781 } 782 783 bool subset (hb_subset_context_t *c) const 784 { 785 switch (u.version.major) { 786 case 1: return u.version1.subset (c); 787 #ifndef HB_NO_BEYOND_64K 788 case 2: return u.version2.subset (c); 789 #endif 790 default: return false; 791 } 792 } 793 794 bool has_glyph_classes () const 795 { 796 switch (u.version.major) { 797 case 1: return u.version1.glyphClassDef != 0; 798 #ifndef HB_NO_BEYOND_64K 799 case 2: return u.version2.glyphClassDef != 0; 800 #endif 801 default: return false; 802 } 803 } 804 const ClassDef &get_glyph_class_def () const 805 { 806 switch (u.version.major) { 807 case 1: return this+u.version1.glyphClassDef; 808 #ifndef HB_NO_BEYOND_64K 809 case 2: return this+u.version2.glyphClassDef; 810 #endif 811 default: return Null(ClassDef); 812 } 813 } 814 bool has_attach_list () const 815 { 816 switch (u.version.major) { 817 case 1: return u.version1.attachList != 0; 818 #ifndef HB_NO_BEYOND_64K 819 case 2: return u.version2.attachList != 0; 820 #endif 821 default: return false; 822 } 823 } 824 const AttachList &get_attach_list () const 825 { 826 switch (u.version.major) { 827 case 1: return this+u.version1.attachList; 828 #ifndef HB_NO_BEYOND_64K 829 case 2: return this+u.version2.attachList; 830 #endif 831 default: return Null(AttachList); 832 } 833 } 834 bool has_lig_carets () const 835 { 836 switch (u.version.major) { 837 case 1: return u.version1.ligCaretList != 0; 838 #ifndef HB_NO_BEYOND_64K 839 case 2: return u.version2.ligCaretList != 0; 840 #endif 841 default: return false; 842 } 843 } 844 const LigCaretList &get_lig_caret_list () const 845 { 846 switch (u.version.major) { 847 case 1: return this+u.version1.ligCaretList; 848 #ifndef HB_NO_BEYOND_64K 849 case 2: return this+u.version2.ligCaretList; 850 #endif 851 default: return Null(LigCaretList); 852 } 853 } 854 bool has_mark_attachment_types () const 855 { 856 switch (u.version.major) { 857 case 1: return u.version1.markAttachClassDef != 0; 858 #ifndef HB_NO_BEYOND_64K 859 case 2: return u.version2.markAttachClassDef != 0; 860 #endif 861 default: return false; 862 } 863 } 864 const ClassDef &get_mark_attach_class_def () const 865 { 866 switch (u.version.major) { 867 case 1: return this+u.version1.markAttachClassDef; 868 #ifndef HB_NO_BEYOND_64K 869 case 2: return this+u.version2.markAttachClassDef; 870 #endif 871 default: return Null(ClassDef); 872 } 873 } 874 bool has_mark_glyph_sets () const 875 { 876 switch (u.version.major) { 877 case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0; 878 #ifndef HB_NO_BEYOND_64K 879 case 2: return u.version2.markGlyphSetsDef != 0; 880 #endif 881 default: return false; 882 } 883 } 884 const MarkGlyphSets &get_mark_glyph_sets () const 885 { 886 switch (u.version.major) { 887 case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets); 888 #ifndef HB_NO_BEYOND_64K 889 case 2: return this+u.version2.markGlyphSetsDef; 890 #endif 891 default: return Null(MarkGlyphSets); 892 } 893 } 894 bool has_var_store () const 895 { 896 switch (u.version.major) { 897 case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0; 898 #ifndef HB_NO_BEYOND_64K 899 case 2: return u.version2.varStore != 0; 900 #endif 901 default: return false; 902 } 903 } 904 const ItemVariationStore &get_var_store () const 905 { 906 switch (u.version.major) { 907 case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore); 908 #ifndef HB_NO_BEYOND_64K 909 case 2: return this+u.version2.varStore; 910 #endif 911 default: return Null(ItemVariationStore); 912 } 913 } 914 915 916 bool has_data () const { return u.version.to_int (); } 917 unsigned int get_glyph_class (hb_codepoint_t glyph) const 918 { return get_glyph_class_def ().get_class (glyph); } 919 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const 920 { get_glyph_class_def ().collect_class (glyphs, klass); } 921 922 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const 923 { return get_mark_attach_class_def ().get_class (glyph); } 924 925 unsigned int get_attach_points (hb_codepoint_t glyph_id, 926 unsigned int start_offset, 927 unsigned int *point_count /* IN/OUT */, 928 unsigned int *point_array /* OUT */) const 929 { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); } 930 931 unsigned int get_lig_carets (hb_font_t *font, 932 hb_direction_t direction, 933 hb_codepoint_t glyph_id, 934 unsigned int start_offset, 935 unsigned int *caret_count /* IN/OUT */, 936 hb_position_t *caret_array /* OUT */) const 937 { return get_lig_caret_list ().get_lig_carets (font, 938 direction, glyph_id, get_var_store(), 939 start_offset, caret_count, caret_array); } 940 941 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const 942 { return get_mark_glyph_sets ().covers (set_index, glyph_id); } 943 944 /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing 945 * glyph class and other bits, and high 8-bit the mark attachment type (if any). 946 * Not to be confused with lookup_props which is very similar. */ 947 unsigned int get_glyph_props (hb_codepoint_t glyph) const 948 { 949 unsigned int klass = get_glyph_class (glyph); 950 951 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); 952 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); 953 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); 954 955 switch (klass) { 956 default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; 957 case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; 958 case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 959 case MarkGlyph: 960 klass = get_mark_attachment_type (glyph); 961 return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); 962 } 963 } 964 965 HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, 966 hb_face_t *face) const; 967 968 struct accelerator_t 969 { 970 accelerator_t (hb_face_t *face) 971 { 972 table = hb_sanitize_context_t ().reference_table<GDEF> (face); 973 if (unlikely (table->is_blocklisted (table.get_blob (), face))) 974 { 975 hb_blob_destroy (table.get_blob ()); 976 table = hb_blob_get_empty (); 977 } 978 979 #ifndef HB_NO_GDEF_CACHE 980 table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets); 981 #endif 982 } 983 ~accelerator_t () { table.destroy (); } 984 985 unsigned int get_glyph_props (hb_codepoint_t glyph) const 986 { 987 unsigned v; 988 989 #ifndef HB_NO_GDEF_CACHE 990 if (glyph_props_cache.get (glyph, &v)) 991 return v; 992 #endif 993 994 v = table->get_glyph_props (glyph); 995 996 #ifndef HB_NO_GDEF_CACHE 997 if (likely (table.get_blob ())) // Don't try setting if we are the null instance! 998 glyph_props_cache.set (glyph, v); 999 #endif 1000 1001 return v; 1002 1003 } 1004 1005 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const 1006 { 1007 return 1008 #ifndef HB_NO_GDEF_CACHE 1009 mark_glyph_sets[set_index].may_have (glyph_id) 1010 #else 1011 table->mark_set_covers (set_index, glyph_id) 1012 #endif 1013 ; 1014 } 1015 1016 hb_blob_ptr_t<GDEF> table; 1017 #ifndef HB_NO_GDEF_CACHE 1018 hb_vector_t<hb_bit_set_t> mark_glyph_sets; 1019 mutable hb_cache_t<21, 3> glyph_props_cache; 1020 static_assert (sizeof (glyph_props_cache) == 512, ""); 1021 #endif 1022 }; 1023 1024 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 1025 { get_lig_caret_list ().collect_variation_indices (c); } 1026 1027 protected: 1028 union { 1029 FixedVersion<> version; /* Version identifier */ 1030 GDEFVersion1_2<SmallTypes> version1; 1031 #ifndef HB_NO_BEYOND_64K 1032 GDEFVersion1_2<MediumTypes> version2; 1033 #endif 1034 } u; 1035 public: 1036 DEFINE_SIZE_MIN (4); 1037 }; 1038 1039 struct GDEF_accelerator_t : GDEF::accelerator_t { 1040 GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} 1041 }; 1042 1043 } /* namespace OT */ 1044 1045 1046 #endif /* OT_LAYOUT_GDEF_GDEF_HH */