Imported Upstream version 2.4.0
[platform/upstream/harfbuzz.git] / src / hb-ot-cff-common.hh
1 /*
2  * Copyright © 2018 Adobe Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Adobe Author(s): Michiharu Ariza
25  */
26 #ifndef HB_OT_CFF_COMMON_HH
27 #define HB_OT_CFF_COMMON_HH
28
29 #include "hb-open-type.hh"
30 #include "hb-ot-layout-common.hh"
31 #include "hb-cff-interp-dict-common.hh"
32 #include "hb-subset-plan.hh"
33
34 namespace CFF {
35
36 using namespace OT;
37
38 #define CFF_UNDEF_CODE  0xFFFFFFFF
39
40 /* utility macro */
41 template<typename Type>
42 static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
43 { return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
44
45 inline unsigned int calcOffSize(unsigned int dataSize)
46 {
47   unsigned int size = 1;
48   unsigned int offset = dataSize + 1;
49   while ((offset & ~0xFF) != 0)
50   {
51     size++;
52     offset >>= 8;
53   }
54   /* format does not support size > 4; caller should handle it as an error */
55   return size;
56 }
57
58 struct code_pair_t
59 {
60   hb_codepoint_t  code;
61   hb_codepoint_t  glyph;
62 };
63
64 typedef hb_vector_t<unsigned char> str_buff_t;
65 struct str_buff_vec_t : hb_vector_t<str_buff_t>
66 {
67   void fini () { SUPER::fini_deep (); }
68
69   unsigned int total_size () const
70   {
71     unsigned int size = 0;
72     for (unsigned int i = 0; i < length; i++)
73       size += (*this)[i].length;
74     return size;
75   }
76
77   private:
78   typedef hb_vector_t<str_buff_t> SUPER;
79 };
80
81 /* CFF INDEX */
82 template <typename COUNT>
83 struct CFFIndex
84 {
85   bool sanitize (hb_sanitize_context_t *c) const
86   {
87     TRACE_SANITIZE (this);
88     return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
89                           (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
90                            c->check_array (offsets, offSize, count + 1) &&
91                            c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
92   }
93
94   static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
95   { return offSize * (count + 1); }
96
97   unsigned int offset_array_size () const
98   { return calculate_offset_array_size (offSize, count); }
99
100   static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
101   {
102     if (count == 0)
103       return COUNT::static_size;
104     else
105       return min_size + calculate_offset_array_size (offSize, count) + dataSize;
106   }
107
108   bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
109   {
110     TRACE_SERIALIZE (this);
111     unsigned int size = src.get_size ();
112     CFFIndex *dest = c->allocate_size<CFFIndex> (size);
113     if (unlikely (dest == nullptr)) return_trace (false);
114     memcpy (dest, &src, size);
115     return_trace (true);
116   }
117
118   bool serialize (hb_serialize_context_t *c,
119                   unsigned int offSize_,
120                   const byte_str_array_t &byteArray)
121   {
122     TRACE_SERIALIZE (this);
123     if (byteArray.length == 0)
124     {
125       COUNT *dest = c->allocate_min<COUNT> ();
126       if (unlikely (dest == nullptr)) return_trace (false);
127       dest->set (0);
128     }
129     else
130     {
131       /* serialize CFFIndex header */
132       if (unlikely (!c->extend_min (*this))) return_trace (false);
133       this->count.set (byteArray.length);
134       this->offSize.set (offSize_);
135       if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
136         return_trace (false);
137
138       /* serialize indices */
139       unsigned int  offset = 1;
140       unsigned int  i = 0;
141       for (; i < byteArray.length; i++)
142       {
143         set_offset_at (i, offset);
144         offset += byteArray[i].get_size ();
145       }
146       set_offset_at (i, offset);
147
148       /* serialize data */
149       for (unsigned int i = 0; i < byteArray.length; i++)
150       {
151         const byte_str_t &bs = byteArray[i];
152         unsigned char  *dest = c->allocate_size<unsigned char> (bs.length);
153         if (unlikely (dest == nullptr))
154           return_trace (false);
155         memcpy (dest, &bs[0], bs.length);
156       }
157     }
158     return_trace (true);
159   }
160
161   bool serialize (hb_serialize_context_t *c,
162                   unsigned int offSize_,
163                   const str_buff_vec_t &buffArray)
164   {
165     byte_str_array_t  byteArray;
166     byteArray.init ();
167     byteArray.resize (buffArray.length);
168     for (unsigned int i = 0; i < byteArray.length; i++)
169     {
170       byteArray[i] = byte_str_t (buffArray[i].arrayZ (), buffArray[i].length);
171     }
172     bool result = this->serialize (c, offSize_, byteArray);
173     byteArray.fini ();
174     return result;
175   }
176
177   void set_offset_at (unsigned int index, unsigned int offset)
178   {
179     HBUINT8 *p = offsets + offSize * index + offSize;
180     unsigned int size = offSize;
181     for (; size; size--)
182     {
183       --p;
184       p->set (offset & 0xFF);
185       offset >>= 8;
186     }
187   }
188
189   unsigned int offset_at (unsigned int index) const
190   {
191     assert (index <= count);
192     const HBUINT8 *p = offsets + offSize * index;
193     unsigned int size = offSize;
194     unsigned int offset = 0;
195     for (; size; size--)
196       offset = (offset << 8) + *p++;
197     return offset;
198   }
199
200   unsigned int length_at (unsigned int index) const
201   {
202         if (likely ((offset_at (index + 1) >= offset_at (index)) &&
203                     (offset_at (index + 1) <= offset_at (count))))
204           return offset_at (index + 1) - offset_at (index);
205         else
206           return 0;
207   }
208
209   const unsigned char *data_base () const
210   { return (const unsigned char *)this + min_size + offset_array_size (); }
211
212   unsigned int data_size () const { return HBINT8::static_size; }
213
214   byte_str_t operator [] (unsigned int index) const
215   {
216     if (likely (index < count))
217       return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
218     else
219       return Null(byte_str_t);
220   }
221
222   unsigned int get_size () const
223   {
224     if (this != &Null(CFFIndex))
225     {
226       if (count > 0)
227         return min_size + offset_array_size () + (offset_at (count) - 1);
228       else
229         return count.static_size;  /* empty CFFIndex contains count only */
230     }
231     else
232       return 0;
233   }
234
235   protected:
236   unsigned int max_offset () const
237   {
238     unsigned int max = 0;
239     for (unsigned int i = 0; i < count + 1u; i++)
240     {
241       unsigned int off = offset_at (i);
242       if (off > max) max = off;
243     }
244     return max;
245   }
246
247   public:
248   COUNT     count;      /* Number of object data. Note there are (count+1) offsets */
249   HBUINT8   offSize;      /* The byte size of each offset in the offsets array. */
250   HBUINT8   offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
251   /* HBUINT8 data[VAR];      Object data */
252   public:
253   DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
254 };
255
256 template <typename COUNT, typename TYPE>
257 struct CFFIndexOf : CFFIndex<COUNT>
258 {
259   const byte_str_t operator [] (unsigned int index) const
260   {
261     if (likely (index < CFFIndex<COUNT>::count))
262       return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
263     return Null(byte_str_t);
264   }
265
266   template <typename DATA, typename PARAM1, typename PARAM2>
267   bool serialize (hb_serialize_context_t *c,
268                   unsigned int offSize_,
269                   const DATA *dataArray,
270                   unsigned int dataArrayLen,
271                   const hb_vector_t<unsigned int> &dataSizeArray,
272                   const PARAM1 &param1,
273                   const PARAM2 &param2)
274   {
275     TRACE_SERIALIZE (this);
276     /* serialize CFFIndex header */
277     if (unlikely (!c->extend_min (*this))) return_trace (false);
278     this->count.set (dataArrayLen);
279     this->offSize.set (offSize_);
280     if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
281       return_trace (false);
282
283     /* serialize indices */
284     unsigned int  offset = 1;
285     unsigned int  i = 0;
286     for (; i < dataArrayLen; i++)
287     {
288       CFFIndex<COUNT>::set_offset_at (i, offset);
289       offset += dataSizeArray[i];
290     }
291     CFFIndex<COUNT>::set_offset_at (i, offset);
292
293     /* serialize data */
294     for (unsigned int i = 0; i < dataArrayLen; i++)
295     {
296       TYPE  *dest = c->start_embed<TYPE> ();
297       if (unlikely (dest == nullptr ||
298                     !dest->serialize (c, dataArray[i], param1, param2)))
299         return_trace (false);
300     }
301     return_trace (true);
302   }
303
304   /* in parallel to above */
305   template <typename DATA, typename PARAM>
306   static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
307                                                  const DATA *dataArray,
308                                                  unsigned int dataArrayLen,
309                                                  hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
310                                                  const PARAM &param)
311   {
312     /* determine offset size */
313     unsigned int  totalDataSize = 0;
314     for (unsigned int i = 0; i < dataArrayLen; i++)
315     {
316       unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
317       dataSizeArray[i] = dataSize;
318       totalDataSize += dataSize;
319     }
320     offSize_ = calcOffSize (totalDataSize);
321
322     return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize);
323   }
324 };
325
326 /* Top Dict, Font Dict, Private Dict */
327 struct Dict : UnsizedByteStr
328 {
329   template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
330   bool serialize (hb_serialize_context_t *c,
331                   const DICTVAL &dictval,
332                   OP_SERIALIZER& opszr,
333                   PARAM& param)
334   {
335     TRACE_SERIALIZE (this);
336     for (unsigned int i = 0; i < dictval.get_count (); i++)
337     {
338       if (unlikely (!opszr.serialize (c, dictval[i], param)))
339         return_trace (false);
340     }
341     return_trace (true);
342   }
343
344   /* in parallel to above */
345   template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
346   static unsigned int calculate_serialized_size (const DICTVAL &dictval,
347                                                  OP_SERIALIZER& opszr,
348                                                  PARAM& param)
349   {
350     unsigned int size = 0;
351     for (unsigned int i = 0; i < dictval.get_count (); i++)
352       size += opszr.calculate_serialized_size (dictval[i], param);
353     return size;
354   }
355
356   template <typename DICTVAL, typename OP_SERIALIZER>
357   static unsigned int calculate_serialized_size (const DICTVAL &dictval,
358                                                  OP_SERIALIZER& opszr)
359   {
360     unsigned int size = 0;
361     for (unsigned int i = 0; i < dictval.get_count (); i++)
362       size += opszr.calculate_serialized_size (dictval[i]);
363     return size;
364   }
365
366   template <typename INTTYPE, int minVal, int maxVal>
367   static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp)
368   {
369     // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
370     if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
371       return false;
372
373     TRACE_SERIALIZE (this);
374     /* serialize the opcode */
375     HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
376     if (unlikely (p == nullptr)) return_trace (false);
377     if (Is_OpCode_ESC (op))
378     {
379       p->set (OpCode_escape);
380       op = Unmake_OpCode_ESC (op);
381       p++;
382     }
383     p->set (op);
384     return_trace (true);
385   }
386
387   static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value)
388   { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
389
390   static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value)
391   { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
392
393   static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
394   {
395     return serialize_uint4_op (c, op, value);
396   }
397
398   static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
399   {
400     return serialize_uint2_op (c, op, value);
401   }
402 };
403
404 struct TopDict : Dict {};
405 struct FontDict : Dict {};
406 struct PrivateDict : Dict {};
407
408 struct table_info_t
409 {
410   void init () { offSize = offset = size = 0; }
411
412   unsigned int    offset;
413   unsigned int    size;
414   unsigned int    offSize;
415 };
416
417 /* used to remap font index or SID from fullset to subset.
418  * set to CFF_UNDEF_CODE if excluded from subset */
419 struct remap_t : hb_vector_t<hb_codepoint_t>
420 {
421   void init () { SUPER::init (); }
422
423   void fini () { SUPER::fini (); }
424
425   bool reset (unsigned int size)
426   {
427     if (unlikely (!SUPER::resize (size)))
428       return false;
429     for (unsigned int i = 0; i < length; i++)
430       (*this)[i] = CFF_UNDEF_CODE;
431     count = 0;
432     return true;
433   }
434
435   bool identity (unsigned int size)
436   {
437     if (unlikely (!SUPER::resize (size)))
438       return false;
439     unsigned int i;
440     for (i = 0; i < length; i++)
441       (*this)[i] = i;
442     count = i;
443     return true;
444   }
445
446   bool excludes (hb_codepoint_t id) const
447   { return (id < length) && ((*this)[id] == CFF_UNDEF_CODE); }
448
449   bool includes (hb_codepoint_t id) const
450   { return !excludes (id); }
451
452   unsigned int add (unsigned int i)
453   {
454     if ((*this)[i] == CFF_UNDEF_CODE)
455       (*this)[i] = count++;
456     return (*this)[i];
457   }
458
459   hb_codepoint_t get_count () const { return count; }
460
461   protected:
462   hb_codepoint_t  count;
463
464   private:
465   typedef hb_vector_t<hb_codepoint_t> SUPER;
466 };
467
468 template <typename COUNT>
469 struct FDArray : CFFIndexOf<COUNT, FontDict>
470 {
471   /* used by CFF1 */
472   template <typename DICTVAL, typename OP_SERIALIZER>
473   bool serialize (hb_serialize_context_t *c,
474                   unsigned int offSize_,
475                   const hb_vector_t<DICTVAL> &fontDicts,
476                   OP_SERIALIZER& opszr)
477   {
478     TRACE_SERIALIZE (this);
479     if (unlikely (!c->extend_min (*this))) return_trace (false);
480     this->count.set (fontDicts.length);
481     this->offSize.set (offSize_);
482     if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
483       return_trace (false);
484
485     /* serialize font dict offsets */
486     unsigned int  offset = 1;
487     unsigned int fid = 0;
488     for (; fid < fontDicts.length; fid++)
489     {
490       CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
491       offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
492     }
493     CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
494
495     /* serialize font dicts */
496     for (unsigned int i = 0; i < fontDicts.length; i++)
497     {
498       FontDict *dict = c->start_embed<FontDict> ();
499       if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
500         return_trace (false);
501     }
502     return_trace (true);
503   }
504
505   /* used by CFF2 */
506   template <typename DICTVAL, typename OP_SERIALIZER>
507   bool serialize (hb_serialize_context_t *c,
508                   unsigned int offSize_,
509                   const hb_vector_t<DICTVAL> &fontDicts,
510                   unsigned int fdCount,
511                   const remap_t &fdmap,
512                   OP_SERIALIZER& opszr,
513                   const hb_vector_t<table_info_t> &privateInfos)
514   {
515     TRACE_SERIALIZE (this);
516     if (unlikely (!c->extend_min (*this))) return_trace (false);
517     this->count.set (fdCount);
518     this->offSize.set (offSize_);
519     if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
520       return_trace (false);
521
522     /* serialize font dict offsets */
523     unsigned int  offset = 1;
524     unsigned int  fid = 0;
525     for (unsigned i = 0; i < fontDicts.length; i++)
526       if (fdmap.includes (i))
527       {
528         if (unlikely (fid >= fdCount)) return_trace (false);
529         CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
530         offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
531       }
532     CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
533
534     /* serialize font dicts */
535     for (unsigned int i = 0; i < fontDicts.length; i++)
536       if (fdmap.includes (i))
537       {
538         FontDict *dict = c->start_embed<FontDict> ();
539         if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
540           return_trace (false);
541       }
542     return_trace (true);
543   }
544
545   /* in parallel to above */
546   template <typename OP_SERIALIZER, typename DICTVAL>
547   static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
548                                                  const hb_vector_t<DICTVAL> &fontDicts,
549                                                  unsigned int fdCount,
550                                                  const remap_t &fdmap,
551                                                  OP_SERIALIZER& opszr)
552   {
553     unsigned int dictsSize = 0;
554     for (unsigned int i = 0; i < fontDicts.len; i++)
555       if (fdmap.includes (i))
556         dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
557
558     offSize_ = calcOffSize (dictsSize);
559     return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
560   }
561 };
562
563 /* FDSelect */
564 struct FDSelect0 {
565   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
566   {
567     TRACE_SANITIZE (this);
568     if (unlikely (!(c->check_struct (this))))
569       return_trace (false);
570     for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
571       if (unlikely (!fds[i].sanitize (c)))
572         return_trace (false);
573
574     return_trace (true);
575   }
576
577   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
578   {
579     return (hb_codepoint_t)fds[glyph];
580   }
581
582   unsigned int get_size (unsigned int num_glyphs) const
583   { return HBUINT8::static_size * num_glyphs; }
584
585   HBUINT8     fds[VAR];
586
587   DEFINE_SIZE_MIN (1);
588 };
589
590 template <typename GID_TYPE, typename FD_TYPE>
591 struct FDSelect3_4_Range {
592   bool sanitize (hb_sanitize_context_t *c, const void */*nullptr*/, unsigned int fdcount) const
593   {
594     TRACE_SANITIZE (this);
595     return_trace (first < c->get_num_glyphs () && (fd < fdcount));
596   }
597
598   GID_TYPE    first;
599   FD_TYPE     fd;
600
601   DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
602 };
603
604 template <typename GID_TYPE, typename FD_TYPE>
605 struct FDSelect3_4 {
606   unsigned int get_size () const
607   { return GID_TYPE::static_size * 2 + ranges.get_size (); }
608
609   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
610   {
611     TRACE_SANITIZE (this);
612     if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) ||
613                   (nRanges () == 0) || ranges[0].first != 0))
614       return_trace (false);
615
616     for (unsigned int i = 1; i < nRanges (); i++)
617     {
618       if (unlikely (ranges[i - 1].first >= ranges[i].first))
619           return_trace (false);
620     }
621
622     if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
623       return_trace (false);
624
625     return_trace (true);
626   }
627
628   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
629   {
630     unsigned int i;
631     for (i = 1; i < nRanges (); i++)
632       if (glyph < ranges[i].first)
633         break;
634
635     return (hb_codepoint_t)ranges[i - 1].fd;
636   }
637
638   GID_TYPE &nRanges () { return ranges.len; }
639   GID_TYPE nRanges () const { return ranges.len; }
640   GID_TYPE &sentinel ()  { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
641   const GID_TYPE &sentinel () const  { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
642
643   ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges;
644   /* GID_TYPE sentinel */
645
646   DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges);
647 };
648
649 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
650 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
651
652 struct FDSelect {
653   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
654   {
655     TRACE_SANITIZE (this);
656
657     return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
658                           (format == 0)?
659                           u.format0.sanitize (c, fdcount):
660                           u.format3.sanitize (c, fdcount)));
661   }
662
663   bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
664   {
665     TRACE_SERIALIZE (this);
666     unsigned int size = src.get_size (num_glyphs);
667     FDSelect *dest = c->allocate_size<FDSelect> (size);
668     if (unlikely (dest == nullptr)) return_trace (false);
669     memcpy (dest, &src, size);
670     return_trace (true);
671   }
672
673   unsigned int calculate_serialized_size (unsigned int num_glyphs) const
674   { return get_size (num_glyphs); }
675
676   unsigned int get_size (unsigned int num_glyphs) const
677   {
678     unsigned int size = format.static_size;
679     if (format == 0)
680       size += u.format0.get_size (num_glyphs);
681     else
682       size += u.format3.get_size ();
683     return size;
684   }
685
686   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
687   {
688     if (this == &Null(FDSelect))
689       return 0;
690     if (format == 0)
691       return u.format0.get_fd (glyph);
692     else
693       return u.format3.get_fd (glyph);
694   }
695
696   HBUINT8       format;
697   union {
698     FDSelect0   format0;
699     FDSelect3   format3;
700   } u;
701
702   DEFINE_SIZE_MIN (1);
703 };
704
705 template <typename COUNT>
706 struct Subrs : CFFIndex<COUNT>
707 {
708   typedef COUNT count_type;
709   typedef CFFIndex<COUNT> SUPER;
710 };
711
712 } /* namespace CFF */
713
714 #endif /* HB_OT_CFF_COMMON_HH */