• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
subsetOT::AttachPoint47   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 {
get_attach_pointsOT::AttachList59   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 
subsetOT::AttachList84   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 
sanitizeOT::AttachList105   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;
subsetOT::CaretValueFormat1129   bool subset (hb_subset_context_t *c) const
130   {
131     TRACE_SUBSET (this);
132     auto *out = c->serializer->embed (this);
133     if (unlikely (!out)) return_trace (false);
134     return_trace (true);
135   }
136 
137   private:
get_caret_valueOT::CaretValueFormat1138   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 
sanitizeOT::CaretValueFormat1143   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;
subsetOT::CaretValueFormat2159   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:
get_caret_valueOT::CaretValueFormat2168   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 
sanitizeOT::CaretValueFormat2175   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 
get_caret_valueOT::CaretValueFormat3192   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 
subsetOT::CaretValueFormat3200   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 
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 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>
dispatchOT::CaretValue265   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 
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     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 {
get_lig_caretsOT::LigGlyph315   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 
subsetOT::LigGlyph335   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 
collect_variation_indicesOT::LigGlyph348   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 
sanitizeOT::LigGlyph354   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 {
get_lig_caretsOT::LigCaretList371   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 
subsetOT::LigCaretList390   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 
collect_variation_indicesOT::LigCaretList411   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 
sanitizeOT::LigCaretList421   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 {
coversOT::MarkGlyphSetsFormat1441   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 
subsetOT::MarkGlyphSetsFormat1444   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 
sanitizeOT::MarkGlyphSetsFormat1472   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 {
coversOT::MarkGlyphSets489   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 
subsetOT::MarkGlyphSets497   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 
sanitizeOT::MarkGlyphSets506   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 
get_sizeOT::GDEFVersion1_2569   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 
sanitizeOT::GDEFVersion1_2576   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 
subsetOT::GDEFVersion1_2588   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 
get_sizeOT::GDEF642   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 
sanitizeOT::GDEF653   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 
subsetOT::GDEF666   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 
has_glyph_classesOT::GDEF677   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   }
get_glyph_class_defOT::GDEF687   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   }
has_attach_listOT::GDEF697   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   }
get_attach_listOT::GDEF707   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   }
has_lig_caretsOT::GDEF717   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   }
get_lig_caret_listOT::GDEF727   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   }
has_mark_attachment_typesOT::GDEF737   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   }
get_mark_attach_class_defOT::GDEF747   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   }
has_mark_glyph_setsOT::GDEF757   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   }
get_mark_glyph_setsOT::GDEF767   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   }
has_var_storeOT::GDEF777   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   }
get_var_storeOT::GDEF787   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 
has_dataOT::GDEF799   bool has_data () const { return u.version.to_int (); }
get_glyph_classOT::GDEF800   unsigned int get_glyph_class (hb_codepoint_t glyph) const
801   { return get_glyph_class_def ().get_class (glyph); }
get_glyphs_in_classOT::GDEF802   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
803   { get_glyph_class_def ().collect_class (glyphs, klass); }
804 
get_mark_attachment_typeOT::GDEF805   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
806   { return get_mark_attach_class_def ().get_class (glyph); }
807 
get_attach_pointsOT::GDEF808   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 
get_lig_caretsOT::GDEF814   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 
mark_set_coversOT::GDEF824   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. */
get_glyph_propsOT::GDEF830   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   {
accelerator_tOT::GDEF::accelerator_t853     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     }
~accelerator_tOT::GDEF::accelerator_t862     ~accelerator_t () { table.destroy (); }
863 
864     hb_blob_ptr_t<GDEF> table;
865   };
866 
collect_variation_indicesOT::GDEF867   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
868   { get_lig_caret_list ().collect_variation_indices (c); }
869 
remap_layout_variation_indicesOT::GDEF870   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 {
GDEF_accelerator_tOT::GDEF_accelerator_t912   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 */
919