comparison mupdf-source/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh @ 2:b50eed0cc0ef upstream

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