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