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-bimap.hh"
31 #include "hb-ot-layout-common.hh"
32 #include "hb-cff-interp-dict-common.hh"
33 #include "hb-subset-plan.hh"
34
35 namespace CFF {
36
37 using namespace OT;
38
39 #define CFF_UNDEF_CODE 0xFFFFFFFF
40
41 /* utility macro */
42 template<typename Type>
StructAtOffsetOrNull(const void * P,unsigned int offset)43 static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
44 { return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
45
calcOffSize(unsigned int dataSize)46 inline unsigned int calcOffSize (unsigned int dataSize)
47 {
48 unsigned int size = 1;
49 unsigned int offset = dataSize + 1;
50 while (offset & ~0xFF)
51 {
52 size++;
53 offset >>= 8;
54 }
55 /* format does not support size > 4; caller should handle it as an error */
56 return size;
57 }
58
59 struct code_pair_t
60 {
61 hb_codepoint_t code;
62 hb_codepoint_t glyph;
63 };
64
65 typedef hb_vector_t<unsigned char> str_buff_t;
66 struct str_buff_vec_t : hb_vector_t<str_buff_t>
67 {
finiCFF::str_buff_vec_t68 void fini () { SUPER::fini_deep (); }
69
total_sizeCFF::str_buff_vec_t70 unsigned int total_size () const
71 {
72 unsigned int size = 0;
73 for (unsigned int i = 0; i < length; i++)
74 size += (*this)[i].length;
75 return size;
76 }
77
78 private:
79 typedef hb_vector_t<str_buff_t> SUPER;
80 };
81
82 /* CFF INDEX */
83 template <typename COUNT>
84 struct CFFIndex
85 {
calculate_offset_array_sizeCFF::CFFIndex86 static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
87 { return offSize * (count + 1); }
88
offset_array_sizeCFF::CFFIndex89 unsigned int offset_array_size () const
90 { return calculate_offset_array_size (offSize, count); }
91
calculate_serialized_sizeCFF::CFFIndex92 static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count,
93 unsigned int dataSize)
94 {
95 if (count == 0) return COUNT::static_size;
96 return min_size + calculate_offset_array_size (offSize_, count) + dataSize;
97 }
98
serializeCFF::CFFIndex99 bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
100 {
101 TRACE_SERIALIZE (this);
102 unsigned int size = src.get_size ();
103 CFFIndex *dest = c->allocate_size<CFFIndex> (size);
104 if (unlikely (dest == nullptr)) return_trace (false);
105 memcpy (dest, &src, size);
106 return_trace (true);
107 }
108
serializeCFF::CFFIndex109 bool serialize (hb_serialize_context_t *c,
110 unsigned int offSize_,
111 const byte_str_array_t &byteArray)
112 {
113 TRACE_SERIALIZE (this);
114 if (byteArray.length == 0)
115 {
116 COUNT *dest = c->allocate_min<COUNT> ();
117 if (unlikely (dest == nullptr)) return_trace (false);
118 *dest = 0;
119 }
120 else
121 {
122 /* serialize CFFIndex header */
123 if (unlikely (!c->extend_min (*this))) return_trace (false);
124 this->count = byteArray.length;
125 this->offSize = offSize_;
126 if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
127 return_trace (false);
128
129 /* serialize indices */
130 unsigned int offset = 1;
131 unsigned int i = 0;
132 for (; i < byteArray.length; i++)
133 {
134 set_offset_at (i, offset);
135 offset += byteArray[i].get_size ();
136 }
137 set_offset_at (i, offset);
138
139 /* serialize data */
140 for (unsigned int i = 0; i < byteArray.length; i++)
141 {
142 const byte_str_t &bs = byteArray[i];
143 unsigned char *dest = c->allocate_size<unsigned char> (bs.length);
144 if (unlikely (dest == nullptr))
145 return_trace (false);
146 memcpy (dest, &bs[0], bs.length);
147 }
148 }
149 return_trace (true);
150 }
151
serializeCFF::CFFIndex152 bool serialize (hb_serialize_context_t *c,
153 unsigned int offSize_,
154 const str_buff_vec_t &buffArray)
155 {
156 byte_str_array_t byteArray;
157 byteArray.init ();
158 byteArray.resize (buffArray.length);
159 for (unsigned int i = 0; i < byteArray.length; i++)
160 byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length);
161 bool result = this->serialize (c, offSize_, byteArray);
162 byteArray.fini ();
163 return result;
164 }
165
set_offset_atCFF::CFFIndex166 void set_offset_at (unsigned int index, unsigned int offset)
167 {
168 HBUINT8 *p = offsets + offSize * index + offSize;
169 unsigned int size = offSize;
170 for (; size; size--)
171 {
172 --p;
173 *p = offset & 0xFF;
174 offset >>= 8;
175 }
176 }
177
offset_atCFF::CFFIndex178 unsigned int offset_at (unsigned int index) const
179 {
180 assert (index <= count);
181 const HBUINT8 *p = offsets + offSize * index;
182 unsigned int size = offSize;
183 unsigned int offset = 0;
184 for (; size; size--)
185 offset = (offset << 8) + *p++;
186 return offset;
187 }
188
length_atCFF::CFFIndex189 unsigned int length_at (unsigned int index) const
190 {
191 if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
192 (offset_at (index + 1) > offset_at (count))))
193 return 0;
194 return offset_at (index + 1) - offset_at (index);
195 }
196
data_baseCFF::CFFIndex197 const unsigned char *data_base () const
198 { return (const unsigned char *) this + min_size + offset_array_size (); }
199
data_sizeCFF::CFFIndex200 unsigned int data_size () const { return HBINT8::static_size; }
201
operator []CFF::CFFIndex202 byte_str_t operator [] (unsigned int index) const
203 {
204 if (unlikely (index >= count)) return Null (byte_str_t);
205 return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
206 }
207
get_sizeCFF::CFFIndex208 unsigned int get_size () const
209 {
210 if (this == &Null (CFFIndex)) return 0;
211 if (count > 0)
212 return min_size + offset_array_size () + (offset_at (count) - 1);
213 return count.static_size; /* empty CFFIndex contains count only */
214 }
215
sanitizeCFF::CFFIndex216 bool sanitize (hb_sanitize_context_t *c) const
217 {
218 TRACE_SANITIZE (this);
219 return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */
220 (c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
221 c->check_array (offsets, offSize, count + 1) &&
222 c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1))));
223 }
224
225 protected:
max_offsetCFF::CFFIndex226 unsigned int max_offset () const
227 {
228 unsigned int max = 0;
229 for (unsigned int i = 0; i < count + 1u; i++)
230 {
231 unsigned int off = offset_at (i);
232 if (off > max) max = off;
233 }
234 return max;
235 }
236
237 public:
238 COUNT count; /* Number of object data. Note there are (count+1) offsets */
239 HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
240 HBUINT8 offsets[HB_VAR_ARRAY]; /* The array of (count + 1) offsets into objects array (1-base). */
241 /* HBUINT8 data[HB_VAR_ARRAY]; Object data */
242 public:
243 DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
244 };
245
246 template <typename COUNT, typename TYPE>
247 struct CFFIndexOf : CFFIndex<COUNT>
248 {
operator []CFF::CFFIndexOf249 const byte_str_t operator [] (unsigned int index) const
250 {
251 if (likely (index < CFFIndex<COUNT>::count))
252 return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
253 return Null(byte_str_t);
254 }
255
256 template <typename DATA, typename PARAM1, typename PARAM2>
serializeCFF::CFFIndexOf257 bool serialize (hb_serialize_context_t *c,
258 unsigned int offSize_,
259 const DATA *dataArray,
260 unsigned int dataArrayLen,
261 const hb_vector_t<unsigned int> &dataSizeArray,
262 const PARAM1 ¶m1,
263 const PARAM2 ¶m2)
264 {
265 TRACE_SERIALIZE (this);
266 /* serialize CFFIndex header */
267 if (unlikely (!c->extend_min (*this))) return_trace (false);
268 this->count = dataArrayLen;
269 this->offSize = offSize_;
270 if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
271 return_trace (false);
272
273 /* serialize indices */
274 unsigned int offset = 1;
275 unsigned int i = 0;
276 for (; i < dataArrayLen; i++)
277 {
278 CFFIndex<COUNT>::set_offset_at (i, offset);
279 offset += dataSizeArray[i];
280 }
281 CFFIndex<COUNT>::set_offset_at (i, offset);
282
283 /* serialize data */
284 for (unsigned int i = 0; i < dataArrayLen; i++)
285 {
286 TYPE *dest = c->start_embed<TYPE> ();
287 if (unlikely (dest == nullptr ||
288 !dest->serialize (c, dataArray[i], param1, param2)))
289 return_trace (false);
290 }
291 return_trace (true);
292 }
293
294 /* in parallel to above */
295 template <typename DATA, typename PARAM>
calculate_serialized_sizeCFF::CFFIndexOf296 static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
297 const DATA *dataArray,
298 unsigned int dataArrayLen,
299 hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
300 const PARAM ¶m)
301 {
302 /* determine offset size */
303 unsigned int totalDataSize = 0;
304 for (unsigned int i = 0; i < dataArrayLen; i++)
305 {
306 unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
307 dataSizeArray[i] = dataSize;
308 totalDataSize += dataSize;
309 }
310 offSize_ = calcOffSize (totalDataSize);
311
312 return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize);
313 }
314 };
315
316 /* Top Dict, Font Dict, Private Dict */
317 struct Dict : UnsizedByteStr
318 {
319 template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
serializeCFF::Dict320 bool serialize (hb_serialize_context_t *c,
321 const DICTVAL &dictval,
322 OP_SERIALIZER& opszr,
323 PARAM& param)
324 {
325 TRACE_SERIALIZE (this);
326 for (unsigned int i = 0; i < dictval.get_count (); i++)
327 if (unlikely (!opszr.serialize (c, dictval[i], param)))
328 return_trace (false);
329
330 return_trace (true);
331 }
332
333 /* in parallel to above */
334 template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
calculate_serialized_sizeCFF::Dict335 static unsigned int calculate_serialized_size (const DICTVAL &dictval,
336 OP_SERIALIZER& opszr,
337 PARAM& param)
338 {
339 unsigned int size = 0;
340 for (unsigned int i = 0; i < dictval.get_count (); i++)
341 size += opszr.calculate_serialized_size (dictval[i], param);
342 return size;
343 }
344
345 template <typename DICTVAL, typename OP_SERIALIZER>
calculate_serialized_sizeCFF::Dict346 static unsigned int calculate_serialized_size (const DICTVAL &dictval,
347 OP_SERIALIZER& opszr)
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]);
352 return size;
353 }
354
355 template <typename INTTYPE, int minVal, int maxVal>
serialize_int_opCFF::Dict356 static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp)
357 {
358 // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
359 if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
360 return false;
361
362 TRACE_SERIALIZE (this);
363 /* serialize the opcode */
364 HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
365 if (unlikely (p == nullptr)) return_trace (false);
366 if (Is_OpCode_ESC (op))
367 {
368 *p = OpCode_escape;
369 op = Unmake_OpCode_ESC (op);
370 p++;
371 }
372 *p = op;
373 return_trace (true);
374 }
375
serialize_uint4_opCFF::Dict376 static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value)
377 { return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
378
serialize_uint2_opCFF::Dict379 static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value)
380 { return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
381
serialize_offset4_opCFF::Dict382 static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
383 { return serialize_uint4_op (c, op, value); }
384
serialize_offset2_opCFF::Dict385 static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
386 { return serialize_uint2_op (c, op, value); }
387 };
388
389 struct TopDict : Dict {};
390 struct FontDict : Dict {};
391 struct PrivateDict : Dict {};
392
393 struct table_info_t
394 {
initCFF::table_info_t395 void init () { offSize = offset = size = 0; }
396
397 unsigned int offset;
398 unsigned int size;
399 unsigned int offSize;
400 };
401
402 template <typename COUNT>
403 struct FDArray : CFFIndexOf<COUNT, FontDict>
404 {
405 /* used by CFF1 */
406 template <typename DICTVAL, typename OP_SERIALIZER>
serializeCFF::FDArray407 bool serialize (hb_serialize_context_t *c,
408 unsigned int offSize_,
409 const hb_vector_t<DICTVAL> &fontDicts,
410 OP_SERIALIZER& opszr)
411 {
412 TRACE_SERIALIZE (this);
413 if (unlikely (!c->extend_min (*this))) return_trace (false);
414 this->count = fontDicts.length;
415 this->offSize = offSize_;
416 if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
417 return_trace (false);
418
419 /* serialize font dict offsets */
420 unsigned int offset = 1;
421 unsigned int fid = 0;
422 for (; fid < fontDicts.length; fid++)
423 {
424 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
425 offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
426 }
427 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
428
429 /* serialize font dicts */
430 for (unsigned int i = 0; i < fontDicts.length; i++)
431 {
432 FontDict *dict = c->start_embed<FontDict> ();
433 if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
434 return_trace (false);
435 }
436 return_trace (true);
437 }
438
439 /* used by CFF2 */
440 template <typename DICTVAL, typename OP_SERIALIZER>
serializeCFF::FDArray441 bool serialize (hb_serialize_context_t *c,
442 unsigned int offSize_,
443 const hb_vector_t<DICTVAL> &fontDicts,
444 unsigned int fdCount,
445 const hb_inc_bimap_t &fdmap,
446 OP_SERIALIZER& opszr,
447 const hb_vector_t<table_info_t> &privateInfos)
448 {
449 TRACE_SERIALIZE (this);
450 if (unlikely (!c->extend_min (*this))) return_trace (false);
451 this->count = fdCount;
452 this->offSize = offSize_;
453 if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
454 return_trace (false);
455
456 /* serialize font dict offsets */
457 unsigned int offset = 1;
458 unsigned int fid = 0;
459 for (unsigned i = 0; i < fontDicts.length; i++)
460 if (fdmap.has (i))
461 {
462 if (unlikely (fid >= fdCount)) return_trace (false);
463 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
464 offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
465 }
466 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
467
468 /* serialize font dicts */
469 for (unsigned int i = 0; i < fontDicts.length; i++)
470 if (fdmap.has (i))
471 {
472 FontDict *dict = c->start_embed<FontDict> ();
473 if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
474 return_trace (false);
475 }
476 return_trace (true);
477 }
478
479 /* in parallel to above */
480 template <typename OP_SERIALIZER, typename DICTVAL>
calculate_serialized_sizeCFF::FDArray481 static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
482 const hb_vector_t<DICTVAL> &fontDicts,
483 unsigned int fdCount,
484 const hb_inc_bimap_t &fdmap,
485 OP_SERIALIZER& opszr)
486 {
487 unsigned int dictsSize = 0;
488 for (unsigned int i = 0; i < fontDicts.len; i++)
489 if (fdmap.has (i))
490 dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
491
492 offSize_ = calcOffSize (dictsSize);
493 return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
494 }
495 };
496
497 /* FDSelect */
498 struct FDSelect0 {
sanitizeCFF::FDSelect0499 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
500 {
501 TRACE_SANITIZE (this);
502 if (unlikely (!(c->check_struct (this))))
503 return_trace (false);
504 for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
505 if (unlikely (!fds[i].sanitize (c)))
506 return_trace (false);
507
508 return_trace (true);
509 }
510
get_fdCFF::FDSelect0511 hb_codepoint_t get_fd (hb_codepoint_t glyph) const
512 { return (hb_codepoint_t) fds[glyph]; }
513
get_sizeCFF::FDSelect0514 unsigned int get_size (unsigned int num_glyphs) const
515 { return HBUINT8::static_size * num_glyphs; }
516
517 HBUINT8 fds[HB_VAR_ARRAY];
518
519 DEFINE_SIZE_MIN (0);
520 };
521
522 template <typename GID_TYPE, typename FD_TYPE>
523 struct FDSelect3_4_Range
524 {
sanitizeCFF::FDSelect3_4_Range525 bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
526 {
527 TRACE_SANITIZE (this);
528 return_trace (first < c->get_num_glyphs () && (fd < fdcount));
529 }
530
531 GID_TYPE first;
532 FD_TYPE fd;
533 public:
534 DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
535 };
536
537 template <typename GID_TYPE, typename FD_TYPE>
538 struct FDSelect3_4
539 {
get_sizeCFF::FDSelect3_4540 unsigned int get_size () const
541 { return GID_TYPE::static_size * 2 + ranges.get_size (); }
542
sanitizeCFF::FDSelect3_4543 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
544 {
545 TRACE_SANITIZE (this);
546 if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) ||
547 (nRanges () == 0) || ranges[0].first != 0))
548 return_trace (false);
549
550 for (unsigned int i = 1; i < nRanges (); i++)
551 if (unlikely (ranges[i - 1].first >= ranges[i].first))
552 return_trace (false);
553
554 if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
555 return_trace (false);
556
557 return_trace (true);
558 }
559
get_fdCFF::FDSelect3_4560 hb_codepoint_t get_fd (hb_codepoint_t glyph) const
561 {
562 unsigned int i;
563 for (i = 1; i < nRanges (); i++)
564 if (glyph < ranges[i].first)
565 break;
566
567 return (hb_codepoint_t) ranges[i - 1].fd;
568 }
569
nRangesCFF::FDSelect3_4570 GID_TYPE &nRanges () { return ranges.len; }
nRangesCFF::FDSelect3_4571 GID_TYPE nRanges () const { return ranges.len; }
sentinelCFF::FDSelect3_4572 GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
sentinelCFF::FDSelect3_4573 const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
574
575 ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges;
576 /* GID_TYPE sentinel */
577
578 DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges);
579 };
580
581 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
582 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
583
584 struct FDSelect
585 {
serializeCFF::FDSelect586 bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
587 {
588 TRACE_SERIALIZE (this);
589 unsigned int size = src.get_size (num_glyphs);
590 FDSelect *dest = c->allocate_size<FDSelect> (size);
591 if (unlikely (dest == nullptr)) return_trace (false);
592 memcpy (dest, &src, size);
593 return_trace (true);
594 }
595
calculate_serialized_sizeCFF::FDSelect596 unsigned int calculate_serialized_size (unsigned int num_glyphs) const
597 { return get_size (num_glyphs); }
598
get_sizeCFF::FDSelect599 unsigned int get_size (unsigned int num_glyphs) const
600 {
601 switch (format)
602 {
603 case 0: return format.static_size + u.format0.get_size (num_glyphs);
604 case 3: return format.static_size + u.format3.get_size ();
605 default:return 0;
606 }
607 }
608
get_fdCFF::FDSelect609 hb_codepoint_t get_fd (hb_codepoint_t glyph) const
610 {
611 if (this == &Null (FDSelect)) return 0;
612
613 switch (format)
614 {
615 case 0: return u.format0.get_fd (glyph);
616 case 3: return u.format3.get_fd (glyph);
617 default:return 0;
618 }
619 }
620
sanitizeCFF::FDSelect621 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
622 {
623 TRACE_SANITIZE (this);
624 if (unlikely (!c->check_struct (this)))
625 return_trace (false);
626
627 switch (format)
628 {
629 case 0: return_trace (u.format0.sanitize (c, fdcount));
630 case 3: return_trace (u.format3.sanitize (c, fdcount));
631 default:return_trace (false);
632 }
633 }
634
635 HBUINT8 format;
636 union {
637 FDSelect0 format0;
638 FDSelect3 format3;
639 } u;
640 public:
641 DEFINE_SIZE_MIN (1);
642 };
643
644 template <typename COUNT>
645 struct Subrs : CFFIndex<COUNT>
646 {
647 typedef COUNT count_type;
648 typedef CFFIndex<COUNT> SUPER;
649 };
650
651 } /* namespace CFF */
652
653 #endif /* HB_OT_CFF_COMMON_HH */
654