|
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 ¶m1, |
|
273 const PARAM2 ¶m2) |
|
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 ¶m) |
|
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 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset); |
|
529 offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); |
|
530 } |
|
531 CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset); |
|
532 |
|
533 /* serialize font dicts */ |
|
534 for (unsigned int i = 0; i < fontDicts.length; i++) |
|
535 if (fdmap.includes (i)) |
|
536 { |
|
537 FontDict *dict = c->start_embed<FontDict> (); |
|
538 if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) |
|
539 return_trace (false); |
|
540 } |
|
541 return_trace (true); |
|
542 } |
|
543 |
|
544 /* in parallel to above */ |
|
545 template <typename OP_SERIALIZER, typename DICTVAL> |
|
546 static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, |
|
547 const hb_vector_t<DICTVAL> &fontDicts, |
|
548 unsigned int fdCount, |
|
549 const remap_t &fdmap, |
|
550 OP_SERIALIZER& opszr) |
|
551 { |
|
552 unsigned int dictsSize = 0; |
|
553 for (unsigned int i = 0; i < fontDicts.len; i++) |
|
554 if (fdmap.includes (i)) |
|
555 dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); |
|
556 |
|
557 offSize_ = calcOffSize (dictsSize); |
|
558 return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize); |
|
559 } |
|
560 }; |
|
561 |
|
562 /* FDSelect */ |
|
563 struct FDSelect0 { |
|
564 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const |
|
565 { |
|
566 TRACE_SANITIZE (this); |
|
567 if (unlikely (!(c->check_struct (this)))) |
|
568 return_trace (false); |
|
569 for (unsigned int i = 0; i < c->get_num_glyphs (); i++) |
|
570 if (unlikely (!fds[i].sanitize (c))) |
|
571 return_trace (false); |
|
572 |
|
573 return_trace (true); |
|
574 } |
|
575 |
|
576 hb_codepoint_t get_fd (hb_codepoint_t glyph) const |
|
577 { |
|
578 return (hb_codepoint_t)fds[glyph]; |
|
579 } |
|
580 |
|
581 unsigned int get_size (unsigned int num_glyphs) const |
|
582 { return HBUINT8::static_size * num_glyphs; } |
|
583 |
|
584 HBUINT8 fds[VAR]; |
|
585 |
|
586 DEFINE_SIZE_MIN (1); |
|
587 }; |
|
588 |
|
589 template <typename GID_TYPE, typename FD_TYPE> |
|
590 struct FDSelect3_4_Range { |
|
591 bool sanitize (hb_sanitize_context_t *c, const void */*nullptr*/, unsigned int fdcount) const |
|
592 { |
|
593 TRACE_SANITIZE (this); |
|
594 return_trace (first < c->get_num_glyphs () && (fd < fdcount)); |
|
595 } |
|
596 |
|
597 GID_TYPE first; |
|
598 FD_TYPE fd; |
|
599 |
|
600 DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size); |
|
601 }; |
|
602 |
|
603 template <typename GID_TYPE, typename FD_TYPE> |
|
604 struct FDSelect3_4 { |
|
605 unsigned int get_size () const |
|
606 { return GID_TYPE::static_size * 2 + ranges.get_size (); } |
|
607 |
|
608 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const |
|
609 { |
|
610 TRACE_SANITIZE (this); |
|
611 if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) || |
|
612 (nRanges () == 0) || ranges[0].first != 0)) |
|
613 return_trace (false); |
|
614 |
|
615 for (unsigned int i = 1; i < nRanges (); i++) |
|
616 { |
|
617 if (unlikely (ranges[i - 1].first >= ranges[i].first)) |
|
618 return_trace (false); |
|
619 } |
|
620 |
|
621 if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) |
|
622 return_trace (false); |
|
623 |
|
624 return_trace (true); |
|
625 } |
|
626 |
|
627 hb_codepoint_t get_fd (hb_codepoint_t glyph) const |
|
628 { |
|
629 unsigned int i; |
|
630 for (i = 1; i < nRanges (); i++) |
|
631 if (glyph < ranges[i].first) |
|
632 break; |
|
633 |
|
634 return (hb_codepoint_t)ranges[i - 1].fd; |
|
635 } |
|
636 |
|
637 GID_TYPE &nRanges () { return ranges.len; } |
|
638 GID_TYPE nRanges () const { return ranges.len; } |
|
639 GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); } |
|
640 const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); } |
|
641 |
|
642 ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges; |
|
643 /* GID_TYPE sentinel */ |
|
644 |
|
645 DEFINE_SIZE_ARRAY (GID_TYPE::static_size, ranges); |
|
646 }; |
|
647 |
|
648 typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3; |
|
649 typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range; |
|
650 |
|
651 struct FDSelect { |
|
652 bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const |
|
653 { |
|
654 TRACE_SANITIZE (this); |
|
655 |
|
656 return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) && |
|
657 (format == 0)? |
|
658 u.format0.sanitize (c, fdcount): |
|
659 u.format3.sanitize (c, fdcount))); |
|
660 } |
|
661 |
|
662 bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs) |
|
663 { |
|
664 TRACE_SERIALIZE (this); |
|
665 unsigned int size = src.get_size (num_glyphs); |
|
666 FDSelect *dest = c->allocate_size<FDSelect> (size); |
|
667 if (unlikely (dest == nullptr)) return_trace (false); |
|
668 memcpy (dest, &src, size); |
|
669 return_trace (true); |
|
670 } |
|
671 |
|
672 unsigned int calculate_serialized_size (unsigned int num_glyphs) const |
|
673 { return get_size (num_glyphs); } |
|
674 |
|
675 unsigned int get_size (unsigned int num_glyphs) const |
|
676 { |
|
677 unsigned int size = format.static_size; |
|
678 if (format == 0) |
|
679 size += u.format0.get_size (num_glyphs); |
|
680 else |
|
681 size += u.format3.get_size (); |
|
682 return size; |
|
683 } |
|
684 |
|
685 hb_codepoint_t get_fd (hb_codepoint_t glyph) const |
|
686 { |
|
687 if (this == &Null(FDSelect)) |
|
688 return 0; |
|
689 if (format == 0) |
|
690 return u.format0.get_fd (glyph); |
|
691 else |
|
692 return u.format3.get_fd (glyph); |
|
693 } |
|
694 |
|
695 HBUINT8 format; |
|
696 union { |
|
697 FDSelect0 format0; |
|
698 FDSelect3 format3; |
|
699 } u; |
|
700 |
|
701 DEFINE_SIZE_MIN (1); |
|
702 }; |
|
703 |
|
704 template <typename COUNT> |
|
705 struct Subrs : CFFIndex<COUNT> |
|
706 { |
|
707 typedef COUNT count_type; |
|
708 typedef CFFIndex<COUNT> SUPER; |
|
709 }; |
|
710 |
|
711 } /* namespace CFF */ |
|
712 |
|
713 #endif /* HB_OT_CFF_COMMON_HH */ |