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 : ArrayOf<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.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 (); 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 (c->serializer, out) 102 .serialize (c->serializer, new_coverage.iter ()); 103 return_trace (bool (new_coverage)); 104 } 105 sanitizeOT::AttachList106 bool sanitize (hb_sanitize_context_t *c) const 107 { 108 TRACE_SANITIZE (this); 109 return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); 110 } 111 112 protected: 113 OffsetTo<Coverage> 114 coverage; /* Offset to Coverage table -- from 115 * beginning of AttachList table */ 116 OffsetArrayOf<AttachPoint> 117 attachPoint; /* Array of AttachPoint tables 118 * in Coverage Index order */ 119 public: 120 DEFINE_SIZE_ARRAY (4, attachPoint); 121 }; 122 123 /* 124 * Ligature Caret Table 125 */ 126 127 struct CaretValueFormat1 128 { 129 friend struct CaretValue; subsetOT::CaretValueFormat1130 bool subset (hb_subset_context_t *c) const 131 { 132 TRACE_SUBSET (this); 133 auto *out = c->serializer->embed (this); 134 if (unlikely (!out)) return_trace (false); 135 return_trace (true); 136 } 137 138 private: get_caret_valueOT::CaretValueFormat1139 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const 140 { 141 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); 142 } 143 sanitizeOT::CaretValueFormat1144 bool sanitize (hb_sanitize_context_t *c) const 145 { 146 TRACE_SANITIZE (this); 147 return_trace (c->check_struct (this)); 148 } 149 150 protected: 151 HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ 152 FWORD coordinate; /* X or Y value, in design units */ 153 public: 154 DEFINE_SIZE_STATIC (4); 155 }; 156 157 struct CaretValueFormat2 158 { 159 friend struct CaretValue; subsetOT::CaretValueFormat2160 bool subset (hb_subset_context_t *c) const 161 { 162 TRACE_SUBSET (this); 163 auto *out = c->serializer->embed (this); 164 if (unlikely (!out)) return_trace (false); 165 return_trace (true); 166 } 167 168 private: get_caret_valueOT::CaretValueFormat2169 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const 170 { 171 hb_position_t x, y; 172 font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); 173 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; 174 } 175 sanitizeOT::CaretValueFormat2176 bool sanitize (hb_sanitize_context_t *c) const 177 { 178 TRACE_SANITIZE (this); 179 return_trace (c->check_struct (this)); 180 } 181 182 protected: 183 HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ 184 HBUINT16 caretValuePoint; /* Contour point index on glyph */ 185 public: 186 DEFINE_SIZE_STATIC (4); 187 }; 188 189 struct CaretValueFormat3 190 { 191 friend struct CaretValue; 192 get_caret_valueOT::CaretValueFormat3193 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, 194 const VariationStore &var_store) const 195 { 196 return HB_DIRECTION_IS_HORIZONTAL (direction) ? 197 font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : 198 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); 199 } 200 subsetOT::CaretValueFormat3201 bool subset (hb_subset_context_t *c) const 202 { 203 TRACE_SUBSET (this); 204 auto *out = c->serializer->embed (this); 205 if (unlikely (!out)) return_trace (false); 206 207 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), 208 hb_serialize_context_t::Head, c->plan->layout_variation_idx_map)); 209 } 210 collect_variation_indicesOT::CaretValueFormat3211 void collect_variation_indices (hb_set_t *layout_variation_indices) const 212 { (this+deviceTable).collect_variation_indices (layout_variation_indices); } 213 sanitizeOT::CaretValueFormat3214 bool sanitize (hb_sanitize_context_t *c) const 215 { 216 TRACE_SANITIZE (this); 217 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); 218 } 219 220 protected: 221 HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ 222 FWORD coordinate; /* X or Y value, in design units */ 223 OffsetTo<Device> 224 deviceTable; /* Offset to Device table for X or Y 225 * value--from beginning of CaretValue 226 * table */ 227 public: 228 DEFINE_SIZE_STATIC (6); 229 }; 230 231 struct CaretValue 232 { get_caret_valueOT::CaretValue233 hb_position_t get_caret_value (hb_font_t *font, 234 hb_direction_t direction, 235 hb_codepoint_t glyph_id, 236 const VariationStore &var_store) const 237 { 238 switch (u.format) { 239 case 1: return u.format1.get_caret_value (font, direction); 240 case 2: return u.format2.get_caret_value (font, direction, glyph_id); 241 case 3: return u.format3.get_caret_value (font, direction, var_store); 242 default:return 0; 243 } 244 } 245 246 template <typename context_t, typename ...Ts> dispatchOT::CaretValue247 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 248 { 249 TRACE_DISPATCH (this, u.format); 250 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 251 switch (u.format) { 252 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...)); 253 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...)); 254 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...)); 255 default:return_trace (c->default_return_value ()); 256 } 257 } 258 collect_variation_indicesOT::CaretValue259 void collect_variation_indices (hb_set_t *layout_variation_indices) const 260 { 261 switch (u.format) { 262 case 1: 263 case 2: 264 return; 265 case 3: 266 u.format3.collect_variation_indices (layout_variation_indices); 267 return; 268 default: return; 269 } 270 } 271 sanitizeOT::CaretValue272 bool sanitize (hb_sanitize_context_t *c) const 273 { 274 TRACE_SANITIZE (this); 275 if (!u.format.sanitize (c)) return_trace (false); 276 switch (u.format) { 277 case 1: return_trace (u.format1.sanitize (c)); 278 case 2: return_trace (u.format2.sanitize (c)); 279 case 3: return_trace (u.format3.sanitize (c)); 280 default:return_trace (true); 281 } 282 } 283 284 protected: 285 union { 286 HBUINT16 format; /* Format identifier */ 287 CaretValueFormat1 format1; 288 CaretValueFormat2 format2; 289 CaretValueFormat3 format3; 290 } u; 291 public: 292 DEFINE_SIZE_UNION (2, format); 293 }; 294 295 struct LigGlyph 296 { get_lig_caretsOT::LigGlyph297 unsigned get_lig_carets (hb_font_t *font, 298 hb_direction_t direction, 299 hb_codepoint_t glyph_id, 300 const VariationStore &var_store, 301 unsigned start_offset, 302 unsigned *caret_count /* IN/OUT */, 303 hb_position_t *caret_array /* OUT */) const 304 { 305 if (caret_count) 306 { 307 + carets.sub_array (start_offset, caret_count) 308 | hb_map (hb_add (this)) 309 | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); }) 310 | hb_sink (hb_array (caret_array, *caret_count)) 311 ; 312 } 313 314 return carets.len; 315 } 316 subsetOT::LigGlyph317 bool subset (hb_subset_context_t *c) const 318 { 319 TRACE_SUBSET (this); 320 auto *out = c->serializer->start_embed (*this); 321 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 322 323 + hb_iter (carets) 324 | hb_apply (subset_offset_array (c, out->carets, this)) 325 ; 326 327 return_trace (bool (out->carets)); 328 } 329 collect_variation_indicesOT::LigGlyph330 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 331 { 332 for (const OffsetTo<CaretValue>& offset : carets.iter ()) 333 (this+offset).collect_variation_indices (c->layout_variation_indices); 334 } 335 sanitizeOT::LigGlyph336 bool sanitize (hb_sanitize_context_t *c) const 337 { 338 TRACE_SANITIZE (this); 339 return_trace (carets.sanitize (c, this)); 340 } 341 342 protected: 343 OffsetArrayOf<CaretValue> 344 carets; /* Offset array of CaretValue tables 345 * --from beginning of LigGlyph table 346 * --in increasing coordinate order */ 347 public: 348 DEFINE_SIZE_ARRAY (2, carets); 349 }; 350 351 struct LigCaretList 352 { get_lig_caretsOT::LigCaretList353 unsigned int get_lig_carets (hb_font_t *font, 354 hb_direction_t direction, 355 hb_codepoint_t glyph_id, 356 const VariationStore &var_store, 357 unsigned int start_offset, 358 unsigned int *caret_count /* IN/OUT */, 359 hb_position_t *caret_array /* OUT */) const 360 { 361 unsigned int index = (this+coverage).get_coverage (glyph_id); 362 if (index == NOT_COVERED) 363 { 364 if (caret_count) 365 *caret_count = 0; 366 return 0; 367 } 368 const LigGlyph &lig_glyph = this+ligGlyph[index]; 369 return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); 370 } 371 subsetOT::LigCaretList372 bool subset (hb_subset_context_t *c) const 373 { 374 TRACE_SUBSET (this); 375 const hb_set_t &glyphset = *c->plan->glyphset (); 376 const hb_map_t &glyph_map = *c->plan->glyph_map; 377 378 auto *out = c->serializer->start_embed (*this); 379 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 380 381 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 382 + hb_zip (this+coverage, ligGlyph) 383 | hb_filter (glyphset, hb_first) 384 | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) 385 | hb_map (hb_first) 386 | hb_map (glyph_map) 387 | hb_sink (new_coverage) 388 ; 389 out->coverage.serialize (c->serializer, out) 390 .serialize (c->serializer, new_coverage.iter ()); 391 return_trace (bool (new_coverage)); 392 } 393 collect_variation_indicesOT::LigCaretList394 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 395 { 396 + hb_zip (this+coverage, ligGlyph) 397 | hb_filter (c->glyph_set, hb_first) 398 | hb_map (hb_second) 399 | hb_map (hb_add (this)) 400 | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) 401 ; 402 } 403 sanitizeOT::LigCaretList404 bool sanitize (hb_sanitize_context_t *c) const 405 { 406 TRACE_SANITIZE (this); 407 return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); 408 } 409 410 protected: 411 OffsetTo<Coverage> 412 coverage; /* Offset to Coverage table--from 413 * beginning of LigCaretList table */ 414 OffsetArrayOf<LigGlyph> 415 ligGlyph; /* Array of LigGlyph tables 416 * in Coverage Index order */ 417 public: 418 DEFINE_SIZE_ARRAY (4, ligGlyph); 419 }; 420 421 422 struct MarkGlyphSetsFormat1 423 { coversOT::MarkGlyphSetsFormat1424 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 425 { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } 426 subsetOT::MarkGlyphSetsFormat1427 bool subset (hb_subset_context_t *c) const 428 { 429 TRACE_SUBSET (this); 430 auto *out = c->serializer->start_embed (*this); 431 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 432 out->format = format; 433 434 bool ret = true; 435 for (const LOffsetTo<Coverage>& offset : coverage.iter ()) 436 { 437 auto *o = out->coverage.serialize_append (c->serializer); 438 if (unlikely (!o)) 439 { 440 ret = false; 441 break; 442 } 443 444 //not using o->serialize_subset (c, offset, this, out) here because 445 //OTS doesn't allow null offset. 446 //See issue: https://github.com/khaledhosny/ots/issues/172 447 c->serializer->push (); 448 c->dispatch (this+offset); 449 c->serializer->add_link (*o, c->serializer->pop_pack ()); 450 } 451 452 return_trace (ret && out->coverage.len); 453 } 454 sanitizeOT::MarkGlyphSetsFormat1455 bool sanitize (hb_sanitize_context_t *c) const 456 { 457 TRACE_SANITIZE (this); 458 return_trace (coverage.sanitize (c, this)); 459 } 460 461 protected: 462 HBUINT16 format; /* Format identifier--format = 1 */ 463 ArrayOf<LOffsetTo<Coverage>> 464 coverage; /* Array of long offsets to mark set 465 * coverage tables */ 466 public: 467 DEFINE_SIZE_ARRAY (4, coverage); 468 }; 469 470 struct MarkGlyphSets 471 { coversOT::MarkGlyphSets472 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 473 { 474 switch (u.format) { 475 case 1: return u.format1.covers (set_index, glyph_id); 476 default:return false; 477 } 478 } 479 subsetOT::MarkGlyphSets480 bool subset (hb_subset_context_t *c) const 481 { 482 TRACE_SUBSET (this); 483 switch (u.format) { 484 case 1: return_trace (u.format1.subset (c)); 485 default:return_trace (false); 486 } 487 } 488 sanitizeOT::MarkGlyphSets489 bool sanitize (hb_sanitize_context_t *c) const 490 { 491 TRACE_SANITIZE (this); 492 if (!u.format.sanitize (c)) return_trace (false); 493 switch (u.format) { 494 case 1: return_trace (u.format1.sanitize (c)); 495 default:return_trace (true); 496 } 497 } 498 499 protected: 500 union { 501 HBUINT16 format; /* Format identifier */ 502 MarkGlyphSetsFormat1 format1; 503 } u; 504 public: 505 DEFINE_SIZE_UNION (2, format); 506 }; 507 508 509 /* 510 * GDEF -- Glyph Definition 511 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef 512 */ 513 514 515 struct GDEF 516 { 517 static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; 518 519 enum GlyphClasses { 520 UnclassifiedGlyph = 0, 521 BaseGlyph = 1, 522 LigatureGlyph = 2, 523 MarkGlyph = 3, 524 ComponentGlyph = 4 525 }; 526 has_dataOT::GDEF527 bool has_data () const { return version.to_int (); } has_glyph_classesOT::GDEF528 bool has_glyph_classes () const { return glyphClassDef != 0; } get_glyph_classOT::GDEF529 unsigned int get_glyph_class (hb_codepoint_t glyph) const 530 { return (this+glyphClassDef).get_class (glyph); } get_glyphs_in_classOT::GDEF531 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const 532 { (this+glyphClassDef).collect_class (glyphs, klass); } 533 has_mark_attachment_typesOT::GDEF534 bool has_mark_attachment_types () const { return markAttachClassDef != 0; } get_mark_attachment_typeOT::GDEF535 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const 536 { return (this+markAttachClassDef).get_class (glyph); } 537 has_attach_pointsOT::GDEF538 bool has_attach_points () const { return attachList != 0; } get_attach_pointsOT::GDEF539 unsigned int get_attach_points (hb_codepoint_t glyph_id, 540 unsigned int start_offset, 541 unsigned int *point_count /* IN/OUT */, 542 unsigned int *point_array /* OUT */) const 543 { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); } 544 has_lig_caretsOT::GDEF545 bool has_lig_carets () const { return ligCaretList != 0; } get_lig_caretsOT::GDEF546 unsigned int get_lig_carets (hb_font_t *font, 547 hb_direction_t direction, 548 hb_codepoint_t glyph_id, 549 unsigned int start_offset, 550 unsigned int *caret_count /* IN/OUT */, 551 hb_position_t *caret_array /* OUT */) const 552 { return (this+ligCaretList).get_lig_carets (font, 553 direction, glyph_id, get_var_store(), 554 start_offset, caret_count, caret_array); } 555 has_mark_setsOT::GDEF556 bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; } mark_set_coversOT::GDEF557 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const 558 { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); } 559 has_var_storeOT::GDEF560 bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; } get_var_storeOT::GDEF561 const VariationStore &get_var_store () const 562 { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); } 563 564 /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing 565 * glyph class and other bits, and high 8-bit the mark attachment type (if any). 566 * Not to be confused with lookup_props which is very similar. */ get_glyph_propsOT::GDEF567 unsigned int get_glyph_props (hb_codepoint_t glyph) const 568 { 569 unsigned int klass = get_glyph_class (glyph); 570 571 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); 572 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); 573 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); 574 575 switch (klass) { 576 default: return 0; 577 case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; 578 case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 579 case MarkGlyph: 580 klass = get_mark_attachment_type (glyph); 581 return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); 582 } 583 } 584 585 HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, 586 hb_face_t *face) const; 587 588 struct accelerator_t 589 { initOT::GDEF::accelerator_t590 void init (hb_face_t *face) 591 { 592 this->table = hb_sanitize_context_t ().reference_table<GDEF> (face); 593 if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) 594 { 595 hb_blob_destroy (this->table.get_blob ()); 596 this->table = hb_blob_get_empty (); 597 } 598 } 599 finiOT::GDEF::accelerator_t600 void fini () { this->table.destroy (); } 601 602 hb_blob_ptr_t<GDEF> table; 603 }; 604 get_sizeOT::GDEF605 unsigned int get_size () const 606 { 607 return min_size + 608 (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + 609 (version.to_int () >= 0x00010003u ? varStore.static_size : 0); 610 } 611 collect_variation_indicesOT::GDEF612 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const 613 { (this+ligCaretList).collect_variation_indices (c); } 614 remap_layout_variation_indicesOT::GDEF615 void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, 616 hb_map_t *layout_variation_idx_map /* OUT */) const 617 { 618 if (version.to_int () < 0x00010003u || !varStore) return; 619 if (layout_variation_indices->is_empty ()) return; 620 621 unsigned new_major = 0, new_minor = 0; 622 unsigned last_major = (layout_variation_indices->get_min ()) >> 16; 623 for (unsigned idx : layout_variation_indices->iter ()) 624 { 625 uint16_t major = idx >> 16; 626 if (major >= (this+varStore).get_sub_table_count ()) break; 627 if (major != last_major) 628 { 629 new_minor = 0; 630 ++new_major; 631 } 632 633 unsigned new_idx = (new_major << 16) + new_minor; 634 layout_variation_idx_map->set (idx, new_idx); 635 ++new_minor; 636 last_major = major; 637 } 638 } 639 subsetOT::GDEF640 bool subset (hb_subset_context_t *c) const 641 { 642 TRACE_SUBSET (this); 643 auto *out = c->serializer->embed (*this); 644 if (unlikely (!out)) return_trace (false); 645 646 bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this); 647 bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); 648 bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); 649 bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this); 650 651 bool subset_markglyphsetsdef = true; 652 if (version.to_int () >= 0x00010002u) 653 { 654 subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); 655 if (!subset_markglyphsetsdef && 656 version.to_int () == 0x00010002u) 657 out->version.minor = 0; 658 } 659 660 bool subset_varstore = true; 661 if (version.to_int () >= 0x00010003u) 662 { 663 subset_varstore = out->varStore.serialize_subset (c, varStore, this); 664 if (!subset_varstore && version.to_int () == 0x00010003u) 665 out->version.minor = 2; 666 } 667 668 return_trace (subset_glyphclassdef || subset_attachlist || 669 subset_ligcaretlist || subset_markattachclassdef || 670 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || 671 (out->version.to_int () >= 0x00010003u && subset_varstore)); 672 } 673 sanitizeOT::GDEF674 bool sanitize (hb_sanitize_context_t *c) const 675 { 676 TRACE_SANITIZE (this); 677 return_trace (version.sanitize (c) && 678 likely (version.major == 1) && 679 glyphClassDef.sanitize (c, this) && 680 attachList.sanitize (c, this) && 681 ligCaretList.sanitize (c, this) && 682 markAttachClassDef.sanitize (c, this) && 683 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && 684 (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); 685 } 686 687 protected: 688 FixedVersion<>version; /* Version of the GDEF table--currently 689 * 0x00010003u */ 690 OffsetTo<ClassDef> 691 glyphClassDef; /* Offset to class definition table 692 * for glyph type--from beginning of 693 * GDEF header (may be Null) */ 694 OffsetTo<AttachList> 695 attachList; /* Offset to list of glyphs with 696 * attachment points--from beginning 697 * of GDEF header (may be Null) */ 698 OffsetTo<LigCaretList> 699 ligCaretList; /* Offset to list of positioning points 700 * for ligature carets--from beginning 701 * of GDEF header (may be Null) */ 702 OffsetTo<ClassDef> 703 markAttachClassDef; /* Offset to class definition table for 704 * mark attachment type--from beginning 705 * of GDEF header (may be Null) */ 706 OffsetTo<MarkGlyphSets> 707 markGlyphSetsDef; /* Offset to the table of mark set 708 * definitions--from beginning of GDEF 709 * header (may be NULL). Introduced 710 * in version 0x00010002. */ 711 LOffsetTo<VariationStore> 712 varStore; /* Offset to the table of Item Variation 713 * Store--from beginning of GDEF 714 * header (may be NULL). Introduced 715 * in version 0x00010003. */ 716 public: 717 DEFINE_SIZE_MIN (12); 718 }; 719 720 struct GDEF_accelerator_t : GDEF::accelerator_t {}; 721 722 } /* namespace OT */ 723 724 725 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */ 726