xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Layout/GDEF/GDEF.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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-var-common.hh"
33 
34 #include "../../../hb-font.hh"
35 #include "../../../hb-cache.hh"
36 
37 
38 namespace OT {
39 
40 
41 /*
42  * Attachment List Table
43  */
44 
45 /* Array of contour point indices--in increasing numerical order */
46 struct AttachPoint : Array16Of<HBUINT16>
47 {
subsetOT::AttachPoint48   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 
56 struct AttachList
57 {
get_attach_pointsOT::AttachList58   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 
subsetOT::AttachList83   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 
sanitizeOT::AttachList104   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 
125 struct CaretValueFormat1
126 {
127   friend struct CaretValue;
subsetOT::CaretValueFormat1128   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:
get_caret_valueOT::CaretValueFormat1137   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 
sanitizeOT::CaretValueFormat1142   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 
155 struct CaretValueFormat2
156 {
157   friend struct CaretValue;
subsetOT::CaretValueFormat2158   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:
get_caret_valueOT::CaretValueFormat2167   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 
sanitizeOT::CaretValueFormat2174   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 
187 struct CaretValueFormat3
188 {
189   friend struct CaretValue;
190 
get_caret_valueOT::CaretValueFormat3191   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
192 				 const ItemVariationStore &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 
subsetOT::CaretValueFormat3199   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     hb_pair_t<unsigned, int> *new_varidx_delta;
208     if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
209       return_trace (false);
210 
211     uint32_t new_varidx = hb_first (*new_varidx_delta);
212     int delta = hb_second (*new_varidx_delta);
213     if (delta != 0)
214     {
215       if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
216         return_trace (false);
217     }
218 
219     if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
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 
collect_variation_indicesOT::CaretValueFormat3229   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
230   { (this+deviceTable).collect_variation_indices (c); }
231 
sanitizeOT::CaretValueFormat3232   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 {
get_caret_valueOT::CaretValue251   hb_position_t get_caret_value (hb_font_t *font,
252 				 hb_direction_t direction,
253 				 hb_codepoint_t glyph_id,
254 				 const ItemVariationStore &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>
dispatchOT::CaretValue265   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
266   {
267     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
268     TRACE_DISPATCH (this, u.format);
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 
collect_variation_indicesOT::CaretValue277   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 
sanitizeOT::CaretValue290   bool sanitize (hb_sanitize_context_t *c) const
291   {
292     TRACE_SANITIZE (this);
293     if (!u.format.sanitize (c)) return_trace (false);
294     hb_barrier ();
295     switch (u.format) {
296     case 1: return_trace (u.format1.sanitize (c));
297     case 2: return_trace (u.format2.sanitize (c));
298     case 3: return_trace (u.format3.sanitize (c));
299     default:return_trace (true);
300     }
301   }
302 
303   protected:
304   union {
305   HBUINT16		format;		/* Format identifier */
306   CaretValueFormat1	format1;
307   CaretValueFormat2	format2;
308   CaretValueFormat3	format3;
309   } u;
310   public:
311   DEFINE_SIZE_UNION (2, format);
312 };
313 
314 struct LigGlyph
315 {
get_lig_caretsOT::LigGlyph316   unsigned get_lig_carets (hb_font_t            *font,
317 			   hb_direction_t        direction,
318 			   hb_codepoint_t        glyph_id,
319 			   const ItemVariationStore &var_store,
320 			   unsigned              start_offset,
321 			   unsigned             *caret_count /* IN/OUT */,
322 			   hb_position_t        *caret_array /* OUT */) const
323   {
324     if (caret_count)
325     {
326       + carets.as_array ().sub_array (start_offset, caret_count)
327       | hb_map (hb_add (this))
328       | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
329       | hb_sink (hb_array (caret_array, *caret_count))
330       ;
331     }
332 
333     return carets.len;
334   }
335 
subsetOT::LigGlyph336   bool subset (hb_subset_context_t *c) const
337   {
338     TRACE_SUBSET (this);
339     auto *out = c->serializer->start_embed (*this);
340     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
341 
342     + hb_iter (carets)
343     | hb_apply (subset_offset_array (c, out->carets, this))
344     ;
345 
346     return_trace (bool (out->carets));
347   }
348 
collect_variation_indicesOT::LigGlyph349   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
350   {
351     for (const Offset16To<CaretValue>& offset : carets.iter ())
352       (this+offset).collect_variation_indices (c);
353   }
354 
sanitizeOT::LigGlyph355   bool sanitize (hb_sanitize_context_t *c) const
356   {
357     TRACE_SANITIZE (this);
358     return_trace (carets.sanitize (c, this));
359   }
360 
361   protected:
362   Array16OfOffset16To<CaretValue>
363 		carets;			/* Offset array of CaretValue tables
364 					 * --from beginning of LigGlyph table
365 					 * --in increasing coordinate order */
366   public:
367   DEFINE_SIZE_ARRAY (2, carets);
368 };
369 
370 struct LigCaretList
371 {
get_lig_caretsOT::LigCaretList372   unsigned int get_lig_carets (hb_font_t *font,
373 			       hb_direction_t direction,
374 			       hb_codepoint_t glyph_id,
375 			       const ItemVariationStore &var_store,
376 			       unsigned int start_offset,
377 			       unsigned int *caret_count /* IN/OUT */,
378 			       hb_position_t *caret_array /* OUT */) const
379   {
380     unsigned int index = (this+coverage).get_coverage (glyph_id);
381     if (index == NOT_COVERED)
382     {
383       if (caret_count)
384 	*caret_count = 0;
385       return 0;
386     }
387     const LigGlyph &lig_glyph = this+ligGlyph[index];
388     return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
389   }
390 
subsetOT::LigCaretList391   bool subset (hb_subset_context_t *c) const
392   {
393     TRACE_SUBSET (this);
394     const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
395     const hb_map_t &glyph_map = *c->plan->glyph_map;
396 
397     auto *out = c->serializer->start_embed (*this);
398     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
399 
400     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
401     + hb_zip (this+coverage, ligGlyph)
402     | hb_filter (glyphset, hb_first)
403     | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
404     | hb_map (hb_first)
405     | hb_map (glyph_map)
406     | hb_sink (new_coverage)
407     ;
408     out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
409     return_trace (bool (new_coverage));
410   }
411 
collect_variation_indicesOT::LigCaretList412   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
413   {
414     + hb_zip (this+coverage, ligGlyph)
415     | hb_filter (c->glyph_set, hb_first)
416     | hb_map (hb_second)
417     | hb_map (hb_add (this))
418     | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
419     ;
420   }
421 
sanitizeOT::LigCaretList422   bool sanitize (hb_sanitize_context_t *c) const
423   {
424     TRACE_SANITIZE (this);
425     return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
426   }
427 
428   protected:
429   Offset16To<Coverage>
430 		coverage;		/* Offset to Coverage table--from
431 					 * beginning of LigCaretList table */
432   Array16OfOffset16To<LigGlyph>
433 		ligGlyph;		/* Array of LigGlyph tables
434 					 * in Coverage Index order */
435   public:
436   DEFINE_SIZE_ARRAY (4, ligGlyph);
437 };
438 
439 
440 struct MarkGlyphSetsFormat1
441 {
coversOT::MarkGlyphSetsFormat1442   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
443   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
444 
collect_used_mark_setsOT::MarkGlyphSetsFormat1445   void collect_used_mark_sets (const hb_set_t& glyph_set,
446                                hb_set_t& used_mark_sets /* OUT */) const
447   {
448     unsigned i = 0;
449     for (const auto &offset : coverage)
450      {
451        const auto &cov = this+offset;
452        if (cov.intersects (&glyph_set))
453          used_mark_sets.add (i);
454 
455        i++;
456      }
457   }
458 
459   template <typename set_t>
collect_coverageOT::MarkGlyphSetsFormat1460   void collect_coverage (hb_vector_t<set_t> &sets) const
461   {
462      for (const auto &offset : coverage)
463      {
464        const auto &cov = this+offset;
465        cov.collect_coverage (sets.push ());
466      }
467   }
468 
subsetOT::MarkGlyphSetsFormat1469   bool subset (hb_subset_context_t *c) const
470   {
471     TRACE_SUBSET (this);
472     auto *out = c->serializer->start_embed (*this);
473     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
474     out->format = format;
475 
476     bool ret = true;
477     for (const Offset32To<Coverage>& offset : coverage.iter ())
478     {
479       auto snap = c->serializer->snapshot ();
480       auto *o = out->coverage.serialize_append (c->serializer);
481       if (unlikely (!o))
482       {
483 	ret = false;
484 	break;
485       }
486 
487       //skip empty coverage
488       c->serializer->push ();
489       bool res = false;
490       if (offset) res = c->dispatch (this+offset);
491       if (!res)
492       {
493         c->serializer->pop_discard ();
494         c->serializer->revert (snap);
495         (out->coverage.len)--;
496         continue;
497       }
498       c->serializer->add_link (*o, c->serializer->pop_pack ());
499     }
500 
501     return_trace (ret && out->coverage.len);
502   }
503 
sanitizeOT::MarkGlyphSetsFormat1504   bool sanitize (hb_sanitize_context_t *c) const
505   {
506     TRACE_SANITIZE (this);
507     return_trace (coverage.sanitize (c, this));
508   }
509 
510   protected:
511   HBUINT16	format;			/* Format identifier--format = 1 */
512   Array16Of<Offset32To<Coverage>>
513 		coverage;		/* Array of long offsets to mark set
514 					 * coverage tables */
515   public:
516   DEFINE_SIZE_ARRAY (4, coverage);
517 };
518 
519 struct MarkGlyphSets
520 {
coversOT::MarkGlyphSets521   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
522   {
523     switch (u.format) {
524     case 1: return u.format1.covers (set_index, glyph_id);
525     default:return false;
526     }
527   }
528 
529   template <typename set_t>
collect_coverageOT::MarkGlyphSets530   void collect_coverage (hb_vector_t<set_t> &sets) const
531   {
532     switch (u.format) {
533     case 1: u.format1.collect_coverage (sets); return;
534     default:return;
535     }
536   }
537 
collect_used_mark_setsOT::MarkGlyphSets538   void collect_used_mark_sets (const hb_set_t& glyph_set,
539                                hb_set_t& used_mark_sets /* OUT */) const
540   {
541     switch (u.format) {
542     case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
543     default:return;
544     }
545   }
546 
subsetOT::MarkGlyphSets547   bool subset (hb_subset_context_t *c) const
548   {
549     TRACE_SUBSET (this);
550     switch (u.format) {
551     case 1: return_trace (u.format1.subset (c));
552     default:return_trace (false);
553     }
554   }
555 
sanitizeOT::MarkGlyphSets556   bool sanitize (hb_sanitize_context_t *c) const
557   {
558     TRACE_SANITIZE (this);
559     if (!u.format.sanitize (c)) return_trace (false);
560     hb_barrier ();
561     switch (u.format) {
562     case 1: return_trace (u.format1.sanitize (c));
563     default:return_trace (true);
564     }
565   }
566 
567   protected:
568   union {
569   HBUINT16		format;		/* Format identifier */
570   MarkGlyphSetsFormat1	format1;
571   } u;
572   public:
573   DEFINE_SIZE_UNION (2, format);
574 };
575 
576 
577 /*
578  * GDEF -- Glyph Definition
579  * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
580  */
581 
582 
583 template <typename Types>
584 struct GDEFVersion1_2
585 {
586   friend struct GDEF;
587 
588   protected:
589   FixedVersion<>version;		/* Version of the GDEF table--currently
590 					 * 0x00010003u */
591   typename Types::template OffsetTo<ClassDef>
592 		glyphClassDef;		/* Offset to class definition table
593 					 * for glyph type--from beginning of
594 					 * GDEF header (may be Null) */
595   typename Types::template OffsetTo<AttachList>
596 		attachList;		/* Offset to list of glyphs with
597 					 * attachment points--from beginning
598 					 * of GDEF header (may be Null) */
599   typename Types::template OffsetTo<LigCaretList>
600 		ligCaretList;		/* Offset to list of positioning points
601 					 * for ligature carets--from beginning
602 					 * of GDEF header (may be Null) */
603   typename Types::template OffsetTo<ClassDef>
604 		markAttachClassDef;	/* Offset to class definition table for
605 					 * mark attachment type--from beginning
606 					 * of GDEF header (may be Null) */
607   typename Types::template OffsetTo<MarkGlyphSets>
608 		markGlyphSetsDef;	/* Offset to the table of mark set
609 					 * definitions--from beginning of GDEF
610 					 * header (may be NULL).  Introduced
611 					 * in version 0x00010002. */
612   Offset32To<ItemVariationStore>
613 		varStore;		/* Offset to the table of Item Variation
614 					 * Store--from beginning of GDEF
615 					 * header (may be NULL).  Introduced
616 					 * in version 0x00010003. */
617   public:
618   DEFINE_SIZE_MIN (4 + 4 * Types::size);
619 
get_sizeOT::GDEFVersion1_2620   unsigned int get_size () const
621   {
622     return min_size +
623 	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
624 	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
625   }
626 
sanitizeOT::GDEFVersion1_2627   bool sanitize (hb_sanitize_context_t *c) const
628   {
629     TRACE_SANITIZE (this);
630     return_trace (version.sanitize (c) &&
631 		  glyphClassDef.sanitize (c, this) &&
632 		  attachList.sanitize (c, this) &&
633 		  ligCaretList.sanitize (c, this) &&
634 		  markAttachClassDef.sanitize (c, this) &&
635 		  hb_barrier () &&
636 		  ((version.to_int () < 0x00010002u && hb_barrier ()) || markGlyphSetsDef.sanitize (c, this)) &&
637 		  ((version.to_int () < 0x00010003u && hb_barrier ()) || varStore.sanitize (c, this)));
638   }
639 
remap_varidx_after_instantiationOT::GDEFVersion1_2640   static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
641                                                 hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
642   {
643     /* varidx_map is empty which means varstore is empty after instantiation,
644      * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
645      * varidx_map doesn't have original varidx, indicating delta row is all
646      * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
647     for (auto _ : layout_variation_idx_delta_map.iter_ref ())
648     {
649       /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
650        * varidx is used as key of varidx_map during instantiation */
651       uint32_t varidx = _.second.first;
652       uint32_t *new_varidx;
653       if (varidx_map.has (varidx, &new_varidx))
654         _.second.first = *new_varidx;
655       else
656         _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
657     }
658   }
659 
subsetOT::GDEFVersion1_2660   bool subset (hb_subset_context_t *c) const
661   {
662     TRACE_SUBSET (this);
663     auto *out = c->serializer->start_embed (*this);
664     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
665 
666     // Push var store first (if it's needed) so that it's last in the
667     // serialization order. Some font consumers assume that varstore runs to
668     // the end of the GDEF table.
669     // See: https://github.com/harfbuzz/harfbuzz/issues/4636
670     auto snapshot_version0 = c->serializer->snapshot ();
671     if (unlikely (version.to_int () >= 0x00010002u && hb_barrier () && !c->serializer->embed (markGlyphSetsDef)))
672       return_trace (false);
673 
674     bool subset_varstore = false;
675     unsigned varstore_index = (unsigned) -1;
676     auto snapshot_version2 = c->serializer->snapshot ();
677     if (version.to_int () >= 0x00010003u && hb_barrier ())
678     {
679       if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
680       if (c->plan->all_axes_pinned)
681         out->varStore = 0;
682       else if (c->plan->normalized_coords)
683       {
684         if (varStore)
685         {
686           item_variations_t item_vars;
687           if (item_vars.instantiate (this+varStore, c->plan, true, true,
688                                      c->plan->gdef_varstore_inner_maps.as_array ())) {
689             subset_varstore = out->varStore.serialize_serialize (c->serializer,
690                                                                  item_vars.has_long_word (),
691                                                                  c->plan->axis_tags,
692                                                                  item_vars.get_region_list (),
693                                                                  item_vars.get_vardata_encodings ());
694             varstore_index = c->serializer->last_added_child_index();
695           }
696           remap_varidx_after_instantiation (item_vars.get_varidx_map (),
697                                             c->plan->layout_variation_idx_delta_map);
698         }
699       }
700       else
701       {
702         subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
703         varstore_index = c->serializer->last_added_child_index();
704       }
705     }
706 
707     out->version.major = version.major;
708     out->version.minor = version.minor;
709 
710     if (!subset_varstore && version.to_int () >= 0x00010002u) {
711       c->serializer->revert (snapshot_version2);
712     }
713 
714     bool subset_markglyphsetsdef = false;
715     if (version.to_int () >= 0x00010002u && hb_barrier ())
716     {
717       subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
718     }
719 
720     if (subset_varstore)
721     {
722       out->version.minor = 3;
723       c->plan->has_gdef_varstore = true;
724     } else if (subset_markglyphsetsdef) {
725       out->version.minor = 2;
726     } else  {
727       out->version.minor = 0;
728       c->serializer->revert (snapshot_version0);
729     }
730 
731     bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
732     bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
733     bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
734     bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
735 
736     if (subset_varstore && varstore_index != (unsigned) -1) {
737       c->serializer->repack_last(varstore_index);
738     }
739 
740     return_trace (subset_glyphclassdef || subset_attachlist ||
741 		  subset_ligcaretlist || subset_markattachclassdef ||
742 		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
743 		  (out->version.to_int () >= 0x00010003u && subset_varstore));
744   }
745 };
746 
747 struct GDEF
748 {
749   static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
750 
751   enum GlyphClasses {
752     UnclassifiedGlyph	= 0,
753     BaseGlyph		= 1,
754     LigatureGlyph	= 2,
755     MarkGlyph		= 3,
756     ComponentGlyph	= 4
757   };
758 
get_sizeOT::GDEF759   unsigned int get_size () const
760   {
761     switch (u.version.major) {
762     case 1: return u.version1.get_size ();
763 #ifndef HB_NO_BEYOND_64K
764     case 2: return u.version2.get_size ();
765 #endif
766     default: return u.version.static_size;
767     }
768   }
769 
sanitizeOT::GDEF770   bool sanitize (hb_sanitize_context_t *c) const
771   {
772     TRACE_SANITIZE (this);
773     if (unlikely (!u.version.sanitize (c))) return_trace (false);
774     hb_barrier ();
775     switch (u.version.major) {
776     case 1: return_trace (u.version1.sanitize (c));
777 #ifndef HB_NO_BEYOND_64K
778     case 2: return_trace (u.version2.sanitize (c));
779 #endif
780     default: return_trace (true);
781     }
782   }
783 
subsetOT::GDEF784   bool subset (hb_subset_context_t *c) const
785   {
786     switch (u.version.major) {
787     case 1: return u.version1.subset (c);
788 #ifndef HB_NO_BEYOND_64K
789     case 2: return u.version2.subset (c);
790 #endif
791     default: return false;
792     }
793   }
794 
has_glyph_classesOT::GDEF795   bool has_glyph_classes () const
796   {
797     switch (u.version.major) {
798     case 1: return u.version1.glyphClassDef != 0;
799 #ifndef HB_NO_BEYOND_64K
800     case 2: return u.version2.glyphClassDef != 0;
801 #endif
802     default: return false;
803     }
804   }
get_glyph_class_defOT::GDEF805   const ClassDef &get_glyph_class_def () const
806   {
807     switch (u.version.major) {
808     case 1: return this+u.version1.glyphClassDef;
809 #ifndef HB_NO_BEYOND_64K
810     case 2: return this+u.version2.glyphClassDef;
811 #endif
812     default: return Null(ClassDef);
813     }
814   }
has_attach_listOT::GDEF815   bool has_attach_list () const
816   {
817     switch (u.version.major) {
818     case 1: return u.version1.attachList != 0;
819 #ifndef HB_NO_BEYOND_64K
820     case 2: return u.version2.attachList != 0;
821 #endif
822     default: return false;
823     }
824   }
get_attach_listOT::GDEF825   const AttachList &get_attach_list () const
826   {
827     switch (u.version.major) {
828     case 1: return this+u.version1.attachList;
829 #ifndef HB_NO_BEYOND_64K
830     case 2: return this+u.version2.attachList;
831 #endif
832     default: return Null(AttachList);
833     }
834   }
has_lig_caretsOT::GDEF835   bool has_lig_carets () const
836   {
837     switch (u.version.major) {
838     case 1: return u.version1.ligCaretList != 0;
839 #ifndef HB_NO_BEYOND_64K
840     case 2: return u.version2.ligCaretList != 0;
841 #endif
842     default: return false;
843     }
844   }
get_lig_caret_listOT::GDEF845   const LigCaretList &get_lig_caret_list () const
846   {
847     switch (u.version.major) {
848     case 1: return this+u.version1.ligCaretList;
849 #ifndef HB_NO_BEYOND_64K
850     case 2: return this+u.version2.ligCaretList;
851 #endif
852     default: return Null(LigCaretList);
853     }
854   }
has_mark_attachment_typesOT::GDEF855   bool has_mark_attachment_types () const
856   {
857     switch (u.version.major) {
858     case 1: return u.version1.markAttachClassDef != 0;
859 #ifndef HB_NO_BEYOND_64K
860     case 2: return u.version2.markAttachClassDef != 0;
861 #endif
862     default: return false;
863     }
864   }
get_mark_attach_class_defOT::GDEF865   const ClassDef &get_mark_attach_class_def () const
866   {
867     switch (u.version.major) {
868     case 1: return this+u.version1.markAttachClassDef;
869 #ifndef HB_NO_BEYOND_64K
870     case 2: return this+u.version2.markAttachClassDef;
871 #endif
872     default: return Null(ClassDef);
873     }
874   }
has_mark_glyph_setsOT::GDEF875   bool has_mark_glyph_sets () const
876   {
877     switch (u.version.major) {
878     case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () && u.version1.markGlyphSetsDef != 0;
879 #ifndef HB_NO_BEYOND_64K
880     case 2: return u.version2.markGlyphSetsDef != 0;
881 #endif
882     default: return false;
883     }
884   }
get_mark_glyph_setsOT::GDEF885   const MarkGlyphSets &get_mark_glyph_sets () const
886   {
887     switch (u.version.major) {
888     case 1: return u.version.to_int () >= 0x00010002u && hb_barrier () ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
889 #ifndef HB_NO_BEYOND_64K
890     case 2: return this+u.version2.markGlyphSetsDef;
891 #endif
892     default: return Null(MarkGlyphSets);
893     }
894   }
has_var_storeOT::GDEF895   bool has_var_store () const
896   {
897     switch (u.version.major) {
898     case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () && u.version1.varStore != 0;
899 #ifndef HB_NO_BEYOND_64K
900     case 2: return u.version2.varStore != 0;
901 #endif
902     default: return false;
903     }
904   }
get_var_storeOT::GDEF905   const ItemVariationStore &get_var_store () const
906   {
907     switch (u.version.major) {
908     case 1: return u.version.to_int () >= 0x00010003u && hb_barrier () ? this+u.version1.varStore : Null(ItemVariationStore);
909 #ifndef HB_NO_BEYOND_64K
910     case 2: return this+u.version2.varStore;
911 #endif
912     default: return Null(ItemVariationStore);
913     }
914   }
915 
916 
has_dataOT::GDEF917   bool has_data () const { return u.version.to_int (); }
get_glyph_classOT::GDEF918   unsigned int get_glyph_class (hb_codepoint_t glyph) const
919   { return get_glyph_class_def ().get_class (glyph); }
get_glyphs_in_classOT::GDEF920   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
921   { get_glyph_class_def ().collect_class (glyphs, klass); }
922 
get_mark_attachment_typeOT::GDEF923   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
924   { return get_mark_attach_class_def ().get_class (glyph); }
925 
get_attach_pointsOT::GDEF926   unsigned int get_attach_points (hb_codepoint_t glyph_id,
927 				  unsigned int start_offset,
928 				  unsigned int *point_count /* IN/OUT */,
929 				  unsigned int *point_array /* OUT */) const
930   { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
931 
get_lig_caretsOT::GDEF932   unsigned int get_lig_carets (hb_font_t *font,
933 			       hb_direction_t direction,
934 			       hb_codepoint_t glyph_id,
935 			       unsigned int start_offset,
936 			       unsigned int *caret_count /* IN/OUT */,
937 			       hb_position_t *caret_array /* OUT */) const
938   { return get_lig_caret_list ().get_lig_carets (font,
939 						 direction, glyph_id, get_var_store(),
940 						 start_offset, caret_count, caret_array); }
941 
mark_set_coversOT::GDEF942   bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
943   { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
944 
945   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
946    * glyph class and other bits, and high 8-bit the mark attachment type (if any).
947    * Not to be confused with lookup_props which is very similar. */
get_glyph_propsOT::GDEF948   unsigned int get_glyph_props (hb_codepoint_t glyph) const
949   {
950     unsigned int klass = get_glyph_class (glyph);
951 
952     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
953     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
954     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
955 
956     switch (klass) {
957     default:			return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
958     case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
959     case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
960     case MarkGlyph:
961 	  klass = get_mark_attachment_type (glyph);
962 	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
963     }
964   }
965 
966   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
967 				   hb_face_t *face) const;
968 
969   struct accelerator_t
970   {
accelerator_tOT::GDEF::accelerator_t971     accelerator_t (hb_face_t *face)
972     {
973       table = hb_sanitize_context_t ().reference_table<GDEF> (face);
974       if (unlikely (table->is_blocklisted (table.get_blob (), face)))
975       {
976 	hb_blob_destroy (table.get_blob ());
977 	table = hb_blob_get_empty ();
978       }
979 
980 #ifndef HB_NO_GDEF_CACHE
981       table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
982 #endif
983     }
~accelerator_tOT::GDEF::accelerator_t984     ~accelerator_t () { table.destroy (); }
985 
get_glyph_propsOT::GDEF::accelerator_t986     unsigned int get_glyph_props (hb_codepoint_t glyph) const
987     {
988       unsigned v;
989 
990 #ifndef HB_NO_GDEF_CACHE
991       if (glyph_props_cache.get (glyph, &v))
992         return v;
993 #endif
994 
995       v = table->get_glyph_props (glyph);
996 
997 #ifndef HB_NO_GDEF_CACHE
998       if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
999 	glyph_props_cache.set (glyph, v);
1000 #endif
1001 
1002       return v;
1003 
1004     }
1005 
mark_set_coversOT::GDEF::accelerator_t1006     bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
1007     {
1008       return
1009 #ifndef HB_NO_GDEF_CACHE
1010 	     mark_glyph_set_digests[set_index].may_have (glyph_id) &&
1011 #endif
1012 	     table->mark_set_covers (set_index, glyph_id);
1013     }
1014 
1015     hb_blob_ptr_t<GDEF> table;
1016 #ifndef HB_NO_GDEF_CACHE
1017     hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
1018     mutable hb_cache_t<21, 3, 8> glyph_props_cache;
1019 #endif
1020   };
1021 
collect_variation_indicesOT::GDEF1022   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
1023   { get_lig_caret_list ().collect_variation_indices (c); }
1024 
1025   protected:
1026   union {
1027   FixedVersion<>		version;	/* Version identifier */
1028   GDEFVersion1_2<SmallTypes>	version1;
1029 #ifndef HB_NO_BEYOND_64K
1030   GDEFVersion1_2<MediumTypes>	version2;
1031 #endif
1032   } u;
1033   public:
1034   DEFINE_SIZE_MIN (4);
1035 };
1036 
1037 struct GDEF_accelerator_t : GDEF::accelerator_t {
GDEF_accelerator_tOT::GDEF_accelerator_t1038   GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
1039 };
1040 
1041 } /* namespace OT */
1042 
1043 
1044 #endif /* OT_LAYOUT_GDEF_GDEF_HH */
1045