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 : ArrayOf<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.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 ();
88     const hb_map_t &glyph_map = *c->plan->glyph_map;
89 
90     auto *out = c->serializer->start_embed (*this);
91     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
92 
93     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
94     + hb_zip (this+coverage, attachPoint)
95     | hb_filter (glyphset, hb_first)
96     | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
97     | hb_map (hb_first)
98     | hb_map (glyph_map)
99     | hb_sink (new_coverage)
100     ;
101     out->coverage.serialize (c->serializer, out)
102                  .serialize (c->serializer, new_coverage.iter ());
103     return_trace (bool (new_coverage));
104   }
105 
sanitizeOT::AttachList106   bool sanitize (hb_sanitize_context_t *c) const
107   {
108     TRACE_SANITIZE (this);
109     return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
110   }
111 
112   protected:
113   OffsetTo<Coverage>
114                 coverage;               /* Offset to Coverage table -- from
115                                          * beginning of AttachList table */
116   OffsetArrayOf<AttachPoint>
117                 attachPoint;            /* Array of AttachPoint tables
118                                          * in Coverage Index order */
119   public:
120   DEFINE_SIZE_ARRAY (4, attachPoint);
121 };
122 
123 /*
124  * Ligature Caret Table
125  */
126 
127 struct CaretValueFormat1
128 {
129   friend struct CaretValue;
subsetOT::CaretValueFormat1130   bool subset (hb_subset_context_t *c) const
131   {
132     TRACE_SUBSET (this);
133     auto *out = c->serializer->embed (this);
134     if (unlikely (!out)) return_trace (false);
135     return_trace (true);
136   }
137 
138   private:
get_caret_valueOT::CaretValueFormat1139   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
140   {
141     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
142   }
143 
sanitizeOT::CaretValueFormat1144   bool sanitize (hb_sanitize_context_t *c) const
145   {
146     TRACE_SANITIZE (this);
147     return_trace (c->check_struct (this));
148   }
149 
150   protected:
151   HBUINT16      caretValueFormat;       /* Format identifier--format = 1 */
152   FWORD         coordinate;             /* X or Y value, in design units */
153   public:
154   DEFINE_SIZE_STATIC (4);
155 };
156 
157 struct CaretValueFormat2
158 {
159   friend struct CaretValue;
subsetOT::CaretValueFormat2160   bool subset (hb_subset_context_t *c) const
161   {
162     TRACE_SUBSET (this);
163     auto *out = c->serializer->embed (this);
164     if (unlikely (!out)) return_trace (false);
165     return_trace (true);
166   }
167 
168   private:
get_caret_valueOT::CaretValueFormat2169   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
170   {
171     hb_position_t x, y;
172     font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
173     return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
174   }
175 
sanitizeOT::CaretValueFormat2176   bool sanitize (hb_sanitize_context_t *c) const
177   {
178     TRACE_SANITIZE (this);
179     return_trace (c->check_struct (this));
180   }
181 
182   protected:
183   HBUINT16      caretValueFormat;       /* Format identifier--format = 2 */
184   HBUINT16      caretValuePoint;        /* Contour point index on glyph */
185   public:
186   DEFINE_SIZE_STATIC (4);
187 };
188 
189 struct CaretValueFormat3
190 {
191   friend struct CaretValue;
192 
get_caret_valueOT::CaretValueFormat3193   hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
194                                  const VariationStore &var_store) const
195   {
196     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
197            font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
198            font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
199   }
200 
subsetOT::CaretValueFormat3201   bool subset (hb_subset_context_t *c) const
202   {
203     TRACE_SUBSET (this);
204     auto *out = c->serializer->embed (this);
205     if (unlikely (!out)) return_trace (false);
206 
207     return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
208                                                    hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
209   }
210 
collect_variation_indicesOT::CaretValueFormat3211   void collect_variation_indices (hb_set_t *layout_variation_indices) const
212   { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
213 
sanitizeOT::CaretValueFormat3214   bool sanitize (hb_sanitize_context_t *c) const
215   {
216     TRACE_SANITIZE (this);
217     return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
218   }
219 
220   protected:
221   HBUINT16      caretValueFormat;       /* Format identifier--format = 3 */
222   FWORD         coordinate;             /* X or Y value, in design units */
223   OffsetTo<Device>
224                 deviceTable;            /* Offset to Device table for X or Y
225                                          * value--from beginning of CaretValue
226                                          * table */
227   public:
228   DEFINE_SIZE_STATIC (6);
229 };
230 
231 struct CaretValue
232 {
get_caret_valueOT::CaretValue233   hb_position_t get_caret_value (hb_font_t *font,
234                                  hb_direction_t direction,
235                                  hb_codepoint_t glyph_id,
236                                  const VariationStore &var_store) const
237   {
238     switch (u.format) {
239     case 1: return u.format1.get_caret_value (font, direction);
240     case 2: return u.format2.get_caret_value (font, direction, glyph_id);
241     case 3: return u.format3.get_caret_value (font, direction, var_store);
242     default:return 0;
243     }
244   }
245 
246   template <typename context_t, typename ...Ts>
dispatchOT::CaretValue247   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
248   {
249     TRACE_DISPATCH (this, u.format);
250     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
251     switch (u.format) {
252     case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
253     case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
254     case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
255     default:return_trace (c->default_return_value ());
256     }
257   }
258 
collect_variation_indicesOT::CaretValue259   void collect_variation_indices (hb_set_t *layout_variation_indices) const
260   {
261     switch (u.format) {
262     case 1:
263     case 2:
264       return;
265     case 3:
266       u.format3.collect_variation_indices (layout_variation_indices);
267       return;
268     default: return;
269     }
270   }
271 
sanitizeOT::CaretValue272   bool sanitize (hb_sanitize_context_t *c) const
273   {
274     TRACE_SANITIZE (this);
275     if (!u.format.sanitize (c)) return_trace (false);
276     switch (u.format) {
277     case 1: return_trace (u.format1.sanitize (c));
278     case 2: return_trace (u.format2.sanitize (c));
279     case 3: return_trace (u.format3.sanitize (c));
280     default:return_trace (true);
281     }
282   }
283 
284   protected:
285   union {
286   HBUINT16              format;         /* Format identifier */
287   CaretValueFormat1     format1;
288   CaretValueFormat2     format2;
289   CaretValueFormat3     format3;
290   } u;
291   public:
292   DEFINE_SIZE_UNION (2, format);
293 };
294 
295 struct LigGlyph
296 {
get_lig_caretsOT::LigGlyph297   unsigned get_lig_carets (hb_font_t            *font,
298                            hb_direction_t        direction,
299                            hb_codepoint_t        glyph_id,
300                            const VariationStore &var_store,
301                            unsigned              start_offset,
302                            unsigned             *caret_count /* IN/OUT */,
303                            hb_position_t        *caret_array /* OUT */) const
304   {
305     if (caret_count)
306     {
307       + carets.sub_array (start_offset, caret_count)
308       | hb_map (hb_add (this))
309       | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
310       | hb_sink (hb_array (caret_array, *caret_count))
311       ;
312     }
313 
314     return carets.len;
315   }
316 
subsetOT::LigGlyph317   bool subset (hb_subset_context_t *c) const
318   {
319     TRACE_SUBSET (this);
320     auto *out = c->serializer->start_embed (*this);
321     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
322 
323     + hb_iter (carets)
324     | hb_apply (subset_offset_array (c, out->carets, this))
325     ;
326 
327     return_trace (bool (out->carets));
328   }
329 
collect_variation_indicesOT::LigGlyph330   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
331   {
332     for (const OffsetTo<CaretValue>& offset : carets.iter ())
333       (this+offset).collect_variation_indices (c->layout_variation_indices);
334   }
335 
sanitizeOT::LigGlyph336   bool sanitize (hb_sanitize_context_t *c) const
337   {
338     TRACE_SANITIZE (this);
339     return_trace (carets.sanitize (c, this));
340   }
341 
342   protected:
343   OffsetArrayOf<CaretValue>
344                 carets;                 /* Offset array of CaretValue tables
345                                          * --from beginning of LigGlyph table
346                                          * --in increasing coordinate order */
347   public:
348   DEFINE_SIZE_ARRAY (2, carets);
349 };
350 
351 struct LigCaretList
352 {
get_lig_caretsOT::LigCaretList353   unsigned int get_lig_carets (hb_font_t *font,
354                                hb_direction_t direction,
355                                hb_codepoint_t glyph_id,
356                                const VariationStore &var_store,
357                                unsigned int start_offset,
358                                unsigned int *caret_count /* IN/OUT */,
359                                hb_position_t *caret_array /* OUT */) const
360   {
361     unsigned int index = (this+coverage).get_coverage (glyph_id);
362     if (index == NOT_COVERED)
363     {
364       if (caret_count)
365         *caret_count = 0;
366       return 0;
367     }
368     const LigGlyph &lig_glyph = this+ligGlyph[index];
369     return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
370   }
371 
subsetOT::LigCaretList372   bool subset (hb_subset_context_t *c) const
373   {
374     TRACE_SUBSET (this);
375     const hb_set_t &glyphset = *c->plan->glyphset ();
376     const hb_map_t &glyph_map = *c->plan->glyph_map;
377 
378     auto *out = c->serializer->start_embed (*this);
379     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
380 
381     hb_sorted_vector_t<hb_codepoint_t> new_coverage;
382     + hb_zip (this+coverage, ligGlyph)
383     | hb_filter (glyphset, hb_first)
384     | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
385     | hb_map (hb_first)
386     | hb_map (glyph_map)
387     | hb_sink (new_coverage)
388     ;
389     out->coverage.serialize (c->serializer, out)
390                  .serialize (c->serializer, new_coverage.iter ());
391     return_trace (bool (new_coverage));
392   }
393 
collect_variation_indicesOT::LigCaretList394   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
395   {
396     + hb_zip (this+coverage, ligGlyph)
397     | hb_filter (c->glyph_set, hb_first)
398     | hb_map (hb_second)
399     | hb_map (hb_add (this))
400     | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
401     ;
402   }
403 
sanitizeOT::LigCaretList404   bool sanitize (hb_sanitize_context_t *c) const
405   {
406     TRACE_SANITIZE (this);
407     return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
408   }
409 
410   protected:
411   OffsetTo<Coverage>
412                 coverage;               /* Offset to Coverage table--from
413                                          * beginning of LigCaretList table */
414   OffsetArrayOf<LigGlyph>
415                 ligGlyph;               /* Array of LigGlyph tables
416                                          * in Coverage Index order */
417   public:
418   DEFINE_SIZE_ARRAY (4, ligGlyph);
419 };
420 
421 
422 struct MarkGlyphSetsFormat1
423 {
coversOT::MarkGlyphSetsFormat1424   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
425   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
426 
subsetOT::MarkGlyphSetsFormat1427   bool subset (hb_subset_context_t *c) const
428   {
429     TRACE_SUBSET (this);
430     auto *out = c->serializer->start_embed (*this);
431     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
432     out->format = format;
433 
434     bool ret = true;
435     for (const LOffsetTo<Coverage>& offset : coverage.iter ())
436     {
437       auto *o = out->coverage.serialize_append (c->serializer);
438       if (unlikely (!o))
439       {
440         ret = false;
441         break;
442       }
443 
444       //not using o->serialize_subset (c, offset, this, out) here because
445       //OTS doesn't allow null offset.
446       //See issue: https://github.com/khaledhosny/ots/issues/172
447       c->serializer->push ();
448       c->dispatch (this+offset);
449       c->serializer->add_link (*o, c->serializer->pop_pack ());
450     }
451 
452     return_trace (ret && out->coverage.len);
453   }
454 
sanitizeOT::MarkGlyphSetsFormat1455   bool sanitize (hb_sanitize_context_t *c) const
456   {
457     TRACE_SANITIZE (this);
458     return_trace (coverage.sanitize (c, this));
459   }
460 
461   protected:
462   HBUINT16      format;                 /* Format identifier--format = 1 */
463   ArrayOf<LOffsetTo<Coverage>>
464                 coverage;               /* Array of long offsets to mark set
465                                          * coverage tables */
466   public:
467   DEFINE_SIZE_ARRAY (4, coverage);
468 };
469 
470 struct MarkGlyphSets
471 {
coversOT::MarkGlyphSets472   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
473   {
474     switch (u.format) {
475     case 1: return u.format1.covers (set_index, glyph_id);
476     default:return false;
477     }
478   }
479 
subsetOT::MarkGlyphSets480   bool subset (hb_subset_context_t *c) const
481   {
482     TRACE_SUBSET (this);
483     switch (u.format) {
484     case 1: return_trace (u.format1.subset (c));
485     default:return_trace (false);
486     }
487   }
488 
sanitizeOT::MarkGlyphSets489   bool sanitize (hb_sanitize_context_t *c) const
490   {
491     TRACE_SANITIZE (this);
492     if (!u.format.sanitize (c)) return_trace (false);
493     switch (u.format) {
494     case 1: return_trace (u.format1.sanitize (c));
495     default:return_trace (true);
496     }
497   }
498 
499   protected:
500   union {
501   HBUINT16              format;         /* Format identifier */
502   MarkGlyphSetsFormat1  format1;
503   } u;
504   public:
505   DEFINE_SIZE_UNION (2, format);
506 };
507 
508 
509 /*
510  * GDEF -- Glyph Definition
511  * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
512  */
513 
514 
515 struct GDEF
516 {
517   static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
518 
519   enum GlyphClasses {
520     UnclassifiedGlyph   = 0,
521     BaseGlyph           = 1,
522     LigatureGlyph       = 2,
523     MarkGlyph           = 3,
524     ComponentGlyph      = 4
525   };
526 
has_dataOT::GDEF527   bool has_data () const { return version.to_int (); }
has_glyph_classesOT::GDEF528   bool has_glyph_classes () const { return glyphClassDef != 0; }
get_glyph_classOT::GDEF529   unsigned int get_glyph_class (hb_codepoint_t glyph) const
530   { return (this+glyphClassDef).get_class (glyph); }
get_glyphs_in_classOT::GDEF531   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
532   { (this+glyphClassDef).collect_class (glyphs, klass); }
533 
has_mark_attachment_typesOT::GDEF534   bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
get_mark_attachment_typeOT::GDEF535   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
536   { return (this+markAttachClassDef).get_class (glyph); }
537 
has_attach_pointsOT::GDEF538   bool has_attach_points () const { return attachList != 0; }
get_attach_pointsOT::GDEF539   unsigned int get_attach_points (hb_codepoint_t glyph_id,
540                                   unsigned int start_offset,
541                                   unsigned int *point_count /* IN/OUT */,
542                                   unsigned int *point_array /* OUT */) const
543   { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
544 
has_lig_caretsOT::GDEF545   bool has_lig_carets () const { return ligCaretList != 0; }
get_lig_caretsOT::GDEF546   unsigned int get_lig_carets (hb_font_t *font,
547                                hb_direction_t direction,
548                                hb_codepoint_t glyph_id,
549                                unsigned int start_offset,
550                                unsigned int *caret_count /* IN/OUT */,
551                                hb_position_t *caret_array /* OUT */) const
552   { return (this+ligCaretList).get_lig_carets (font,
553                                                direction, glyph_id, get_var_store(),
554                                                start_offset, caret_count, caret_array); }
555 
has_mark_setsOT::GDEF556   bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
mark_set_coversOT::GDEF557   bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
558   { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
559 
has_var_storeOT::GDEF560   bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
get_var_storeOT::GDEF561   const VariationStore &get_var_store () const
562   { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
563 
564   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
565    * glyph class and other bits, and high 8-bit the mark attachment type (if any).
566    * Not to be confused with lookup_props which is very similar. */
get_glyph_propsOT::GDEF567   unsigned int get_glyph_props (hb_codepoint_t glyph) const
568   {
569     unsigned int klass = get_glyph_class (glyph);
570 
571     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
572     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
573     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
574 
575     switch (klass) {
576     default:                    return 0;
577     case BaseGlyph:             return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
578     case LigatureGlyph:         return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
579     case MarkGlyph:
580           klass = get_mark_attachment_type (glyph);
581           return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
582     }
583   }
584 
585   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
586                                    hb_face_t *face) const;
587 
588   struct accelerator_t
589   {
initOT::GDEF::accelerator_t590     void init (hb_face_t *face)
591     {
592       this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
593       if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
594       {
595         hb_blob_destroy (this->table.get_blob ());
596         this->table = hb_blob_get_empty ();
597       }
598     }
599 
finiOT::GDEF::accelerator_t600     void fini () { this->table.destroy (); }
601 
602     hb_blob_ptr_t<GDEF> table;
603   };
604 
get_sizeOT::GDEF605   unsigned int get_size () const
606   {
607     return min_size +
608            (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
609            (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
610   }
611 
collect_variation_indicesOT::GDEF612   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
613   { (this+ligCaretList).collect_variation_indices (c); }
614 
remap_layout_variation_indicesOT::GDEF615   void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
616                                        hb_map_t *layout_variation_idx_map /* OUT */) const
617   {
618     if (version.to_int () < 0x00010003u || !varStore) return;
619     if (layout_variation_indices->is_empty ()) return;
620 
621     unsigned new_major = 0, new_minor = 0;
622     unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
623     for (unsigned idx : layout_variation_indices->iter ())
624     {
625       uint16_t major = idx >> 16;
626       if (major >= (this+varStore).get_sub_table_count ()) break;
627       if (major != last_major)
628       {
629         new_minor = 0;
630         ++new_major;
631       }
632 
633       unsigned new_idx = (new_major << 16) + new_minor;
634       layout_variation_idx_map->set (idx, new_idx);
635       ++new_minor;
636       last_major = major;
637     }
638   }
639 
subsetOT::GDEF640   bool subset (hb_subset_context_t *c) const
641   {
642     TRACE_SUBSET (this);
643     auto *out = c->serializer->embed (*this);
644     if (unlikely (!out)) return_trace (false);
645 
646     bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
647     bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
648     bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
649     bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this);
650 
651     bool subset_markglyphsetsdef = true;
652     if (version.to_int () >= 0x00010002u)
653     {
654       subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
655       if (!subset_markglyphsetsdef &&
656           version.to_int () == 0x00010002u)
657         out->version.minor = 0;
658     }
659 
660     bool subset_varstore = true;
661     if (version.to_int () >= 0x00010003u)
662     {
663       subset_varstore = out->varStore.serialize_subset (c, varStore, this);
664       if (!subset_varstore && version.to_int () == 0x00010003u)
665         out->version.minor = 2;
666     }
667 
668     return_trace (subset_glyphclassdef || subset_attachlist ||
669                   subset_ligcaretlist || subset_markattachclassdef ||
670                   (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
671                   (out->version.to_int () >= 0x00010003u && subset_varstore));
672   }
673 
sanitizeOT::GDEF674   bool sanitize (hb_sanitize_context_t *c) const
675   {
676     TRACE_SANITIZE (this);
677     return_trace (version.sanitize (c) &&
678                   likely (version.major == 1) &&
679                   glyphClassDef.sanitize (c, this) &&
680                   attachList.sanitize (c, this) &&
681                   ligCaretList.sanitize (c, this) &&
682                   markAttachClassDef.sanitize (c, this) &&
683                   (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
684                   (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
685   }
686 
687   protected:
688   FixedVersion<>version;                /* Version of the GDEF table--currently
689                                          * 0x00010003u */
690   OffsetTo<ClassDef>
691                 glyphClassDef;          /* Offset to class definition table
692                                          * for glyph type--from beginning of
693                                          * GDEF header (may be Null) */
694   OffsetTo<AttachList>
695                 attachList;             /* Offset to list of glyphs with
696                                          * attachment points--from beginning
697                                          * of GDEF header (may be Null) */
698   OffsetTo<LigCaretList>
699                 ligCaretList;           /* Offset to list of positioning points
700                                          * for ligature carets--from beginning
701                                          * of GDEF header (may be Null) */
702   OffsetTo<ClassDef>
703                 markAttachClassDef;     /* Offset to class definition table for
704                                          * mark attachment type--from beginning
705                                          * of GDEF header (may be Null) */
706   OffsetTo<MarkGlyphSets>
707                 markGlyphSetsDef;       /* Offset to the table of mark set
708                                          * definitions--from beginning of GDEF
709                                          * header (may be NULL).  Introduced
710                                          * in version 0x00010002. */
711   LOffsetTo<VariationStore>
712                 varStore;               /* Offset to the table of Item Variation
713                                          * Store--from beginning of GDEF
714                                          * header (may be NULL).  Introduced
715                                          * in version 0x00010003. */
716   public:
717   DEFINE_SIZE_MIN (12);
718 };
719 
720 struct GDEF_accelerator_t : GDEF::accelerator_t {};
721 
722 } /* namespace OT */
723 
724 
725 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
726