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>
StructAtOffsetOrNull(const void * P,unsigned int offset)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 
calcOffSize(unsigned int dataSize)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
59 {
60   hb_codepoint_t  code;
61   hb_codepoint_t  glyph;
62 };
63 
64 typedef hb_vector_t<char, 1> StrBuff;
65 struct StrBuffArray : hb_vector_t<StrBuff>
66 {
finiCFF::StrBuffArray67   void fini () { SUPER::fini_deep (); }
68 
total_sizeCFF::StrBuffArray69   unsigned int total_size () const
70   {
71     unsigned int size = 0;
72     for (unsigned int i = 0; i < len; i++)
73       size += (*this)[i].len;
74     return size;
75   }
76 
77   private:
78   typedef hb_vector_t<StrBuff> SUPER;
79 };
80 
81 /* CFF INDEX */
82 template <typename COUNT>
83 struct CFFIndex
84 {
sanitizeCFF::CFFIndex85   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 
calculate_offset_array_sizeCFF::CFFIndex94   static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
95   { return offSize * (count + 1); }
96 
offset_array_sizeCFF::CFFIndex97   unsigned int offset_array_size () const
98   { return calculate_offset_array_size (offSize, count); }
99 
calculate_serialized_sizeCFF::CFFIndex100   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 
serializeCFF::CFFIndex108   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 
serializeCFF::CFFIndex118   bool serialize (hb_serialize_context_t *c,
119 		  unsigned int offSize_,
120 		  const ByteStrArray &byteArray)
121   {
122     TRACE_SERIALIZE (this);
123     if (byteArray.len == 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.len);
134       this->offSize.set (offSize_);
135       if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
136 	return_trace (false);
137 
138       /* serialize indices */
139       unsigned int  offset = 1;
140       unsigned int  i = 0;
141       for (; i < byteArray.len; 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.len; i++)
150       {
151 	ByteStr  *dest = c->start_embed<ByteStr> ();
152 	if (unlikely (dest == nullptr ||
153 		      !dest->serialize (c, byteArray[i])))
154 	  return_trace (false);
155       }
156     }
157     return_trace (true);
158   }
159 
serializeCFF::CFFIndex160   bool serialize (hb_serialize_context_t *c,
161 		  unsigned int offSize_,
162 		  const StrBuffArray &buffArray)
163   {
164     ByteStrArray  byteArray;
165     byteArray.init ();
166     byteArray.resize (buffArray.len);
167     for (unsigned int i = 0; i < byteArray.len; i++)
168     {
169       byteArray[i] = ByteStr (buffArray[i].arrayZ (), buffArray[i].len);
170     }
171     bool result = this->serialize (c, offSize_, byteArray);
172     byteArray.fini ();
173     return result;
174   }
175 
set_offset_atCFF::CFFIndex176   void set_offset_at (unsigned int index, unsigned int offset)
177   {
178     HBUINT8 *p = offsets + offSize * index + offSize;
179     unsigned int size = offSize;
180     for (; size; size--)
181     {
182       --p;
183       p->set (offset & 0xFF);
184       offset >>= 8;
185     }
186   }
187 
offset_atCFF::CFFIndex188   unsigned int offset_at (unsigned int index) const
189   {
190     assert (index <= count);
191     const HBUINT8 *p = offsets + offSize * index;
192     unsigned int size = offSize;
193     unsigned int offset = 0;
194     for (; size; size--)
195       offset = (offset << 8) + *p++;
196     return offset;
197   }
198 
length_atCFF::CFFIndex199   unsigned int length_at (unsigned int index) const
200   {
201 	if (likely ((offset_at (index + 1) >= offset_at (index)) &&
202 		    (offset_at (index + 1) <= offset_at (count))))
203 	  return offset_at (index + 1) - offset_at (index);
204 	else
205 	  return 0;
206   }
207 
data_baseCFF::CFFIndex208   const char *data_base () const
209   { return (const char *)this + min_size + offset_array_size (); }
210 
data_sizeCFF::CFFIndex211   unsigned int data_size () const { return HBINT8::static_size; }
212 
operator []CFF::CFFIndex213   ByteStr operator [] (unsigned int index) const
214   {
215     if (likely (index < count))
216       return ByteStr (data_base () + offset_at (index) - 1, length_at (index));
217     else
218       return Null(ByteStr);
219   }
220 
get_sizeCFF::CFFIndex221   unsigned int get_size () const
222   {
223     if (this != &Null(CFFIndex))
224     {
225       if (count > 0)
226 	return min_size + offset_array_size () + (offset_at (count) - 1);
227       else
228 	return count.static_size;  /* empty CFFIndex contains count only */
229     }
230     else
231       return 0;
232   }
233 
234   protected:
max_offsetCFF::CFFIndex235   unsigned int max_offset () const
236   {
237     unsigned int max = 0;
238     for (unsigned int i = 0; i < count + 1u; i++)
239     {
240       unsigned int off = offset_at (i);
241       if (off > max) max = off;
242     }
243     return max;
244   }
245 
246   public:
247   COUNT     count;	/* Number of object data. Note there are (count+1) offsets */
248   HBUINT8   offSize;      /* The byte size of each offset in the offsets array. */
249   HBUINT8   offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
250   /* HBUINT8 data[VAR];      Object data */
251   public:
252   DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
253 };
254 
255 template <typename COUNT, typename TYPE>
256 struct CFFIndexOf : CFFIndex<COUNT>
257 {
operator []CFF::CFFIndexOf258   const ByteStr operator [] (unsigned int index) const
259   {
260     if (likely (index < CFFIndex<COUNT>::count))
261       return ByteStr (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
262     return Null(ByteStr);
263   }
264 
265   template <typename DATA, typename PARAM1, typename PARAM2>
serializeCFF::CFFIndexOf266   bool serialize (hb_serialize_context_t *c,
267 		  unsigned int offSize_,
268 		  const DATA *dataArray,
269 		  unsigned int dataArrayLen,
270 		  const hb_vector_t<unsigned int> &dataSizeArray,
271 		  const PARAM1 &param1,
272 		  const PARAM2 &param2)
273   {
274     TRACE_SERIALIZE (this);
275     /* serialize CFFIndex header */
276     if (unlikely (!c->extend_min (*this))) return_trace (false);
277     this->count.set (dataArrayLen);
278     this->offSize.set (offSize_);
279     if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
280       return_trace (false);
281 
282     /* serialize indices */
283     unsigned int  offset = 1;
284     unsigned int  i = 0;
285     for (; i < dataArrayLen; i++)
286     {
287       CFFIndex<COUNT>::set_offset_at (i, offset);
288       offset += dataSizeArray[i];
289     }
290     CFFIndex<COUNT>::set_offset_at (i, offset);
291 
292     /* serialize data */
293     for (unsigned int i = 0; i < dataArrayLen; i++)
294     {
295       TYPE  *dest = c->start_embed<TYPE> ();
296       if (unlikely (dest == nullptr ||
297 		    !dest->serialize (c, dataArray[i], param1, param2)))
298 	return_trace (false);
299     }
300     return_trace (true);
301   }
302 
303   /* in parallel to above */
304   template <typename DATA, typename PARAM>
calculate_serialized_sizeCFF::CFFIndexOf305   static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
306 						 const DATA *dataArray,
307 						 unsigned int dataArrayLen,
308 						 hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
309 						 const PARAM &param)
310   {
311     /* determine offset size */
312     unsigned int  totalDataSize = 0;
313     for (unsigned int i = 0; i < dataArrayLen; i++)
314     {
315       unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
316       dataSizeArray[i] = dataSize;
317       totalDataSize += dataSize;
318     }
319     offSize_ = calcOffSize (totalDataSize);
320 
321     return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize);
322   }
323 };
324 
325 /* Top Dict, Font Dict, Private Dict */
326 struct Dict : UnsizedByteStr
327 {
328   template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
serializeCFF::Dict329   bool serialize (hb_serialize_context_t *c,
330 		  const DICTVAL &dictval,
331 		  OP_SERIALIZER& opszr,
332 		  PARAM& param)
333   {
334     TRACE_SERIALIZE (this);
335     for (unsigned int i = 0; i < dictval.get_count (); i++)
336     {
337       if (unlikely (!opszr.serialize (c, dictval[i], param)))
338 	return_trace (false);
339     }
340     return_trace (true);
341   }
342 
343   /* in parallel to above */
344   template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
calculate_serialized_sizeCFF::Dict345   static unsigned int calculate_serialized_size (const DICTVAL &dictval,
346 						 OP_SERIALIZER& opszr,
347 						 PARAM& param)
348   {
349     unsigned int size = 0;
350     for (unsigned int i = 0; i < dictval.get_count (); i++)
351       size += opszr.calculate_serialized_size (dictval[i], param);
352     return size;
353   }
354 
355   template <typename DICTVAL, typename OP_SERIALIZER>
calculate_serialized_sizeCFF::Dict356   static unsigned int calculate_serialized_size (const DICTVAL &dictval,
357 						 OP_SERIALIZER& opszr)
358   {
359     unsigned int size = 0;
360     for (unsigned int i = 0; i < dictval.get_count (); i++)
361       size += opszr.calculate_serialized_size (dictval[i]);
362     return size;
363   }
364 
365   template <typename INTTYPE, int minVal, int maxVal>
serialize_int_opCFF::Dict366   static bool serialize_int_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp)
367   {
368     // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
369     if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
370       return false;
371 
372     TRACE_SERIALIZE (this);
373     /* serialize the opcode */
374     HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
375     if (unlikely (p == nullptr)) return_trace (false);
376     if (Is_OpCode_ESC (op))
377     {
378       p->set (OpCode_escape);
379       op = Unmake_OpCode_ESC (op);
380       p++;
381     }
382     p->set (op);
383     return_trace (true);
384   }
385 
serialize_uint4_opCFF::Dict386   static bool serialize_uint4_op (hb_serialize_context_t *c, OpCode op, int value)
387   { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
388 
serialize_uint2_opCFF::Dict389   static bool serialize_uint2_op (hb_serialize_context_t *c, OpCode op, int value)
390   { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
391 
serialize_offset4_opCFF::Dict392   static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value)
393   {
394     return serialize_uint4_op (c, op, value);
395   }
396 
serialize_offset2_opCFF::Dict397   static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value)
398   {
399     return serialize_uint2_op (c, op, value);
400   }
401 };
402 
403 struct TopDict : Dict {};
404 struct FontDict : Dict {};
405 struct PrivateDict : Dict {};
406 
407 struct TableInfo
408 {
initCFF::TableInfo409   void init () { offSize = offset = size = 0; }
410 
411   unsigned int    offset;
412   unsigned int    size;
413   unsigned int    offSize;
414 };
415 
416 /* used to remap font index or SID from fullset to subset.
417  * set to CFF_UNDEF_CODE if excluded from subset */
418 struct Remap : hb_vector_t<hb_codepoint_t>
419 {
initCFF::Remap420   void init () { SUPER::init (); }
421 
finiCFF::Remap422   void fini () { SUPER::fini (); }
423 
resetCFF::Remap424   bool reset (unsigned int size)
425   {
426     if (unlikely (!SUPER::resize (size)))
427       return false;
428     for (unsigned int i = 0; i < len; i++)
429       (*this)[i] = CFF_UNDEF_CODE;
430     count = 0;
431     return true;
432   }
433 
identityCFF::Remap434   bool identity (unsigned int size)
435   {
436     if (unlikely (!SUPER::resize (size)))
437       return false;
438     unsigned int i;
439     for (i = 0; i < len; i++)
440       (*this)[i] = i;
441     count = i;
442     return true;
443   }
444 
excludesCFF::Remap445   bool excludes (hb_codepoint_t id) const
446   { return (id < len) && ((*this)[id] == CFF_UNDEF_CODE); }
447 
includesCFF::Remap448   bool includes (hb_codepoint_t id) const
449   { return !excludes (id); }
450 
addCFF::Remap451   unsigned int add (unsigned int i)
452   {
453     if ((*this)[i] == CFF_UNDEF_CODE)
454       (*this)[i] = count++;
455     return (*this)[i];
456   }
457 
get_countCFF::Remap458   hb_codepoint_t get_count () const { return count; }
459 
460   protected:
461   hb_codepoint_t  count;
462 
463   private:
464   typedef hb_vector_t<hb_codepoint_t> SUPER;
465 };
466 
467 template <typename COUNT>
468 struct FDArray : CFFIndexOf<COUNT, FontDict>
469 {
470   /* used by CFF1 */
471   template <typename DICTVAL, typename OP_SERIALIZER>
serializeCFF::FDArray472   bool serialize (hb_serialize_context_t *c,
473 		  unsigned int offSize_,
474 		  const hb_vector_t<DICTVAL> &fontDicts,
475 		  OP_SERIALIZER& opszr)
476   {
477     TRACE_SERIALIZE (this);
478     if (unlikely (!c->extend_min (*this))) return_trace (false);
479     this->count.set (fontDicts.len);
480     this->offSize.set (offSize_);
481     if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.len + 1))))
482       return_trace (false);
483 
484     /* serialize font dict offsets */
485     unsigned int  offset = 1;
486     unsigned int fid = 0;
487     for (; fid < fontDicts.len; fid++)
488     {
489       CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
490       offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
491     }
492     CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
493 
494     /* serialize font dicts */
495     for (unsigned int i = 0; i < fontDicts.len; i++)
496     {
497       FontDict *dict = c->start_embed<FontDict> ();
498       if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
499 	return_trace (false);
500     }
501     return_trace (true);
502   }
503 
504   /* used by CFF2 */
505   template <typename DICTVAL, typename OP_SERIALIZER>
serializeCFF::FDArray506   bool serialize (hb_serialize_context_t *c,
507 		  unsigned int offSize_,
508 		  const hb_vector_t<DICTVAL> &fontDicts,
509 		  unsigned int fdCount,
510 		  const Remap &fdmap,
511 		  OP_SERIALIZER& opszr,
512 		  const hb_vector_t<TableInfo> &privateInfos)
513   {
514     TRACE_SERIALIZE (this);
515     if (unlikely (!c->extend_min (*this))) return_trace (false);
516     this->count.set (fdCount);
517     this->offSize.set (offSize_);
518     if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
519       return_trace (false);
520 
521     /* serialize font dict offsets */
522     unsigned int  offset = 1;
523     unsigned int  fid = 0;
524     for (unsigned i = 0; i < fontDicts.len; i++)
525       if (fdmap.includes (i))
526       {
527 	CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
528 	offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
529       }
530     CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
531 
532     /* serialize font dicts */
533     for (unsigned int i = 0; i < fontDicts.len; i++)
534       if (fdmap.includes (i))
535       {
536 	FontDict *dict = c->start_embed<FontDict> ();
537 	if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
538 	  return_trace (false);
539       }
540     return_trace (true);
541   }
542 
543   /* in parallel to above */
544   template <typename OP_SERIALIZER, typename DICTVAL>
calculate_serialized_sizeCFF::FDArray545   static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
546 						 const hb_vector_t<DICTVAL> &fontDicts,
547 						 unsigned int fdCount,
548 						 const Remap &fdmap,
549 						 OP_SERIALIZER& opszr)
550   {
551     unsigned int dictsSize = 0;
552     for (unsigned int i = 0; i < fontDicts.len; i++)
553       if (fdmap.includes (i))
554 	dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
555 
556     offSize_ = calcOffSize (dictsSize);
557     return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
558   }
559 };
560 
561 /* FDSelect */
562 struct FDSelect0 {
sanitizeCFF::FDSelect0563   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
564   {
565     TRACE_SANITIZE (this);
566     if (unlikely (!(c->check_struct (this))))
567       return_trace (false);
568     for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
569       if (unlikely (!fds[i].sanitize (c)))
570 	return_trace (false);
571 
572     return_trace (true);
573   }
574 
get_fdCFF::FDSelect0575   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
576   {
577     return (hb_codepoint_t)fds[glyph];
578   }
579 
get_sizeCFF::FDSelect0580   unsigned int get_size (unsigned int num_glyphs) const
581   { return HBUINT8::static_size * num_glyphs; }
582 
583   HBUINT8     fds[VAR];
584 
585   DEFINE_SIZE_MIN (1);
586 };
587 
588 template <typename GID_TYPE, typename FD_TYPE>
589 struct FDSelect3_4_Range {
sanitizeCFF::FDSelect3_4_Range590   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
591   {
592     TRACE_SANITIZE (this);
593     return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ()) && (fd < fdcount)));
594   }
595 
596   GID_TYPE    first;
597   FD_TYPE     fd;
598 
599   DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
600 };
601 
602 template <typename GID_TYPE, typename FD_TYPE>
603 struct FDSelect3_4 {
get_sizeCFF::FDSelect3_4604   unsigned int get_size () const
605   { return GID_TYPE::static_size * 2 + FDSelect3_4_Range<GID_TYPE, FD_TYPE>::static_size * nRanges; }
606 
sanitizeCFF::FDSelect3_4607   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
608   {
609     TRACE_SANITIZE (this);
610     if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0))))
611       return_trace (false);
612 
613     for (unsigned int i = 0; i < nRanges; i++)
614     {
615       if (unlikely (!ranges[i].sanitize (c, fdcount)))
616 	return_trace (false);
617       if ((0 < i) && unlikely (ranges[i - 1].first >= ranges[i].first))
618 	return_trace (false);
619     }
620     if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
621       return_trace (false);
622 
623     return_trace (true);
624   }
625 
get_fdCFF::FDSelect3_4626   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
627   {
628     unsigned int i;
629     for (i = 1; i < nRanges; i++)
630       if (glyph < ranges[i].first)
631 	break;
632 
633     return (hb_codepoint_t)ranges[i - 1].fd;
634   }
635 
sentinelCFF::FDSelect3_4636   GID_TYPE &sentinel ()  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
sentinelCFF::FDSelect3_4637   const GID_TYPE &sentinel () const  { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
638 
639   GID_TYPE	 nRanges;
640   FDSelect3_4_Range<GID_TYPE, FD_TYPE>  ranges[VAR];
641   /* GID_TYPE sentinel */
642 
643   DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges);
644 };
645 
646 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
647 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
648 
649 struct FDSelect {
sanitizeCFF::FDSelect650   bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
651   {
652     TRACE_SANITIZE (this);
653 
654     return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
655 			  (format == 0)?
656 			  u.format0.sanitize (c, fdcount):
657 			  u.format3.sanitize (c, fdcount)));
658   }
659 
serializeCFF::FDSelect660   bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
661   {
662     TRACE_SERIALIZE (this);
663     unsigned int size = src.get_size (num_glyphs);
664     FDSelect *dest = c->allocate_size<FDSelect> (size);
665     if (unlikely (dest == nullptr)) return_trace (false);
666     memcpy (dest, &src, size);
667     return_trace (true);
668   }
669 
calculate_serialized_sizeCFF::FDSelect670   unsigned int calculate_serialized_size (unsigned int num_glyphs) const
671   { return get_size (num_glyphs); }
672 
get_sizeCFF::FDSelect673   unsigned int get_size (unsigned int num_glyphs) const
674   {
675     unsigned int size = format.static_size;
676     if (format == 0)
677       size += u.format0.get_size (num_glyphs);
678     else
679       size += u.format3.get_size ();
680     return size;
681   }
682 
get_fdCFF::FDSelect683   hb_codepoint_t get_fd (hb_codepoint_t glyph) const
684   {
685     if (this == &Null(FDSelect))
686       return 0;
687     if (format == 0)
688       return u.format0.get_fd (glyph);
689     else
690       return u.format3.get_fd (glyph);
691   }
692 
693   HBUINT8       format;
694   union {
695     FDSelect0   format0;
696     FDSelect3   format3;
697   } u;
698 
699   DEFINE_SIZE_MIN (1);
700 };
701 
702 template <typename COUNT>
703 struct Subrs : CFFIndex<COUNT>
704 {
705   typedef COUNT count_type;
706   typedef CFFIndex<COUNT> SUPER;
707 };
708 
709 } /* namespace CFF */
710 
711 #endif /* HB_OT_CFF_COMMON_HH */
712