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 HB_OT_LAYOUT_GDEF_TABLE_HH 30 #define HB_OT_LAYOUT_GDEF_TABLE_HH 31 32 #include "hb-ot-layout-common.hh" 33 34 #include "hb-font.hh" 35 36 37 namespace OT { 38 39 40 /* 41 * Attachment List Table 42 */ 43 44 /* Array of contour point indices--in increasing numerical order */ 45 struct AttachPoint : Array16Of<HBUINT16> 46 { subsetOT::AttachPoint47 bool subset (hb_subset_context_t *c) const 48 { 49 TRACE_SUBSET (this); 50 auto *out = c->serializer->start_embed (*this); 51 if (unlikely (!out)) return_trace (false); 52 53 return_trace (out->serialize (c->serializer, + iter ())); 54 } 55 }; 56 57 struct AttachList 58 { get_attach_pointsOT::AttachList59 unsigned int get_attach_points (hb_codepoint_t glyph_id, 60 unsigned int start_offset, 61 unsigned int *point_count /* IN/OUT */, 62 unsigned int *point_array /* OUT */) const 63 { 64 unsigned int index = (this+coverage).get_coverage (glyph_id); 65 if (index == NOT_COVERED) 66 { 67 if (point_count) 68 *point_count = 0; 69 return 0; 70 } 71 72 const AttachPoint &points = this+attachPoint[index]; 73 74 if (point_count) 75 { 76 + points.as_array ().sub_array (start_offset, point_count) 77 | hb_sink (hb_array (point_array, *point_count)) 78 ; 79 } 80 81 return points.len; 82 } 83 subsetOT::AttachList84 bool subset (hb_subset_context_t *c) const 85 { 86 TRACE_SUBSET (this); 87 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); 88 const hb_map_t &glyph_map = *c->plan->glyph_map; 89 90 auto *out = c->serializer->start_embed (*this); 91 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 92 93 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 94 + hb_zip (this+coverage, attachPoint) 95 | hb_filter (glyphset, hb_first) 96 | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second) 97 | hb_map (hb_first) 98 | hb_map (glyph_map) 99 | hb_sink (new_coverage) 100 ; 101 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); 102 return_trace (bool (new_coverage)); 103 } 104 sanitizeOT::AttachList105 bool sanitize (hb_sanitize_context_t *c) const 106 { 107 TRACE_SANITIZE (this); 108 return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); 109 } 110 111 protected: 112 Offset16To<Coverage> 113 coverage; /* Offset to Coverage table -- from 114 * beginning of AttachList table */ 115 Array16OfOffset16To<AttachPoint> 116 attachPoint; /* Array of AttachPoint tables 117 * in Coverage Index order */ 118 public: 119 DEFINE_SIZE_ARRAY (4, attachPoint); 120 }; 121 122 /* 123 * Ligature Caret Table 124 */ 125 126 struct CaretValueFormat1 127 { 128 friend struct CaretValue; subsetOT::CaretValueFormat1129 bool subset (hb_subset_context_t *c) const 130 { 131 TRACE_SUBSET (this); 132 auto *out = c->serializer->embed (this); 133 if (unlikely (!out)) return_trace (false); 134 return_trace (true); 135 } 136 137 private: get_caret_valueOT::CaretValueFormat1138 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const 139 { 140 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); 141 } 142 sanitizeOT::CaretValueFormat1143 bool sanitize (hb_sanitize_context_t *c) const 144 { 145 TRACE_SANITIZE (this); 146 return_trace (c->check_struct (this)); 147 } 148 149 protected: 150 HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ 151 FWORD coordinate; /* X or Y value, in design units */ 152 public: 153 DEFINE_SIZE_STATIC (4); 154 }; 155 156 struct CaretValueFormat2 157 { 158 friend struct CaretValue; subsetOT::CaretValueFormat2159 bool subset (hb_subset_context_t *c) const 160 { 161 TRACE_SUBSET (this); 162 auto *out = c->serializer->embed (this); 163 if (unlikely (!out)) return_trace (false); 164 return_trace (true); 165 } 166 167 private: get_caret_valueOT::CaretValueFormat2168 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const 169 { 170 hb_position_t x, y; 171 font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); 172 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; 173 } 174 sanitizeOT::CaretValueFormat2175 bool sanitize (hb_sanitize_context_t *c) const 176 { 177 TRACE_SANITIZE (this); 178 return_trace (c->check_struct (this)); 179 } 180 181 protected: 182 HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ 183 HBUINT16 caretValuePoint; /* Contour point index on glyph */ 184 public: 185 DEFINE_SIZE_STATIC (4); 186 }; 187 188 struct CaretValueFormat3 189 { 190 friend struct CaretValue; 191 get_caret_valueOT::CaretValueFormat3192 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, 193 const VariationStore &var_store) const 194 { 195 return HB_DIRECTION_IS_HORIZONTAL (direction) ? 196 font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : 197 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); 198 } 199 subsetOT::CaretValueFormat3200 bool subset (hb_subset_context_t *c) const 201 { 202 TRACE_SUBSET (this); 203 auto *out = c->serializer->start_embed (*this); 204 if (unlikely (!out)) return_trace (false); 205 if (!c->serializer->embed (caretValueFormat)) return_trace (false); 206 if (!c->serializer->embed (coordinate)) return_trace (false); 207 208 unsigned varidx = (this+deviceTable).get_variation_index (); 209 if (c->plan->layout_variation_idx_delta_map->has (varidx)) 210 { 211 int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (varidx)); 212 if (delta != 0) 213 { 214 if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 215 return_trace (false); 216 } 217 } 218 219 if (c->plan->all_axes_pinned) 220 return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); 221 222 if (!c->serializer->embed (deviceTable)) 223 return_trace (false); 224 225 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), 226 hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map)); 227 } 228 collect_variation_indicesOT::CaretValueFormat3229 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 230 { (this+deviceTable).collect_variation_indices (c); } 231 sanitizeOT::CaretValueFormat3232 bool sanitize (hb_sanitize_context_t *c) const 233 { 234 TRACE_SANITIZE (this); 235 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); 236 } 237 238 protected: 239 HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ 240 FWORD coordinate; /* X or Y value, in design units */ 241 Offset16To<Device> 242 deviceTable; /* Offset to Device table for X or Y 243 * value--from beginning of CaretValue 244 * table */ 245 public: 246 DEFINE_SIZE_STATIC (6); 247 }; 248 249 struct CaretValue 250 { get_caret_valueOT::CaretValue251 hb_position_t get_caret_value (hb_font_t *font, 252 hb_direction_t direction, 253 hb_codepoint_t glyph_id, 254 const VariationStore &var_store) const 255 { 256 switch (u.format) { 257 case 1: return u.format1.get_caret_value (font, direction); 258 case 2: return u.format2.get_caret_value (font, direction, glyph_id); 259 case 3: return u.format3.get_caret_value (font, direction, var_store); 260 default:return 0; 261 } 262 } 263 264 template <typename context_t, typename ...Ts> dispatchOT::CaretValue265 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 266 { 267 TRACE_DISPATCH (this, u.format); 268 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 269 switch (u.format) { 270 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 271 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); 272 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...)); 273 default:return_trace (c->default_return_value ()); 274 } 275 } 276 collect_variation_indicesOT::CaretValue277 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 278 { 279 switch (u.format) { 280 case 1: 281 case 2: 282 return; 283 case 3: 284 u.format3.collect_variation_indices (c); 285 return; 286 default: return; 287 } 288 } 289 sanitizeOT::CaretValue290 bool sanitize (hb_sanitize_context_t *c) const 291 { 292 TRACE_SANITIZE (this); 293 if (!u.format.sanitize (c)) return_trace (false); 294 switch (u.format) { 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 HBUINT16 format; /* Format identifier */ 305 CaretValueFormat1 format1; 306 CaretValueFormat2 format2; 307 CaretValueFormat3 format3; 308 } u; 309 public: 310 DEFINE_SIZE_UNION (2, format); 311 }; 312 313 struct LigGlyph 314 { get_lig_caretsOT::LigGlyph315 unsigned get_lig_carets (hb_font_t *font, 316 hb_direction_t direction, 317 hb_codepoint_t glyph_id, 318 const VariationStore &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 subsetOT::LigGlyph335 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 collect_variation_indicesOT::LigGlyph348 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 sanitizeOT::LigGlyph354 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 { get_lig_caretsOT::LigCaretList371 unsigned int get_lig_carets (hb_font_t *font, 372 hb_direction_t direction, 373 hb_codepoint_t glyph_id, 374 const VariationStore &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 subsetOT::LigCaretList390 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 collect_variation_indicesOT::LigCaretList411 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 sanitizeOT::LigCaretList421 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 { coversOT::MarkGlyphSetsFormat1441 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 subsetOT::MarkGlyphSetsFormat1444 bool subset (hb_subset_context_t *c) const 445 { 446 TRACE_SUBSET (this); 447 auto *out = c->serializer->start_embed (*this); 448 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 449 out->format = format; 450 451 bool ret = true; 452 for (const Offset32To<Coverage>& offset : coverage.iter ()) 453 { 454 auto *o = out->coverage.serialize_append (c->serializer); 455 if (unlikely (!o)) 456 { 457 ret = false; 458 break; 459 } 460 461 //not using o->serialize_subset (c, offset, this, out) here because 462 //OTS doesn't allow null offset. 463 //See issue: https://github.com/khaledhosny/ots/issues/172 464 c->serializer->push (); 465 c->dispatch (this+offset); 466 c->serializer->add_link (*o, c->serializer->pop_pack ()); 467 } 468 469 return_trace (ret && out->coverage.len); 470 } 471 sanitizeOT::MarkGlyphSetsFormat1472 bool sanitize (hb_sanitize_context_t *c) const 473 { 474 TRACE_SANITIZE (this); 475 return_trace (coverage.sanitize (c, this)); 476 } 477 478 protected: 479 HBUINT16 format; /* Format identifier--format = 1 */ 480 Array16Of<Offset32To<Coverage>> 481 coverage; /* Array of long offsets to mark set 482 * coverage tables */ 483 public: 484 DEFINE_SIZE_ARRAY (4, coverage); 485 }; 486 487 struct MarkGlyphSets 488 { coversOT::MarkGlyphSets489 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 490 { 491 switch (u.format) { 492 case 1: return u.format1.covers (set_index, glyph_id); 493 default:return false; 494 } 495 } 496 subsetOT::MarkGlyphSets497 bool subset (hb_subset_context_t *c) const 498 { 499 TRACE_SUBSET (this); 500 switch (u.format) { 501 case 1: return_trace (u.format1.subset (c)); 502 default:return_trace (false); 503 } 504 } 505 sanitizeOT::MarkGlyphSets506 bool sanitize (hb_sanitize_context_t *c) const 507 { 508 TRACE_SANITIZE (this); 509 if (!u.format.sanitize (c)) return_trace (false); 510 switch (u.format) { 511 case 1: return_trace (u.format1.sanitize (c)); 512 default:return_trace (true); 513 } 514 } 515 516 protected: 517 union { 518 HBUINT16 format; /* Format identifier */ 519 MarkGlyphSetsFormat1 format1; 520 } u; 521 public: 522 DEFINE_SIZE_UNION (2, format); 523 }; 524 525 526 /* 527 * GDEF -- Glyph Definition 528 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef 529 */ 530 531 532 template <typename Types> 533 struct GDEFVersion1_2 534 { 535 friend struct GDEF; 536 537 protected: 538 FixedVersion<>version; /* Version of the GDEF table--currently 539 * 0x00010003u */ 540 typename Types::template OffsetTo<ClassDef> 541 glyphClassDef; /* Offset to class definition table 542 * for glyph type--from beginning of 543 * GDEF header (may be Null) */ 544 typename Types::template OffsetTo<AttachList> 545 attachList; /* Offset to list of glyphs with 546 * attachment points--from beginning 547 * of GDEF header (may be Null) */ 548 typename Types::template OffsetTo<LigCaretList> 549 ligCaretList; /* Offset to list of positioning points 550 * for ligature carets--from beginning 551 * of GDEF header (may be Null) */ 552 typename Types::template OffsetTo<ClassDef> 553 markAttachClassDef; /* Offset to class definition table for 554 * mark attachment type--from beginning 555 * of GDEF header (may be Null) */ 556 typename Types::template OffsetTo<MarkGlyphSets> 557 markGlyphSetsDef; /* Offset to the table of mark set 558 * definitions--from beginning of GDEF 559 * header (may be NULL). Introduced 560 * in version 0x00010002. */ 561 Offset32To<VariationStore> 562 varStore; /* Offset to the table of Item Variation 563 * Store--from beginning of GDEF 564 * header (may be NULL). Introduced 565 * in version 0x00010003. */ 566 public: 567 DEFINE_SIZE_MIN (4 + 4 * Types::size); 568 get_sizeOT::GDEFVersion1_2569 unsigned int get_size () const 570 { 571 return min_size + 572 (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + 573 (version.to_int () >= 0x00010003u ? varStore.static_size : 0); 574 } 575 sanitizeOT::GDEFVersion1_2576 bool sanitize (hb_sanitize_context_t *c) const 577 { 578 TRACE_SANITIZE (this); 579 return_trace (version.sanitize (c) && 580 glyphClassDef.sanitize (c, this) && 581 attachList.sanitize (c, this) && 582 ligCaretList.sanitize (c, this) && 583 markAttachClassDef.sanitize (c, this) && 584 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && 585 (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); 586 } 587 subsetOT::GDEFVersion1_2588 bool subset (hb_subset_context_t *c) const 589 { 590 TRACE_SUBSET (this); 591 auto *out = c->serializer->embed (*this); 592 if (unlikely (!out)) return_trace (false); 593 594 bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); 595 bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); 596 bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); 597 bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); 598 599 bool subset_markglyphsetsdef = false; 600 if (version.to_int () >= 0x00010002u) 601 { 602 subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); 603 } 604 605 bool subset_varstore = false; 606 if (version.to_int () >= 0x00010003u) 607 { 608 if (c->plan->all_axes_pinned) 609 out->varStore = 0; 610 else 611 subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); 612 } 613 614 if (subset_varstore) 615 { 616 out->version.minor = 3; 617 } else if (subset_markglyphsetsdef) { 618 out->version.minor = 2; 619 } else { 620 out->version.minor = 0; 621 } 622 623 return_trace (subset_glyphclassdef || subset_attachlist || 624 subset_ligcaretlist || subset_markattachclassdef || 625 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || 626 (out->version.to_int () >= 0x00010003u && subset_varstore)); 627 } 628 }; 629 630 struct GDEF 631 { 632 static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; 633 634 enum GlyphClasses { 635 UnclassifiedGlyph = 0, 636 BaseGlyph = 1, 637 LigatureGlyph = 2, 638 MarkGlyph = 3, 639 ComponentGlyph = 4 640 }; 641 get_sizeOT::GDEF642 unsigned int get_size () const 643 { 644 switch (u.version.major) { 645 case 1: return u.version1.get_size (); 646 #ifndef HB_NO_BEYOND_64K 647 case 2: return u.version2.get_size (); 648 #endif 649 default: return u.version.static_size; 650 } 651 } 652 sanitizeOT::GDEF653 bool sanitize (hb_sanitize_context_t *c) const 654 { 655 TRACE_SANITIZE (this); 656 if (unlikely (!u.version.sanitize (c))) return_trace (false); 657 switch (u.version.major) { 658 case 1: return_trace (u.version1.sanitize (c)); 659 #ifndef HB_NO_BEYOND_64K 660 case 2: return_trace (u.version2.sanitize (c)); 661 #endif 662 default: return_trace (true); 663 } 664 } 665 subsetOT::GDEF666 bool subset (hb_subset_context_t *c) const 667 { 668 switch (u.version.major) { 669 case 1: return u.version1.subset (c); 670 #ifndef HB_NO_BEYOND_64K 671 case 2: return u.version2.subset (c); 672 #endif 673 default: return false; 674 } 675 } 676 has_glyph_classesOT::GDEF677 bool has_glyph_classes () const 678 { 679 switch (u.version.major) { 680 case 1: return u.version1.glyphClassDef != 0; 681 #ifndef HB_NO_BEYOND_64K 682 case 2: return u.version2.glyphClassDef != 0; 683 #endif 684 default: return false; 685 } 686 } get_glyph_class_defOT::GDEF687 const ClassDef &get_glyph_class_def () const 688 { 689 switch (u.version.major) { 690 case 1: return this+u.version1.glyphClassDef; 691 #ifndef HB_NO_BEYOND_64K 692 case 2: return this+u.version2.glyphClassDef; 693 #endif 694 default: return Null(ClassDef); 695 } 696 } has_attach_listOT::GDEF697 bool has_attach_list () const 698 { 699 switch (u.version.major) { 700 case 1: return u.version1.attachList != 0; 701 #ifndef HB_NO_BEYOND_64K 702 case 2: return u.version2.attachList != 0; 703 #endif 704 default: return false; 705 } 706 } get_attach_listOT::GDEF707 const AttachList &get_attach_list () const 708 { 709 switch (u.version.major) { 710 case 1: return this+u.version1.attachList; 711 #ifndef HB_NO_BEYOND_64K 712 case 2: return this+u.version2.attachList; 713 #endif 714 default: return Null(AttachList); 715 } 716 } has_lig_caretsOT::GDEF717 bool has_lig_carets () const 718 { 719 switch (u.version.major) { 720 case 1: return u.version1.ligCaretList != 0; 721 #ifndef HB_NO_BEYOND_64K 722 case 2: return u.version2.ligCaretList != 0; 723 #endif 724 default: return false; 725 } 726 } get_lig_caret_listOT::GDEF727 const LigCaretList &get_lig_caret_list () const 728 { 729 switch (u.version.major) { 730 case 1: return this+u.version1.ligCaretList; 731 #ifndef HB_NO_BEYOND_64K 732 case 2: return this+u.version2.ligCaretList; 733 #endif 734 default: return Null(LigCaretList); 735 } 736 } has_mark_attachment_typesOT::GDEF737 bool has_mark_attachment_types () const 738 { 739 switch (u.version.major) { 740 case 1: return u.version1.markAttachClassDef != 0; 741 #ifndef HB_NO_BEYOND_64K 742 case 2: return u.version2.markAttachClassDef != 0; 743 #endif 744 default: return false; 745 } 746 } get_mark_attach_class_defOT::GDEF747 const ClassDef &get_mark_attach_class_def () const 748 { 749 switch (u.version.major) { 750 case 1: return this+u.version1.markAttachClassDef; 751 #ifndef HB_NO_BEYOND_64K 752 case 2: return this+u.version2.markAttachClassDef; 753 #endif 754 default: return Null(ClassDef); 755 } 756 } has_mark_glyph_setsOT::GDEF757 bool has_mark_glyph_sets () const 758 { 759 switch (u.version.major) { 760 case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0; 761 #ifndef HB_NO_BEYOND_64K 762 case 2: return u.version2.markGlyphSetsDef != 0; 763 #endif 764 default: return false; 765 } 766 } get_mark_glyph_setsOT::GDEF767 const MarkGlyphSets &get_mark_glyph_sets () const 768 { 769 switch (u.version.major) { 770 case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets); 771 #ifndef HB_NO_BEYOND_64K 772 case 2: return this+u.version2.markGlyphSetsDef; 773 #endif 774 default: return Null(MarkGlyphSets); 775 } 776 } has_var_storeOT::GDEF777 bool has_var_store () const 778 { 779 switch (u.version.major) { 780 case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0; 781 #ifndef HB_NO_BEYOND_64K 782 case 2: return u.version2.varStore != 0; 783 #endif 784 default: return false; 785 } 786 } get_var_storeOT::GDEF787 const VariationStore &get_var_store () const 788 { 789 switch (u.version.major) { 790 case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore); 791 #ifndef HB_NO_BEYOND_64K 792 case 2: return this+u.version2.varStore; 793 #endif 794 default: return Null(VariationStore); 795 } 796 } 797 798 has_dataOT::GDEF799 bool has_data () const { return u.version.to_int (); } get_glyph_classOT::GDEF800 unsigned int get_glyph_class (hb_codepoint_t glyph) const 801 { return get_glyph_class_def ().get_class (glyph); } get_glyphs_in_classOT::GDEF802 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const 803 { get_glyph_class_def ().collect_class (glyphs, klass); } 804 get_mark_attachment_typeOT::GDEF805 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const 806 { return get_mark_attach_class_def ().get_class (glyph); } 807 get_attach_pointsOT::GDEF808 unsigned int get_attach_points (hb_codepoint_t glyph_id, 809 unsigned int start_offset, 810 unsigned int *point_count /* IN/OUT */, 811 unsigned int *point_array /* OUT */) const 812 { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); } 813 get_lig_caretsOT::GDEF814 unsigned int get_lig_carets (hb_font_t *font, 815 hb_direction_t direction, 816 hb_codepoint_t glyph_id, 817 unsigned int start_offset, 818 unsigned int *caret_count /* IN/OUT */, 819 hb_position_t *caret_array /* OUT */) const 820 { return get_lig_caret_list ().get_lig_carets (font, 821 direction, glyph_id, get_var_store(), 822 start_offset, caret_count, caret_array); } 823 mark_set_coversOT::GDEF824 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const 825 { return get_mark_glyph_sets ().covers (set_index, glyph_id); } 826 827 /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing 828 * glyph class and other bits, and high 8-bit the mark attachment type (if any). 829 * Not to be confused with lookup_props which is very similar. */ get_glyph_propsOT::GDEF830 unsigned int get_glyph_props (hb_codepoint_t glyph) const 831 { 832 unsigned int klass = get_glyph_class (glyph); 833 834 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); 835 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); 836 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); 837 838 switch (klass) { 839 default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; 840 case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; 841 case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 842 case MarkGlyph: 843 klass = get_mark_attachment_type (glyph); 844 return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); 845 } 846 } 847 848 HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, 849 hb_face_t *face) const; 850 851 struct accelerator_t 852 { accelerator_tOT::GDEF::accelerator_t853 accelerator_t (hb_face_t *face) 854 { 855 table = hb_sanitize_context_t ().reference_table<GDEF> (face); 856 if (unlikely (table->is_blocklisted (table.get_blob (), face))) 857 { 858 hb_blob_destroy (table.get_blob ()); 859 table = hb_blob_get_empty (); 860 } 861 } ~accelerator_tOT::GDEF::accelerator_t862 ~accelerator_t () { table.destroy (); } 863 864 hb_blob_ptr_t<GDEF> table; 865 }; 866 collect_variation_indicesOT::GDEF867 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 868 { get_lig_caret_list ().collect_variation_indices (c); } 869 remap_layout_variation_indicesOT::GDEF870 void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, 871 hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const 872 { 873 if (!has_var_store ()) return; 874 if (layout_variation_indices->is_empty ()) return; 875 876 unsigned new_major = 0, new_minor = 0; 877 unsigned last_major = (layout_variation_indices->get_min ()) >> 16; 878 for (unsigned idx : layout_variation_indices->iter ()) 879 { 880 uint16_t major = idx >> 16; 881 if (major >= get_var_store ().get_sub_table_count ()) break; 882 if (major != last_major) 883 { 884 new_minor = 0; 885 ++new_major; 886 } 887 888 unsigned new_idx = (new_major << 16) + new_minor; 889 if (!layout_variation_idx_delta_map->has (idx)) 890 continue; 891 int delta = hb_second (layout_variation_idx_delta_map->get (idx)); 892 893 layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta)); 894 ++new_minor; 895 last_major = major; 896 } 897 } 898 899 protected: 900 union { 901 FixedVersion<> version; /* Version identifier */ 902 GDEFVersion1_2<SmallTypes> version1; 903 #ifndef HB_NO_BEYOND_64K 904 GDEFVersion1_2<MediumTypes> version2; 905 #endif 906 } u; 907 public: 908 DEFINE_SIZE_MIN (4); 909 }; 910 911 struct GDEF_accelerator_t : GDEF::accelerator_t { GDEF_accelerator_tOT::GDEF_accelerator_t912 GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} 913 }; 914 915 } /* namespace OT */ 916 917 918 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */ 919