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> |
43 | static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) |
44 | { return offset ? StructAtOffset<Type> (P, offset) : Null (Type); } |
45 | |
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 | { |
68 | void fini () { SUPER::fini_deep (); } |
69 | |
70 | 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 | { |
86 | static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) |
87 | { return offSize * (count + 1); } |
88 | |
89 | unsigned int offset_array_size () const |
90 | { return calculate_offset_array_size (offSize, count); } |
91 | |
92 | 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 | |
99 | 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 | |
109 | 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 | |
152 | 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 | |
166 | 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 | |
178 | 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 | |
189 | 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 | |
197 | const unsigned char *data_base () const |
198 | { return (const unsigned char *) this + min_size + offset_array_size (); } |
199 | |
200 | unsigned int data_size () const { return HBINT8::static_size; } |
201 | |
202 | 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 | |
208 | 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 | |
216 | 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: |
226 | 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 | { |
249 | 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> |
257 | 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> |
296 | 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> |
320 | 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> |
335 | 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> |
346 | 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> |
356 | 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 | |
376 | 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 | |
379 | 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 | |
382 | 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 | |
385 | 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 | { |
395 | 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> |
407 | 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> |
441 | 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> |
481 | 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 { |
499 | 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 | |
511 | hb_codepoint_t get_fd (hb_codepoint_t glyph) const |
512 | { return (hb_codepoint_t) fds[glyph]; } |
513 | |
514 | 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 | { |
525 | 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 | { |
540 | unsigned int get_size () const |
541 | { return GID_TYPE::static_size * 2 + ranges.get_size (); } |
542 | |
543 | 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 | |
560 | 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 | |
570 | GID_TYPE &nRanges () { return ranges.len; } |
571 | GID_TYPE nRanges () const { return ranges.len; } |
572 | GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); } |
573 | 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 | { |
586 | 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 | |
596 | unsigned int calculate_serialized_size (unsigned int num_glyphs) const |
597 | { return get_size (num_glyphs); } |
598 | |
599 | 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 | |
609 | 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 | |
621 | 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 | |