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
37namespace OT {
38
39
40/*
41 * Attachment List Table
42 */
43
44/* Array of contour point indices--in increasing numerical order */
45struct AttachPoint : ArrayOf<HBUINT16>
46{
47 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
57struct AttachList
58{
59 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
84 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
106 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
127struct CaretValueFormat1
128{
129 friend struct CaretValue;
130 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:
139 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
144 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
157struct CaretValueFormat2
158{
159 friend struct CaretValue;
160 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:
169 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
176 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
189struct CaretValueFormat3
190{
191 friend struct CaretValue;
192
193 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
201 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
211 void collect_variation_indices (hb_set_t *layout_variation_indices) const
212 { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
213
214 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
231struct CaretValue
232{
233 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>
247 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
259 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
272 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
295struct LigGlyph
296{
297 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
317 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
330 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
336 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
351struct LigCaretList
352{
353 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
372 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
394 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
404 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
422struct MarkGlyphSetsFormat1
423{
424 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
427 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
455 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
470struct MarkGlyphSets
471{
472 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
480 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
489 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
515struct 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
527 bool has_data () const { return version.to_int (); }
528 bool has_glyph_classes () const { return glyphClassDef != 0; }
529 unsigned int get_glyph_class (hb_codepoint_t glyph) const
530 { return (this+glyphClassDef).get_class (glyph); }
531 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
532 { (this+glyphClassDef).collect_class (glyphs, klass); }
533
534 bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
535 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
536 { return (this+markAttachClassDef).get_class (glyph); }
537
538 bool has_attach_points () const { return attachList != 0; }
539 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
545 bool has_lig_carets () const { return ligCaretList != 0; }
546 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
556 bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
557 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
560 bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
561 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. */
567 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 {
590 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
600 void fini () { this->table.destroy (); }
601
602 hb_blob_ptr_t<GDEF> table;
603 };
604
605 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
612 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
613 { (this+ligCaretList).collect_variation_indices (c); }
614
615 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
640 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
674 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
720struct GDEF_accelerator_t : GDEF::accelerator_t {};
721
722} /* namespace OT */
723
724
725#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
726