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 typedef ArrayOf<HBUINT16> AttachPoint; /* Array of contour point indices--in 45 * increasing numerical order */ 46 47 struct AttachList 48 { get_attach_pointsOT::AttachList49 unsigned int get_attach_points (hb_codepoint_t glyph_id, 50 unsigned int start_offset, 51 unsigned int *point_count /* IN/OUT */, 52 unsigned int *point_array /* OUT */) const 53 { 54 unsigned int index = (this+coverage).get_coverage (glyph_id); 55 if (index == NOT_COVERED) 56 { 57 if (point_count) 58 *point_count = 0; 59 return 0; 60 } 61 62 const AttachPoint &points = this+attachPoint[index]; 63 64 if (point_count) 65 { 66 hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count); 67 unsigned int count = array.length; 68 for (unsigned int i = 0; i < count; i++) 69 point_array[i] = array[i]; 70 } 71 72 return points.len; 73 } 74 sanitizeOT::AttachList75 bool sanitize (hb_sanitize_context_t *c) const 76 { 77 TRACE_SANITIZE (this); 78 return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); 79 } 80 81 protected: 82 OffsetTo<Coverage> 83 coverage; /* Offset to Coverage table -- from 84 * beginning of AttachList table */ 85 OffsetArrayOf<AttachPoint> 86 attachPoint; /* Array of AttachPoint tables 87 * in Coverage Index order */ 88 public: 89 DEFINE_SIZE_ARRAY (4, attachPoint); 90 }; 91 92 /* 93 * Ligature Caret Table 94 */ 95 96 struct CaretValueFormat1 97 { 98 friend struct CaretValue; subsetOT::CaretValueFormat199 bool subset (hb_subset_context_t *c) const 100 { 101 TRACE_SUBSET (this); 102 auto *out = c->serializer->embed (this); 103 if (unlikely (!out)) return_trace (false); 104 return_trace (true); 105 } 106 107 private: get_caret_valueOT::CaretValueFormat1108 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const 109 { 110 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); 111 } 112 sanitizeOT::CaretValueFormat1113 bool sanitize (hb_sanitize_context_t *c) const 114 { 115 TRACE_SANITIZE (this); 116 return_trace (c->check_struct (this)); 117 } 118 119 protected: 120 HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ 121 FWORD coordinate; /* X or Y value, in design units */ 122 public: 123 DEFINE_SIZE_STATIC (4); 124 }; 125 126 struct CaretValueFormat2 127 { 128 friend struct CaretValue; subsetOT::CaretValueFormat2129 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::CaretValueFormat2138 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const 139 { 140 hb_position_t x, y; 141 font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); 142 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; 143 } 144 sanitizeOT::CaretValueFormat2145 bool sanitize (hb_sanitize_context_t *c) const 146 { 147 TRACE_SANITIZE (this); 148 return_trace (c->check_struct (this)); 149 } 150 151 protected: 152 HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ 153 HBUINT16 caretValuePoint; /* Contour point index on glyph */ 154 public: 155 DEFINE_SIZE_STATIC (4); 156 }; 157 158 struct CaretValueFormat3 159 { 160 friend struct CaretValue; 161 get_caret_valueOT::CaretValueFormat3162 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, 163 const VariationStore &var_store) const 164 { 165 return HB_DIRECTION_IS_HORIZONTAL (direction) ? 166 font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : 167 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); 168 } 169 subsetOT::CaretValueFormat3170 bool subset (hb_subset_context_t *c) const 171 { 172 TRACE_SUBSET (this); 173 auto *out = c->serializer->embed (this); 174 if (unlikely (!out)) return_trace (false); 175 176 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this)); 177 } 178 sanitizeOT::CaretValueFormat3179 bool sanitize (hb_sanitize_context_t *c) const 180 { 181 TRACE_SANITIZE (this); 182 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); 183 } 184 185 protected: 186 HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ 187 FWORD coordinate; /* X or Y value, in design units */ 188 OffsetTo<Device> 189 deviceTable; /* Offset to Device table for X or Y 190 * value--from beginning of CaretValue 191 * table */ 192 public: 193 DEFINE_SIZE_STATIC (6); 194 }; 195 196 struct CaretValue 197 { get_caret_valueOT::CaretValue198 hb_position_t get_caret_value (hb_font_t *font, 199 hb_direction_t direction, 200 hb_codepoint_t glyph_id, 201 const VariationStore &var_store) const 202 { 203 switch (u.format) { 204 case 1: return u.format1.get_caret_value (font, direction); 205 case 2: return u.format2.get_caret_value (font, direction, glyph_id); 206 case 3: return u.format3.get_caret_value (font, direction, var_store); 207 default:return 0; 208 } 209 } 210 211 template <typename context_t, typename ...Ts> dispatchOT::CaretValue212 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 213 { 214 TRACE_DISPATCH (this, u.format); 215 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 216 switch (u.format) { 217 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...)); 218 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...)); 219 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...)); 220 default:return_trace (c->default_return_value ()); 221 } 222 } 223 sanitizeOT::CaretValue224 bool sanitize (hb_sanitize_context_t *c) const 225 { 226 TRACE_SANITIZE (this); 227 if (!u.format.sanitize (c)) return_trace (false); 228 switch (u.format) { 229 case 1: return_trace (u.format1.sanitize (c)); 230 case 2: return_trace (u.format2.sanitize (c)); 231 case 3: return_trace (u.format3.sanitize (c)); 232 default:return_trace (true); 233 } 234 } 235 236 protected: 237 union { 238 HBUINT16 format; /* Format identifier */ 239 CaretValueFormat1 format1; 240 CaretValueFormat2 format2; 241 CaretValueFormat3 format3; 242 } u; 243 public: 244 DEFINE_SIZE_UNION (2, format); 245 }; 246 247 struct LigGlyph 248 { get_lig_caretsOT::LigGlyph249 unsigned int get_lig_carets (hb_font_t *font, 250 hb_direction_t direction, 251 hb_codepoint_t glyph_id, 252 const VariationStore &var_store, 253 unsigned int start_offset, 254 unsigned int *caret_count /* IN/OUT */, 255 hb_position_t *caret_array /* OUT */) const 256 { 257 if (caret_count) 258 { 259 hb_array_t <const OffsetTo<CaretValue>> array = carets.sub_array (start_offset, caret_count); 260 unsigned int count = array.length; 261 for (unsigned int i = 0; i < count; i++) 262 caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store); 263 } 264 265 return carets.len; 266 } 267 subsetOT::LigGlyph268 bool subset (hb_subset_context_t *c) const 269 { 270 TRACE_SUBSET (this); 271 auto *out = c->serializer->start_embed (*this); 272 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 273 274 + hb_iter (carets) 275 | hb_apply (subset_offset_array (c, out->carets, this)) 276 ; 277 278 return_trace (bool (out->carets)); 279 } 280 sanitizeOT::LigGlyph281 bool sanitize (hb_sanitize_context_t *c) const 282 { 283 TRACE_SANITIZE (this); 284 return_trace (carets.sanitize (c, this)); 285 } 286 287 protected: 288 OffsetArrayOf<CaretValue> 289 carets; /* Offset array of CaretValue tables 290 * --from beginning of LigGlyph table 291 * --in increasing coordinate order */ 292 public: 293 DEFINE_SIZE_ARRAY (2, carets); 294 }; 295 296 struct LigCaretList 297 { get_lig_caretsOT::LigCaretList298 unsigned int get_lig_carets (hb_font_t *font, 299 hb_direction_t direction, 300 hb_codepoint_t glyph_id, 301 const VariationStore &var_store, 302 unsigned int start_offset, 303 unsigned int *caret_count /* IN/OUT */, 304 hb_position_t *caret_array /* OUT */) const 305 { 306 unsigned int index = (this+coverage).get_coverage (glyph_id); 307 if (index == NOT_COVERED) 308 { 309 if (caret_count) 310 *caret_count = 0; 311 return 0; 312 } 313 const LigGlyph &lig_glyph = this+ligGlyph[index]; 314 return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); 315 } 316 subsetOT::LigCaretList317 bool subset (hb_subset_context_t *c) const 318 { 319 TRACE_SUBSET (this); 320 const hb_set_t &glyphset = *c->plan->glyphset (); 321 const hb_map_t &glyph_map = *c->plan->glyph_map; 322 323 auto *out = c->serializer->start_embed (*this); 324 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 325 326 hb_sorted_vector_t<hb_codepoint_t> new_coverage; 327 + hb_zip (this+coverage, ligGlyph) 328 | hb_filter (glyphset, hb_first) 329 | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) 330 | hb_map (hb_first) 331 | hb_map (glyph_map) 332 | hb_sink (new_coverage) 333 ; 334 out->coverage.serialize (c->serializer, out) 335 .serialize (c->serializer, new_coverage.iter ()); 336 return_trace (bool (new_coverage)); 337 } 338 sanitizeOT::LigCaretList339 bool sanitize (hb_sanitize_context_t *c) const 340 { 341 TRACE_SANITIZE (this); 342 return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); 343 } 344 345 protected: 346 OffsetTo<Coverage> 347 coverage; /* Offset to Coverage table--from 348 * beginning of LigCaretList table */ 349 OffsetArrayOf<LigGlyph> 350 ligGlyph; /* Array of LigGlyph tables 351 * in Coverage Index order */ 352 public: 353 DEFINE_SIZE_ARRAY (4, ligGlyph); 354 }; 355 356 357 struct MarkGlyphSetsFormat1 358 { coversOT::MarkGlyphSetsFormat1359 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 360 { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } 361 subsetOT::MarkGlyphSetsFormat1362 bool subset (hb_subset_context_t *c) const 363 { 364 TRACE_SUBSET (this); 365 auto *out = c->serializer->start_embed (*this); 366 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 367 out->format = format; 368 369 bool ret = true; 370 for (const LOffsetTo<Coverage>& offset : coverage.iter ()) 371 { 372 auto *o = out->coverage.serialize_append (c->serializer); 373 if (unlikely (!o)) 374 { 375 ret = false; 376 break; 377 } 378 379 //not using o->serialize_subset (c, offset, this, out) here because 380 //OTS doesn't allow null offset. 381 //See issue: https://github.com/khaledhosny/ots/issues/172 382 c->serializer->push (); 383 c->dispatch (this+offset); 384 c->serializer->add_link (*o, c->serializer->pop_pack ()); 385 } 386 387 return_trace (ret && out->coverage.len); 388 } 389 sanitizeOT::MarkGlyphSetsFormat1390 bool sanitize (hb_sanitize_context_t *c) const 391 { 392 TRACE_SANITIZE (this); 393 return_trace (coverage.sanitize (c, this)); 394 } 395 396 protected: 397 HBUINT16 format; /* Format identifier--format = 1 */ 398 ArrayOf<LOffsetTo<Coverage>> 399 coverage; /* Array of long offsets to mark set 400 * coverage tables */ 401 public: 402 DEFINE_SIZE_ARRAY (4, coverage); 403 }; 404 405 struct MarkGlyphSets 406 { coversOT::MarkGlyphSets407 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const 408 { 409 switch (u.format) { 410 case 1: return u.format1.covers (set_index, glyph_id); 411 default:return false; 412 } 413 } 414 subsetOT::MarkGlyphSets415 bool subset (hb_subset_context_t *c) const 416 { 417 TRACE_SUBSET (this); 418 switch (u.format) { 419 case 1: return_trace (u.format1.subset (c)); 420 default:return_trace (false); 421 } 422 } 423 sanitizeOT::MarkGlyphSets424 bool sanitize (hb_sanitize_context_t *c) const 425 { 426 TRACE_SANITIZE (this); 427 if (!u.format.sanitize (c)) return_trace (false); 428 switch (u.format) { 429 case 1: return_trace (u.format1.sanitize (c)); 430 default:return_trace (true); 431 } 432 } 433 434 protected: 435 union { 436 HBUINT16 format; /* Format identifier */ 437 MarkGlyphSetsFormat1 format1; 438 } u; 439 public: 440 DEFINE_SIZE_UNION (2, format); 441 }; 442 443 444 /* 445 * GDEF -- Glyph Definition 446 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef 447 */ 448 449 450 struct GDEF 451 { 452 static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; 453 454 enum GlyphClasses { 455 UnclassifiedGlyph = 0, 456 BaseGlyph = 1, 457 LigatureGlyph = 2, 458 MarkGlyph = 3, 459 ComponentGlyph = 4 460 }; 461 has_dataOT::GDEF462 bool has_data () const { return version.to_int (); } has_glyph_classesOT::GDEF463 bool has_glyph_classes () const { return glyphClassDef != 0; } get_glyph_classOT::GDEF464 unsigned int get_glyph_class (hb_codepoint_t glyph) const 465 { return (this+glyphClassDef).get_class (glyph); } get_glyphs_in_classOT::GDEF466 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const 467 { (this+glyphClassDef).add_class (glyphs, klass); } 468 has_mark_attachment_typesOT::GDEF469 bool has_mark_attachment_types () const { return markAttachClassDef != 0; } get_mark_attachment_typeOT::GDEF470 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const 471 { return (this+markAttachClassDef).get_class (glyph); } 472 has_attach_pointsOT::GDEF473 bool has_attach_points () const { return attachList != 0; } get_attach_pointsOT::GDEF474 unsigned int get_attach_points (hb_codepoint_t glyph_id, 475 unsigned int start_offset, 476 unsigned int *point_count /* IN/OUT */, 477 unsigned int *point_array /* OUT */) const 478 { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); } 479 has_lig_caretsOT::GDEF480 bool has_lig_carets () const { return ligCaretList != 0; } get_lig_caretsOT::GDEF481 unsigned int get_lig_carets (hb_font_t *font, 482 hb_direction_t direction, 483 hb_codepoint_t glyph_id, 484 unsigned int start_offset, 485 unsigned int *caret_count /* IN/OUT */, 486 hb_position_t *caret_array /* OUT */) const 487 { return (this+ligCaretList).get_lig_carets (font, 488 direction, glyph_id, get_var_store(), 489 start_offset, caret_count, caret_array); } 490 has_mark_setsOT::GDEF491 bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; } mark_set_coversOT::GDEF492 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const 493 { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); } 494 has_var_storeOT::GDEF495 bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; } get_var_storeOT::GDEF496 const VariationStore &get_var_store () const 497 { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); } 498 499 /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing 500 * glyph class and other bits, and high 8-bit the mark attachment type (if any). 501 * Not to be confused with lookup_props which is very similar. */ get_glyph_propsOT::GDEF502 unsigned int get_glyph_props (hb_codepoint_t glyph) const 503 { 504 unsigned int klass = get_glyph_class (glyph); 505 506 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); 507 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); 508 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); 509 510 switch (klass) { 511 default: return 0; 512 case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; 513 case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 514 case MarkGlyph: 515 klass = get_mark_attachment_type (glyph); 516 return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); 517 } 518 } 519 520 HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, 521 hb_face_t *face) const; 522 523 struct accelerator_t 524 { initOT::GDEF::accelerator_t525 void init (hb_face_t *face) 526 { 527 this->table = hb_sanitize_context_t ().reference_table<GDEF> (face); 528 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face))) 529 { 530 hb_blob_destroy (this->table.get_blob ()); 531 this->table = hb_blob_get_empty (); 532 } 533 } 534 finiOT::GDEF::accelerator_t535 void fini () { this->table.destroy (); } 536 537 hb_blob_ptr_t<GDEF> table; 538 }; 539 get_sizeOT::GDEF540 unsigned int get_size () const 541 { 542 return min_size + 543 (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + 544 (version.to_int () >= 0x00010003u ? varStore.static_size : 0); 545 } 546 subsetOT::GDEF547 bool subset (hb_subset_context_t *c) const 548 { 549 TRACE_SUBSET (this); 550 auto *out = c->serializer->embed (*this); 551 if (unlikely (!out)) return_trace (false); 552 553 out->glyphClassDef.serialize_subset (c, glyphClassDef, this); 554 out->attachList = 0;//TODO(subset) serialize_subset (c, attachList, this); 555 out->ligCaretList.serialize_subset (c, ligCaretList, this); 556 out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this); 557 558 if (version.to_int () >= 0x00010002u) 559 { 560 if (!out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this) && 561 version.to_int () == 0x00010002u) 562 out->version.minor = 0; 563 } 564 565 if (version.to_int () >= 0x00010003u) 566 out->varStore = 0;// TODO(subset) serialize_subset (c, varStore, this); 567 568 return_trace (true); 569 } 570 sanitizeOT::GDEF571 bool sanitize (hb_sanitize_context_t *c) const 572 { 573 TRACE_SANITIZE (this); 574 return_trace (version.sanitize (c) && 575 likely (version.major == 1) && 576 glyphClassDef.sanitize (c, this) && 577 attachList.sanitize (c, this) && 578 ligCaretList.sanitize (c, this) && 579 markAttachClassDef.sanitize (c, this) && 580 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && 581 (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); 582 } 583 584 protected: 585 FixedVersion<>version; /* Version of the GDEF table--currently 586 * 0x00010003u */ 587 OffsetTo<ClassDef> 588 glyphClassDef; /* Offset to class definition table 589 * for glyph type--from beginning of 590 * GDEF header (may be Null) */ 591 OffsetTo<AttachList> 592 attachList; /* Offset to list of glyphs with 593 * attachment points--from beginning 594 * of GDEF header (may be Null) */ 595 OffsetTo<LigCaretList> 596 ligCaretList; /* Offset to list of positioning points 597 * for ligature carets--from beginning 598 * of GDEF header (may be Null) */ 599 OffsetTo<ClassDef> 600 markAttachClassDef; /* Offset to class definition table for 601 * mark attachment type--from beginning 602 * of GDEF header (may be Null) */ 603 OffsetTo<MarkGlyphSets> 604 markGlyphSetsDef; /* Offset to the table of mark set 605 * definitions--from beginning of GDEF 606 * header (may be NULL). Introduced 607 * in version 0x00010002. */ 608 LOffsetTo<VariationStore> 609 varStore; /* Offset to the table of Item Variation 610 * Store--from beginning of GDEF 611 * header (may be NULL). Introduced 612 * in version 0x00010003. */ 613 public: 614 DEFINE_SIZE_MIN (12); 615 }; 616 617 struct GDEF_accelerator_t : GDEF::accelerator_t {}; 618 619 } /* namespace OT */ 620 621 622 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */ 623