• 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 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 VariationStore &var_store) const
193   {
194     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
195 	   font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
196 	   font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
197   }
198 
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 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     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     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 
444   template <typename set_t>
collect_coverageOT::MarkGlyphSetsFormat1445   void collect_coverage (hb_vector_t<set_t> &sets) const
446   {
447      for (const auto &offset : coverage)
448      {
449        const auto &cov = this+offset;
450        cov.collect_coverage (sets.push ());
451      }
452   }
453 
subsetOT::MarkGlyphSetsFormat1454   bool subset (hb_subset_context_t *c) const
455   {
456     TRACE_SUBSET (this);
457     auto *out = c->serializer->start_embed (*this);
458     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
459     out->format = format;
460 
461     bool ret = true;
462     for (const Offset32To<Coverage>& offset : coverage.iter ())
463     {
464       auto *o = out->coverage.serialize_append (c->serializer);
465       if (unlikely (!o))
466       {
467 	ret = false;
468 	break;
469       }
470 
471       //not using o->serialize_subset (c, offset, this, out) here because
472       //OTS doesn't allow null offset.
473       //See issue: https://github.com/khaledhosny/ots/issues/172
474       c->serializer->push ();
475       c->dispatch (this+offset);
476       c->serializer->add_link (*o, c->serializer->pop_pack ());
477     }
478 
479     return_trace (ret && out->coverage.len);
480   }
481 
sanitizeOT::MarkGlyphSetsFormat1482   bool sanitize (hb_sanitize_context_t *c) const
483   {
484     TRACE_SANITIZE (this);
485     return_trace (coverage.sanitize (c, this));
486   }
487 
488   protected:
489   HBUINT16	format;			/* Format identifier--format = 1 */
490   Array16Of<Offset32To<Coverage>>
491 		coverage;		/* Array of long offsets to mark set
492 					 * coverage tables */
493   public:
494   DEFINE_SIZE_ARRAY (4, coverage);
495 };
496 
497 struct MarkGlyphSets
498 {
coversOT::MarkGlyphSets499   bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
500   {
501     switch (u.format) {
502     case 1: return u.format1.covers (set_index, glyph_id);
503     default:return false;
504     }
505   }
506 
507   template <typename set_t>
collect_coverageOT::MarkGlyphSets508   void collect_coverage (hb_vector_t<set_t> &sets) const
509   {
510     switch (u.format) {
511     case 1: u.format1.collect_coverage (sets); return;
512     default:return;
513     }
514   }
515 
subsetOT::MarkGlyphSets516   bool subset (hb_subset_context_t *c) const
517   {
518     TRACE_SUBSET (this);
519     switch (u.format) {
520     case 1: return_trace (u.format1.subset (c));
521     default:return_trace (false);
522     }
523   }
524 
sanitizeOT::MarkGlyphSets525   bool sanitize (hb_sanitize_context_t *c) const
526   {
527     TRACE_SANITIZE (this);
528     if (!u.format.sanitize (c)) return_trace (false);
529     switch (u.format) {
530     case 1: return_trace (u.format1.sanitize (c));
531     default:return_trace (true);
532     }
533   }
534 
535   protected:
536   union {
537   HBUINT16		format;		/* Format identifier */
538   MarkGlyphSetsFormat1	format1;
539   } u;
540   public:
541   DEFINE_SIZE_UNION (2, format);
542 };
543 
544 
545 /*
546  * GDEF -- Glyph Definition
547  * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
548  */
549 
550 
551 template <typename Types>
552 struct GDEFVersion1_2
553 {
554   friend struct GDEF;
555 
556   protected:
557   FixedVersion<>version;		/* Version of the GDEF table--currently
558 					 * 0x00010003u */
559   typename Types::template OffsetTo<ClassDef>
560 		glyphClassDef;		/* Offset to class definition table
561 					 * for glyph type--from beginning of
562 					 * GDEF header (may be Null) */
563   typename Types::template OffsetTo<AttachList>
564 		attachList;		/* Offset to list of glyphs with
565 					 * attachment points--from beginning
566 					 * of GDEF header (may be Null) */
567   typename Types::template OffsetTo<LigCaretList>
568 		ligCaretList;		/* Offset to list of positioning points
569 					 * for ligature carets--from beginning
570 					 * of GDEF header (may be Null) */
571   typename Types::template OffsetTo<ClassDef>
572 		markAttachClassDef;	/* Offset to class definition table for
573 					 * mark attachment type--from beginning
574 					 * of GDEF header (may be Null) */
575   typename Types::template OffsetTo<MarkGlyphSets>
576 		markGlyphSetsDef;	/* Offset to the table of mark set
577 					 * definitions--from beginning of GDEF
578 					 * header (may be NULL).  Introduced
579 					 * in version 0x00010002. */
580   Offset32To<VariationStore>
581 		varStore;		/* Offset to the table of Item Variation
582 					 * Store--from beginning of GDEF
583 					 * header (may be NULL).  Introduced
584 					 * in version 0x00010003. */
585   public:
586   DEFINE_SIZE_MIN (4 + 4 * Types::size);
587 
get_sizeOT::GDEFVersion1_2588   unsigned int get_size () const
589   {
590     return min_size +
591 	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
592 	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
593   }
594 
sanitizeOT::GDEFVersion1_2595   bool sanitize (hb_sanitize_context_t *c) const
596   {
597     TRACE_SANITIZE (this);
598     return_trace (version.sanitize (c) &&
599 		  glyphClassDef.sanitize (c, this) &&
600 		  attachList.sanitize (c, this) &&
601 		  ligCaretList.sanitize (c, this) &&
602 		  markAttachClassDef.sanitize (c, this) &&
603 		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
604 		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
605   }
606 
remap_varidx_after_instantiationOT::GDEFVersion1_2607   static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
608                                                 hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
609   {
610     /* varidx_map is empty which means varstore is empty after instantiation,
611      * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
612      * varidx_map doesn't have original varidx, indicating delta row is all
613      * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
614     for (auto _ : layout_variation_idx_delta_map.iter_ref ())
615     {
616       /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
617        * varidx is used as key of varidx_map during instantiation */
618       uint32_t varidx = _.second.first;
619       uint32_t *new_varidx;
620       if (varidx_map.has (varidx, &new_varidx))
621         _.second.first = *new_varidx;
622       else
623         _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
624     }
625   }
626 
subsetOT::GDEFVersion1_2627   bool subset (hb_subset_context_t *c) const
628   {
629     TRACE_SUBSET (this);
630     auto *out = c->serializer->embed (*this);
631     if (unlikely (!out)) return_trace (false);
632 
633     bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
634     bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
635     bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
636     bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
637 
638     bool subset_markglyphsetsdef = false;
639     if (version.to_int () >= 0x00010002u)
640     {
641       subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
642     }
643 
644     bool subset_varstore = false;
645     if (version.to_int () >= 0x00010003u)
646     {
647       if (c->plan->all_axes_pinned)
648         out->varStore = 0;
649       else if (c->plan->normalized_coords)
650       {
651         if (varStore)
652         {
653           item_variations_t item_vars;
654           if (item_vars.instantiate (this+varStore, c->plan, true, true,
655                                      c->plan->gdef_varstore_inner_maps.as_array ()))
656             subset_varstore = out->varStore.serialize_serialize (c->serializer,
657                                                                  item_vars.has_long_word (),
658                                                                  c->plan->axis_tags,
659                                                                  item_vars.get_region_list (),
660                                                                  item_vars.get_vardata_encodings ());
661           remap_varidx_after_instantiation (item_vars.get_varidx_map (),
662                                             c->plan->layout_variation_idx_delta_map);
663         }
664       }
665       else
666         subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
667     }
668 
669     if (subset_varstore)
670     {
671       out->version.minor = 3;
672     } else if (subset_markglyphsetsdef) {
673       out->version.minor = 2;
674     } else  {
675       out->version.minor = 0;
676     }
677 
678     return_trace (subset_glyphclassdef || subset_attachlist ||
679 		  subset_ligcaretlist || subset_markattachclassdef ||
680 		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
681 		  (out->version.to_int () >= 0x00010003u && subset_varstore));
682   }
683 };
684 
685 struct GDEF
686 {
687   static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
688 
689   enum GlyphClasses {
690     UnclassifiedGlyph	= 0,
691     BaseGlyph		= 1,
692     LigatureGlyph	= 2,
693     MarkGlyph		= 3,
694     ComponentGlyph	= 4
695   };
696 
get_sizeOT::GDEF697   unsigned int get_size () const
698   {
699     switch (u.version.major) {
700     case 1: return u.version1.get_size ();
701 #ifndef HB_NO_BEYOND_64K
702     case 2: return u.version2.get_size ();
703 #endif
704     default: return u.version.static_size;
705     }
706   }
707 
sanitizeOT::GDEF708   bool sanitize (hb_sanitize_context_t *c) const
709   {
710     TRACE_SANITIZE (this);
711     if (unlikely (!u.version.sanitize (c))) return_trace (false);
712     switch (u.version.major) {
713     case 1: return_trace (u.version1.sanitize (c));
714 #ifndef HB_NO_BEYOND_64K
715     case 2: return_trace (u.version2.sanitize (c));
716 #endif
717     default: return_trace (true);
718     }
719   }
720 
subsetOT::GDEF721   bool subset (hb_subset_context_t *c) const
722   {
723     switch (u.version.major) {
724     case 1: return u.version1.subset (c);
725 #ifndef HB_NO_BEYOND_64K
726     case 2: return u.version2.subset (c);
727 #endif
728     default: return false;
729     }
730   }
731 
has_glyph_classesOT::GDEF732   bool has_glyph_classes () const
733   {
734     switch (u.version.major) {
735     case 1: return u.version1.glyphClassDef != 0;
736 #ifndef HB_NO_BEYOND_64K
737     case 2: return u.version2.glyphClassDef != 0;
738 #endif
739     default: return false;
740     }
741   }
get_glyph_class_defOT::GDEF742   const ClassDef &get_glyph_class_def () const
743   {
744     switch (u.version.major) {
745     case 1: return this+u.version1.glyphClassDef;
746 #ifndef HB_NO_BEYOND_64K
747     case 2: return this+u.version2.glyphClassDef;
748 #endif
749     default: return Null(ClassDef);
750     }
751   }
has_attach_listOT::GDEF752   bool has_attach_list () const
753   {
754     switch (u.version.major) {
755     case 1: return u.version1.attachList != 0;
756 #ifndef HB_NO_BEYOND_64K
757     case 2: return u.version2.attachList != 0;
758 #endif
759     default: return false;
760     }
761   }
get_attach_listOT::GDEF762   const AttachList &get_attach_list () const
763   {
764     switch (u.version.major) {
765     case 1: return this+u.version1.attachList;
766 #ifndef HB_NO_BEYOND_64K
767     case 2: return this+u.version2.attachList;
768 #endif
769     default: return Null(AttachList);
770     }
771   }
has_lig_caretsOT::GDEF772   bool has_lig_carets () const
773   {
774     switch (u.version.major) {
775     case 1: return u.version1.ligCaretList != 0;
776 #ifndef HB_NO_BEYOND_64K
777     case 2: return u.version2.ligCaretList != 0;
778 #endif
779     default: return false;
780     }
781   }
get_lig_caret_listOT::GDEF782   const LigCaretList &get_lig_caret_list () const
783   {
784     switch (u.version.major) {
785     case 1: return this+u.version1.ligCaretList;
786 #ifndef HB_NO_BEYOND_64K
787     case 2: return this+u.version2.ligCaretList;
788 #endif
789     default: return Null(LigCaretList);
790     }
791   }
has_mark_attachment_typesOT::GDEF792   bool has_mark_attachment_types () const
793   {
794     switch (u.version.major) {
795     case 1: return u.version1.markAttachClassDef != 0;
796 #ifndef HB_NO_BEYOND_64K
797     case 2: return u.version2.markAttachClassDef != 0;
798 #endif
799     default: return false;
800     }
801   }
get_mark_attach_class_defOT::GDEF802   const ClassDef &get_mark_attach_class_def () const
803   {
804     switch (u.version.major) {
805     case 1: return this+u.version1.markAttachClassDef;
806 #ifndef HB_NO_BEYOND_64K
807     case 2: return this+u.version2.markAttachClassDef;
808 #endif
809     default: return Null(ClassDef);
810     }
811   }
has_mark_glyph_setsOT::GDEF812   bool has_mark_glyph_sets () const
813   {
814     switch (u.version.major) {
815     case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
816 #ifndef HB_NO_BEYOND_64K
817     case 2: return u.version2.markGlyphSetsDef != 0;
818 #endif
819     default: return false;
820     }
821   }
get_mark_glyph_setsOT::GDEF822   const MarkGlyphSets &get_mark_glyph_sets () const
823   {
824     switch (u.version.major) {
825     case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
826 #ifndef HB_NO_BEYOND_64K
827     case 2: return this+u.version2.markGlyphSetsDef;
828 #endif
829     default: return Null(MarkGlyphSets);
830     }
831   }
has_var_storeOT::GDEF832   bool has_var_store () const
833   {
834     switch (u.version.major) {
835     case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
836 #ifndef HB_NO_BEYOND_64K
837     case 2: return u.version2.varStore != 0;
838 #endif
839     default: return false;
840     }
841   }
get_var_storeOT::GDEF842   const VariationStore &get_var_store () const
843   {
844     switch (u.version.major) {
845     case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
846 #ifndef HB_NO_BEYOND_64K
847     case 2: return this+u.version2.varStore;
848 #endif
849     default: return Null(VariationStore);
850     }
851   }
852 
853 
has_dataOT::GDEF854   bool has_data () const { return u.version.to_int (); }
get_glyph_classOT::GDEF855   unsigned int get_glyph_class (hb_codepoint_t glyph) const
856   { return get_glyph_class_def ().get_class (glyph); }
get_glyphs_in_classOT::GDEF857   void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
858   { get_glyph_class_def ().collect_class (glyphs, klass); }
859 
get_mark_attachment_typeOT::GDEF860   unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
861   { return get_mark_attach_class_def ().get_class (glyph); }
862 
get_attach_pointsOT::GDEF863   unsigned int get_attach_points (hb_codepoint_t glyph_id,
864 				  unsigned int start_offset,
865 				  unsigned int *point_count /* IN/OUT */,
866 				  unsigned int *point_array /* OUT */) const
867   { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
868 
get_lig_caretsOT::GDEF869   unsigned int get_lig_carets (hb_font_t *font,
870 			       hb_direction_t direction,
871 			       hb_codepoint_t glyph_id,
872 			       unsigned int start_offset,
873 			       unsigned int *caret_count /* IN/OUT */,
874 			       hb_position_t *caret_array /* OUT */) const
875   { return get_lig_caret_list ().get_lig_carets (font,
876 						 direction, glyph_id, get_var_store(),
877 						 start_offset, caret_count, caret_array); }
878 
mark_set_coversOT::GDEF879   bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
880   { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
881 
882   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
883    * glyph class and other bits, and high 8-bit the mark attachment type (if any).
884    * Not to be confused with lookup_props which is very similar. */
get_glyph_propsOT::GDEF885   unsigned int get_glyph_props (hb_codepoint_t glyph) const
886   {
887     unsigned int klass = get_glyph_class (glyph);
888 
889     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
890     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
891     static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
892 
893     switch (klass) {
894     default:			return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
895     case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
896     case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
897     case MarkGlyph:
898 	  klass = get_mark_attachment_type (glyph);
899 	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
900     }
901   }
902 
903   HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
904 				   hb_face_t *face) const;
905 
906   struct accelerator_t
907   {
accelerator_tOT::GDEF::accelerator_t908     accelerator_t (hb_face_t *face)
909     {
910       table = hb_sanitize_context_t ().reference_table<GDEF> (face);
911       if (unlikely (table->is_blocklisted (table.get_blob (), face)))
912       {
913 	hb_blob_destroy (table.get_blob ());
914 	table = hb_blob_get_empty ();
915       }
916 
917 #ifndef HB_NO_GDEF_CACHE
918       table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
919 #endif
920     }
~accelerator_tOT::GDEF::accelerator_t921     ~accelerator_t () { table.destroy (); }
922 
get_glyph_propsOT::GDEF::accelerator_t923     unsigned int get_glyph_props (hb_codepoint_t glyph) const
924     {
925       unsigned v;
926 
927 #ifndef HB_NO_GDEF_CACHE
928       if (glyph_props_cache.get (glyph, &v))
929         return v;
930 #endif
931 
932       v = table->get_glyph_props (glyph);
933 
934 #ifndef HB_NO_GDEF_CACHE
935       if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
936 	glyph_props_cache.set (glyph, v);
937 #endif
938 
939       return v;
940 
941     }
942 
mark_set_coversOT::GDEF::accelerator_t943     bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
944     {
945       return
946 #ifndef HB_NO_GDEF_CACHE
947 	     mark_glyph_set_digests[set_index].may_have (glyph_id) &&
948 #endif
949 	     table->mark_set_covers (set_index, glyph_id);
950     }
951 
952     hb_blob_ptr_t<GDEF> table;
953 #ifndef HB_NO_GDEF_CACHE
954     hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
955     mutable hb_cache_t<21, 3, 8> glyph_props_cache;
956 #endif
957   };
958 
collect_variation_indicesOT::GDEF959   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
960   { get_lig_caret_list ().collect_variation_indices (c); }
961 
remap_layout_variation_indicesOT::GDEF962   void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
963 				       const hb_vector_t<int>& normalized_coords,
964 				       bool calculate_delta, /* not pinned at default */
965 				       bool no_variations, /* all axes pinned */
966 				       hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
967   {
968     if (!has_var_store ()) return;
969     const VariationStore &var_store = get_var_store ();
970     float *store_cache = var_store.create_cache ();
971 
972     unsigned new_major = 0, new_minor = 0;
973     unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
974     for (unsigned idx : layout_variation_indices->iter ())
975     {
976       int delta = 0;
977       if (calculate_delta)
978         delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
979                                              normalized_coords.length, store_cache));
980 
981       if (no_variations)
982       {
983         layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
984         continue;
985       }
986 
987       uint16_t major = idx >> 16;
988       if (major >= var_store.get_sub_table_count ()) break;
989       if (major != last_major)
990       {
991 	new_minor = 0;
992 	++new_major;
993       }
994 
995       unsigned new_idx = (new_major << 16) + new_minor;
996       layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
997       ++new_minor;
998       last_major = major;
999     }
1000     var_store.destroy_cache (store_cache);
1001   }
1002 
1003   protected:
1004   union {
1005   FixedVersion<>		version;	/* Version identifier */
1006   GDEFVersion1_2<SmallTypes>	version1;
1007 #ifndef HB_NO_BEYOND_64K
1008   GDEFVersion1_2<MediumTypes>	version2;
1009 #endif
1010   } u;
1011   public:
1012   DEFINE_SIZE_MIN (4);
1013 };
1014 
1015 struct GDEF_accelerator_t : GDEF::accelerator_t {
GDEF_accelerator_tOT::GDEF_accelerator_t1016   GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
1017 };
1018 
1019 } /* namespace OT */
1020 
1021 
1022 #endif /* OT_LAYOUT_GDEF_GDEF_HH */
1023