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 ¶m1,
272 const PARAM2 ¶m2)
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 ¶m)
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