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 | |
27 | #ifndef HB_OT_CFF1_TABLE_HH |
28 | #define HB_OT_CFF1_TABLE_HH |
29 | |
30 | #include "hb-ot-head-table.hh" |
31 | #include "hb-ot-cff-common.hh" |
32 | #include "hb-subset-cff1.hh" |
33 | |
34 | namespace CFF { |
35 | |
36 | /* |
37 | * CFF -- Compact Font Format (CFF) |
38 | * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf |
39 | */ |
40 | #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') |
41 | |
42 | #define CFF_UNDEF_SID CFF_UNDEF_CODE |
43 | |
44 | enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; |
45 | enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; |
46 | |
47 | typedef CFFIndex<HBUINT16> CFF1Index; |
48 | template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {}; |
49 | |
50 | typedef CFFIndex<HBUINT16> CFF1Index; |
51 | typedef CFF1Index CFF1CharStrings; |
52 | typedef FDArray<HBUINT16> CFF1FDArray; |
53 | typedef Subrs<HBUINT16> CFF1Subrs; |
54 | |
55 | struct CFF1FDSelect : FDSelect {}; |
56 | |
57 | /* Encoding */ |
58 | struct Encoding0 { |
59 | bool sanitize (hb_sanitize_context_t *c) const |
60 | { |
61 | TRACE_SANITIZE (this); |
62 | return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c)); |
63 | } |
64 | |
65 | hb_codepoint_t get_code (hb_codepoint_t glyph) const |
66 | { |
67 | assert (glyph > 0); |
68 | glyph--; |
69 | if (glyph < nCodes) |
70 | { |
71 | return (hb_codepoint_t)codes[glyph]; |
72 | } |
73 | else |
74 | return CFF_UNDEF_CODE; |
75 | } |
76 | |
77 | unsigned int get_size () const |
78 | { return HBUINT8::static_size * (nCodes + 1); } |
79 | |
80 | HBUINT8 nCodes; |
81 | HBUINT8 codes[VAR]; |
82 | |
83 | DEFINE_SIZE_ARRAY(1, codes); |
84 | }; |
85 | |
86 | struct Encoding1_Range { |
87 | bool sanitize (hb_sanitize_context_t *c) const |
88 | { |
89 | TRACE_SANITIZE (this); |
90 | return_trace (c->check_struct (this)); |
91 | } |
92 | |
93 | HBUINT8 first; |
94 | HBUINT8 nLeft; |
95 | |
96 | DEFINE_SIZE_STATIC (2); |
97 | }; |
98 | |
99 | struct Encoding1 { |
100 | unsigned int get_size () const |
101 | { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; } |
102 | |
103 | bool sanitize (hb_sanitize_context_t *c) const |
104 | { |
105 | TRACE_SANITIZE (this); |
106 | return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c))); |
107 | } |
108 | |
109 | hb_codepoint_t get_code (hb_codepoint_t glyph) const |
110 | { |
111 | assert (glyph > 0); |
112 | glyph--; |
113 | for (unsigned int i = 0; i < nRanges; i++) |
114 | { |
115 | if (glyph <= ranges[i].nLeft) |
116 | { |
117 | return (hb_codepoint_t)ranges[i].first + glyph; |
118 | } |
119 | glyph -= (ranges[i].nLeft + 1); |
120 | } |
121 | return CFF_UNDEF_CODE; |
122 | } |
123 | |
124 | HBUINT8 nRanges; |
125 | Encoding1_Range ranges[VAR]; |
126 | |
127 | DEFINE_SIZE_ARRAY (1, ranges); |
128 | }; |
129 | |
130 | struct SuppEncoding { |
131 | bool sanitize (hb_sanitize_context_t *c) const |
132 | { |
133 | TRACE_SANITIZE (this); |
134 | return_trace (c->check_struct (this)); |
135 | } |
136 | |
137 | HBUINT8 code; |
138 | HBUINT16 glyph; |
139 | |
140 | DEFINE_SIZE_STATIC (3); |
141 | }; |
142 | |
143 | struct CFF1SuppEncData { |
144 | bool sanitize (hb_sanitize_context_t *c) const |
145 | { |
146 | TRACE_SANITIZE (this); |
147 | return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c))); |
148 | } |
149 | |
150 | void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const |
151 | { |
152 | for (unsigned int i = 0; i < nSups; i++) |
153 | if (sid == supps[i].glyph) |
154 | codes.push (supps[i].code); |
155 | } |
156 | |
157 | unsigned int get_size () const |
158 | { return HBUINT8::static_size + SuppEncoding::static_size * nSups; } |
159 | |
160 | HBUINT8 nSups; |
161 | SuppEncoding supps[VAR]; |
162 | |
163 | DEFINE_SIZE_ARRAY (1, supps); |
164 | }; |
165 | |
166 | struct Encoding { |
167 | bool sanitize (hb_sanitize_context_t *c) const |
168 | { |
169 | TRACE_SANITIZE (this); |
170 | |
171 | if (unlikely (!c->check_struct (this))) |
172 | return_trace (false); |
173 | unsigned int fmt = format & 0x7F; |
174 | if (unlikely (fmt > 1)) |
175 | return_trace (false); |
176 | if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c)))) |
177 | return_trace (false); |
178 | return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c)); |
179 | } |
180 | |
181 | /* serialize a fullset Encoding */ |
182 | bool serialize (hb_serialize_context_t *c, const Encoding &src) |
183 | { |
184 | TRACE_SERIALIZE (this); |
185 | unsigned int size = src.get_size (); |
186 | Encoding *dest = c->allocate_size<Encoding> (size); |
187 | if (unlikely (dest == nullptr)) return_trace (false); |
188 | memcpy (dest, &src, size); |
189 | return_trace (true); |
190 | } |
191 | |
192 | /* serialize a subset Encoding */ |
193 | bool serialize (hb_serialize_context_t *c, |
194 | uint8_t format, |
195 | unsigned int enc_count, |
196 | const hb_vector_t<code_pair_t>& code_ranges, |
197 | const hb_vector_t<code_pair_t>& supp_codes) |
198 | { |
199 | TRACE_SERIALIZE (this); |
200 | Encoding *dest = c->extend_min (*this); |
201 | if (unlikely (dest == nullptr)) return_trace (false); |
202 | dest->format.set (format | ((supp_codes.length > 0)? 0x80: 0)); |
203 | if (format == 0) |
204 | { |
205 | Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count); |
206 | if (unlikely (fmt0 == nullptr)) return_trace (false); |
207 | fmt0->nCodes.set (enc_count); |
208 | unsigned int glyph = 0; |
209 | for (unsigned int i = 0; i < code_ranges.length; i++) |
210 | { |
211 | hb_codepoint_t code = code_ranges[i].code; |
212 | for (int left = (int)code_ranges[i].glyph; left >= 0; left--) |
213 | fmt0->codes[glyph++].set (code++); |
214 | if (unlikely (!((glyph <= 0x100) && (code <= 0x100)))) |
215 | return_trace (false); |
216 | } |
217 | } |
218 | else |
219 | { |
220 | Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length); |
221 | if (unlikely (fmt1 == nullptr)) return_trace (false); |
222 | fmt1->nRanges.set (code_ranges.length); |
223 | for (unsigned int i = 0; i < code_ranges.length; i++) |
224 | { |
225 | if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF)))) |
226 | return_trace (false); |
227 | fmt1->ranges[i].first.set (code_ranges[i].code); |
228 | fmt1->ranges[i].nLeft.set (code_ranges[i].glyph); |
229 | } |
230 | } |
231 | if (supp_codes.length > 0) |
232 | { |
233 | CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length); |
234 | if (unlikely (suppData == nullptr)) return_trace (false); |
235 | suppData->nSups.set (supp_codes.length); |
236 | for (unsigned int i = 0; i < supp_codes.length; i++) |
237 | { |
238 | suppData->supps[i].code.set (supp_codes[i].code); |
239 | suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */ |
240 | } |
241 | } |
242 | return_trace (true); |
243 | } |
244 | |
245 | /* parallel to above: calculate the size of a subset Encoding */ |
246 | static unsigned int calculate_serialized_size (uint8_t format, |
247 | unsigned int enc_count, |
248 | unsigned int supp_count) |
249 | { |
250 | unsigned int size = min_size; |
251 | if (format == 0) |
252 | size += Encoding0::min_size + HBUINT8::static_size * enc_count; |
253 | else |
254 | size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; |
255 | if (supp_count > 0) |
256 | size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; |
257 | return size; |
258 | } |
259 | |
260 | unsigned int get_size () const |
261 | { |
262 | unsigned int size = min_size; |
263 | if (table_format () == 0) |
264 | size += u.format0.get_size (); |
265 | else |
266 | size += u.format1.get_size (); |
267 | if (has_supplement ()) |
268 | size += suppEncData ().get_size (); |
269 | return size; |
270 | } |
271 | |
272 | hb_codepoint_t get_code (hb_codepoint_t glyph) const |
273 | { |
274 | if (table_format () == 0) |
275 | return u.format0.get_code (glyph); |
276 | else |
277 | return u.format1.get_code (glyph); |
278 | } |
279 | |
280 | uint8_t table_format () const { return (format & 0x7F); } |
281 | bool has_supplement () const { return (format & 0x80) != 0; } |
282 | |
283 | void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const |
284 | { |
285 | codes.resize (0); |
286 | if (has_supplement ()) |
287 | suppEncData().get_codes (sid, codes); |
288 | } |
289 | |
290 | protected: |
291 | const CFF1SuppEncData &suppEncData () const |
292 | { |
293 | if ((format & 0x7F) == 0) |
294 | return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]); |
295 | else |
296 | return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]); |
297 | } |
298 | |
299 | public: |
300 | HBUINT8 format; |
301 | |
302 | union { |
303 | Encoding0 format0; |
304 | Encoding1 format1; |
305 | } u; |
306 | /* CFF1SuppEncData suppEncData; */ |
307 | |
308 | DEFINE_SIZE_MIN (1); |
309 | }; |
310 | |
311 | /* Charset */ |
312 | struct Charset0 { |
313 | bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const |
314 | { |
315 | TRACE_SANITIZE (this); |
316 | return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); |
317 | } |
318 | |
319 | hb_codepoint_t get_sid (hb_codepoint_t glyph) const |
320 | { |
321 | if (glyph == 0) |
322 | return 0; |
323 | else |
324 | return sids[glyph - 1]; |
325 | } |
326 | |
327 | hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const |
328 | { |
329 | if (sid == 0) |
330 | return 0; |
331 | |
332 | for (unsigned int glyph = 1; glyph < num_glyphs; glyph++) |
333 | { |
334 | if (sids[glyph-1] == sid) |
335 | return glyph; |
336 | } |
337 | return 0; |
338 | } |
339 | |
340 | unsigned int get_size (unsigned int num_glyphs) const |
341 | { |
342 | assert (num_glyphs > 0); |
343 | return HBUINT16::static_size * (num_glyphs - 1); |
344 | } |
345 | |
346 | HBUINT16 sids[VAR]; |
347 | |
348 | DEFINE_SIZE_ARRAY(0, sids); |
349 | }; |
350 | |
351 | template <typename TYPE> |
352 | struct Charset_Range { |
353 | bool sanitize (hb_sanitize_context_t *c) const |
354 | { |
355 | TRACE_SANITIZE (this); |
356 | return_trace (c->check_struct (this)); |
357 | } |
358 | |
359 | HBUINT16 first; |
360 | TYPE nLeft; |
361 | |
362 | DEFINE_SIZE_STATIC (HBUINT16::static_size + TYPE::static_size); |
363 | }; |
364 | |
365 | template <typename TYPE> |
366 | struct Charset1_2 { |
367 | bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const |
368 | { |
369 | TRACE_SANITIZE (this); |
370 | if (unlikely (!c->check_struct (this))) |
371 | return_trace (false); |
372 | num_glyphs--; |
373 | for (unsigned int i = 0; num_glyphs > 0; i++) |
374 | { |
375 | if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) |
376 | return_trace (false); |
377 | num_glyphs -= (ranges[i].nLeft + 1); |
378 | } |
379 | return_trace (true); |
380 | } |
381 | |
382 | hb_codepoint_t get_sid (hb_codepoint_t glyph) const |
383 | { |
384 | if (glyph == 0) return 0; |
385 | glyph--; |
386 | for (unsigned int i = 0;; i++) |
387 | { |
388 | if (glyph <= ranges[i].nLeft) |
389 | return (hb_codepoint_t)ranges[i].first + glyph; |
390 | glyph -= (ranges[i].nLeft + 1); |
391 | } |
392 | |
393 | return 0; |
394 | } |
395 | |
396 | hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const |
397 | { |
398 | if (sid == 0) return 0; |
399 | hb_codepoint_t glyph = 1; |
400 | for (unsigned int i = 0;; i++) |
401 | { |
402 | if (glyph >= num_glyphs) |
403 | return 0; |
404 | if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft)) |
405 | return glyph + (sid - ranges[i].first); |
406 | glyph += (ranges[i].nLeft + 1); |
407 | } |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | unsigned int get_size (unsigned int num_glyphs) const |
413 | { |
414 | unsigned int size = HBUINT8::static_size; |
415 | int glyph = (int)num_glyphs; |
416 | |
417 | assert (glyph > 0); |
418 | glyph--; |
419 | for (unsigned int i = 0; glyph > 0; i++) |
420 | { |
421 | glyph -= (ranges[i].nLeft + 1); |
422 | size += Charset_Range<TYPE>::static_size; |
423 | } |
424 | |
425 | return size; |
426 | } |
427 | |
428 | Charset_Range<TYPE> ranges[VAR]; |
429 | |
430 | DEFINE_SIZE_ARRAY (0, ranges); |
431 | }; |
432 | |
433 | typedef Charset1_2<HBUINT8> Charset1; |
434 | typedef Charset1_2<HBUINT16> Charset2; |
435 | typedef Charset_Range<HBUINT8> Charset1_Range; |
436 | typedef Charset_Range<HBUINT16> Charset2_Range; |
437 | |
438 | struct Charset { |
439 | bool sanitize (hb_sanitize_context_t *c) const |
440 | { |
441 | TRACE_SANITIZE (this); |
442 | |
443 | if (unlikely (!c->check_struct (this))) |
444 | return_trace (false); |
445 | if (format == 0) |
446 | return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); |
447 | else if (format == 1) |
448 | return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); |
449 | else if (likely (format == 2)) |
450 | return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); |
451 | else |
452 | return_trace (false); |
453 | } |
454 | |
455 | /* serialize a fullset Charset */ |
456 | bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) |
457 | { |
458 | TRACE_SERIALIZE (this); |
459 | unsigned int size = src.get_size (num_glyphs); |
460 | Charset *dest = c->allocate_size<Charset> (size); |
461 | if (unlikely (dest == nullptr)) return_trace (false); |
462 | memcpy (dest, &src, size); |
463 | return_trace (true); |
464 | } |
465 | |
466 | /* serialize a subset Charset */ |
467 | bool serialize (hb_serialize_context_t *c, |
468 | uint8_t format, |
469 | unsigned int num_glyphs, |
470 | const hb_vector_t<code_pair_t>& sid_ranges) |
471 | { |
472 | TRACE_SERIALIZE (this); |
473 | Charset *dest = c->extend_min (*this); |
474 | if (unlikely (dest == nullptr)) return_trace (false); |
475 | dest->format.set (format); |
476 | if (format == 0) |
477 | { |
478 | Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); |
479 | if (unlikely (fmt0 == nullptr)) return_trace (false); |
480 | unsigned int glyph = 0; |
481 | for (unsigned int i = 0; i < sid_ranges.length; i++) |
482 | { |
483 | hb_codepoint_t sid = sid_ranges[i].code; |
484 | for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) |
485 | fmt0->sids[glyph++].set (sid++); |
486 | } |
487 | } |
488 | else if (format == 1) |
489 | { |
490 | Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); |
491 | if (unlikely (fmt1 == nullptr)) return_trace (false); |
492 | for (unsigned int i = 0; i < sid_ranges.length; i++) |
493 | { |
494 | if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) |
495 | return_trace (false); |
496 | fmt1->ranges[i].first.set (sid_ranges[i].code); |
497 | fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph); |
498 | } |
499 | } |
500 | else /* format 2 */ |
501 | { |
502 | Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); |
503 | if (unlikely (fmt2 == nullptr)) return_trace (false); |
504 | for (unsigned int i = 0; i < sid_ranges.length; i++) |
505 | { |
506 | if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) |
507 | return_trace (false); |
508 | fmt2->ranges[i].first.set (sid_ranges[i].code); |
509 | fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph); |
510 | } |
511 | } |
512 | return_trace (true); |
513 | } |
514 | |
515 | /* parallel to above: calculate the size of a subset Charset */ |
516 | static unsigned int calculate_serialized_size ( |
517 | uint8_t format, |
518 | unsigned int count) |
519 | { |
520 | unsigned int size = min_size; |
521 | if (format == 0) |
522 | size += Charset0::min_size + HBUINT16::static_size * (count - 1); |
523 | else if (format == 1) |
524 | size += Charset1::min_size + Charset1_Range::static_size * count; |
525 | else |
526 | size += Charset2::min_size + Charset2_Range::static_size * count; |
527 | |
528 | return size; |
529 | } |
530 | |
531 | unsigned int get_size (unsigned int num_glyphs) const |
532 | { |
533 | unsigned int size = min_size; |
534 | if (format == 0) |
535 | size += u.format0.get_size (num_glyphs); |
536 | else if (format == 1) |
537 | size += u.format1.get_size (num_glyphs); |
538 | else |
539 | size += u.format2.get_size (num_glyphs); |
540 | return size; |
541 | } |
542 | |
543 | hb_codepoint_t get_sid (hb_codepoint_t glyph) const |
544 | { |
545 | if (format == 0) |
546 | return u.format0.get_sid (glyph); |
547 | else if (format == 1) |
548 | return u.format1.get_sid (glyph); |
549 | else |
550 | return u.format2.get_sid (glyph); |
551 | } |
552 | |
553 | hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const |
554 | { |
555 | if (format == 0) |
556 | return u.format0.get_glyph (sid, num_glyphs); |
557 | else if (format == 1) |
558 | return u.format1.get_glyph (sid, num_glyphs); |
559 | else |
560 | return u.format2.get_glyph (sid, num_glyphs); |
561 | } |
562 | |
563 | HBUINT8 format; |
564 | union { |
565 | Charset0 format0; |
566 | Charset1 format1; |
567 | Charset2 format2; |
568 | } u; |
569 | |
570 | DEFINE_SIZE_MIN (1); |
571 | }; |
572 | |
573 | struct CFF1StringIndex : CFF1Index |
574 | { |
575 | bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, |
576 | unsigned int offSize_, const remap_t &sidmap) |
577 | { |
578 | TRACE_SERIALIZE (this); |
579 | if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) |
580 | { |
581 | if (!unlikely (c->extend_min (this->count))) |
582 | return_trace (false); |
583 | count.set (0); |
584 | return_trace (true); |
585 | } |
586 | |
587 | byte_str_array_t bytesArray; |
588 | bytesArray.init (); |
589 | if (!bytesArray.resize (sidmap.get_count ())) |
590 | return_trace (false); |
591 | for (unsigned int i = 0; i < strings.count; i++) |
592 | { |
593 | hb_codepoint_t j = sidmap[i]; |
594 | if (j != CFF_UNDEF_CODE) |
595 | bytesArray[j] = strings[i]; |
596 | } |
597 | |
598 | bool result = CFF1Index::serialize (c, offSize_, bytesArray); |
599 | bytesArray.fini (); |
600 | return_trace (result); |
601 | } |
602 | |
603 | /* in parallel to above */ |
604 | unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const remap_t &sidmap) const |
605 | { |
606 | offSize = 0; |
607 | if ((count == 0) || (sidmap.get_count () == 0)) |
608 | return count.static_size; |
609 | |
610 | unsigned int dataSize = 0; |
611 | for (unsigned int i = 0; i < count; i++) |
612 | if (sidmap[i] != CFF_UNDEF_CODE) |
613 | dataSize += length_at (i); |
614 | |
615 | offSize = calcOffSize(dataSize); |
616 | return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize); |
617 | } |
618 | }; |
619 | |
620 | struct cff1_top_dict_interp_env_t : num_interp_env_t |
621 | { |
622 | cff1_top_dict_interp_env_t () |
623 | : num_interp_env_t(), prev_offset(0), last_offset(0) {} |
624 | |
625 | unsigned int prev_offset; |
626 | unsigned int last_offset; |
627 | }; |
628 | |
629 | struct name_dict_values_t |
630 | { |
631 | enum name_dict_val_index_t |
632 | { |
633 | version, |
634 | notice, |
635 | copyright, |
636 | fullName, |
637 | familyName, |
638 | weight, |
639 | postscript, |
640 | fontName, |
641 | baseFontName, |
642 | registry, |
643 | ordering, |
644 | |
645 | ValCount |
646 | }; |
647 | |
648 | void init () |
649 | { |
650 | for (unsigned int i = 0; i < ValCount; i++) |
651 | values[i] = CFF_UNDEF_SID; |
652 | } |
653 | |
654 | unsigned int& operator[] (unsigned int i) |
655 | { assert (i < ValCount); return values[i]; } |
656 | |
657 | unsigned int operator[] (unsigned int i) const |
658 | { assert (i < ValCount); return values[i]; } |
659 | |
660 | static enum name_dict_val_index_t name_op_to_index (op_code_t op) |
661 | { |
662 | switch (op) { |
663 | default: // can't happen - just make some compiler happy |
664 | case OpCode_version: |
665 | return version; |
666 | case OpCode_Notice: |
667 | return notice; |
668 | case OpCode_Copyright: |
669 | return copyright; |
670 | case OpCode_FullName: |
671 | return fullName; |
672 | case OpCode_FamilyName: |
673 | return familyName; |
674 | case OpCode_Weight: |
675 | return weight; |
676 | case OpCode_PostScript: |
677 | return postscript; |
678 | case OpCode_FontName: |
679 | return fontName; |
680 | case OpCode_BaseFontName: |
681 | return baseFontName; |
682 | } |
683 | } |
684 | |
685 | unsigned int values[ValCount]; |
686 | }; |
687 | |
688 | struct cff1_top_dict_val_t : op_str_t |
689 | { |
690 | unsigned int last_arg_offset; |
691 | }; |
692 | |
693 | struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t> |
694 | { |
695 | void init () |
696 | { |
697 | top_dict_values_t<cff1_top_dict_val_t>::init (); |
698 | |
699 | nameSIDs.init (); |
700 | ros_supplement = 0; |
701 | cidCount = 8720; |
702 | EncodingOffset = 0; |
703 | CharsetOffset = 0; |
704 | FDSelectOffset = 0; |
705 | privateDictInfo.init (); |
706 | } |
707 | void fini () { top_dict_values_t<cff1_top_dict_val_t>::fini (); } |
708 | |
709 | bool is_CID () const |
710 | { return nameSIDs[name_dict_values_t::registry] != CFF_UNDEF_SID; } |
711 | |
712 | name_dict_values_t nameSIDs; |
713 | unsigned int ros_supplement_offset; |
714 | unsigned int ros_supplement; |
715 | unsigned int cidCount; |
716 | |
717 | unsigned int EncodingOffset; |
718 | unsigned int CharsetOffset; |
719 | unsigned int FDSelectOffset; |
720 | table_info_t privateDictInfo; |
721 | }; |
722 | |
723 | struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t> |
724 | { |
725 | static void process_op (op_code_t op, cff1_top_dict_interp_env_t& env, cff1_top_dict_values_t& dictval) |
726 | { |
727 | cff1_top_dict_val_t val; |
728 | val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ |
729 | |
730 | switch (op) { |
731 | case OpCode_version: |
732 | case OpCode_Notice: |
733 | case OpCode_Copyright: |
734 | case OpCode_FullName: |
735 | case OpCode_FamilyName: |
736 | case OpCode_Weight: |
737 | case OpCode_PostScript: |
738 | case OpCode_BaseFontName: |
739 | dictval.nameSIDs[name_dict_values_t::name_op_to_index (op)] = env.argStack.pop_uint (); |
740 | env.clear_args (); |
741 | break; |
742 | case OpCode_isFixedPitch: |
743 | case OpCode_ItalicAngle: |
744 | case OpCode_UnderlinePosition: |
745 | case OpCode_UnderlineThickness: |
746 | case OpCode_PaintType: |
747 | case OpCode_CharstringType: |
748 | case OpCode_UniqueID: |
749 | case OpCode_StrokeWidth: |
750 | case OpCode_SyntheticBase: |
751 | case OpCode_CIDFontVersion: |
752 | case OpCode_CIDFontRevision: |
753 | case OpCode_CIDFontType: |
754 | case OpCode_UIDBase: |
755 | case OpCode_FontBBox: |
756 | case OpCode_XUID: |
757 | case OpCode_BaseFontBlend: |
758 | env.clear_args (); |
759 | break; |
760 | |
761 | case OpCode_CIDCount: |
762 | dictval.cidCount = env.argStack.pop_uint (); |
763 | env.clear_args (); |
764 | break; |
765 | |
766 | case OpCode_ROS: |
767 | dictval.ros_supplement = env.argStack.pop_uint (); |
768 | dictval.nameSIDs[name_dict_values_t::ordering] = env.argStack.pop_uint (); |
769 | dictval.nameSIDs[name_dict_values_t::registry] = env.argStack.pop_uint (); |
770 | env.clear_args (); |
771 | break; |
772 | |
773 | case OpCode_Encoding: |
774 | dictval.EncodingOffset = env.argStack.pop_uint (); |
775 | env.clear_args (); |
776 | if (unlikely (dictval.EncodingOffset == 0)) return; |
777 | break; |
778 | |
779 | case OpCode_charset: |
780 | dictval.CharsetOffset = env.argStack.pop_uint (); |
781 | env.clear_args (); |
782 | if (unlikely (dictval.CharsetOffset == 0)) return; |
783 | break; |
784 | |
785 | case OpCode_FDSelect: |
786 | dictval.FDSelectOffset = env.argStack.pop_uint (); |
787 | env.clear_args (); |
788 | break; |
789 | |
790 | case OpCode_Private: |
791 | dictval.privateDictInfo.offset = env.argStack.pop_uint (); |
792 | dictval.privateDictInfo.size = env.argStack.pop_uint (); |
793 | env.clear_args (); |
794 | break; |
795 | |
796 | default: |
797 | env.last_offset = env.str_ref.offset; |
798 | top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval); |
799 | /* Record this operand below if stack is empty, otherwise done */ |
800 | if (!env.argStack.is_empty ()) return; |
801 | break; |
802 | } |
803 | |
804 | if (unlikely (env.in_error ())) return; |
805 | |
806 | dictval.add_op (op, env.str_ref, val); |
807 | } |
808 | }; |
809 | |
810 | struct cff1_font_dict_values_t : dict_values_t<op_str_t> |
811 | { |
812 | void init () |
813 | { |
814 | dict_values_t<op_str_t>::init (); |
815 | privateDictInfo.init (); |
816 | fontName = CFF_UNDEF_SID; |
817 | } |
818 | void fini () { dict_values_t<op_str_t>::fini (); } |
819 | |
820 | table_info_t privateDictInfo; |
821 | unsigned int fontName; |
822 | }; |
823 | |
824 | struct cff1_font_dict_opset_t : dict_opset_t |
825 | { |
826 | static void process_op (op_code_t op, num_interp_env_t& env, cff1_font_dict_values_t& dictval) |
827 | { |
828 | switch (op) { |
829 | case OpCode_FontName: |
830 | dictval.fontName = env.argStack.pop_uint (); |
831 | env.clear_args (); |
832 | break; |
833 | case OpCode_FontMatrix: |
834 | case OpCode_PaintType: |
835 | env.clear_args (); |
836 | break; |
837 | case OpCode_Private: |
838 | dictval.privateDictInfo.offset = env.argStack.pop_uint (); |
839 | dictval.privateDictInfo.size = env.argStack.pop_uint (); |
840 | env.clear_args (); |
841 | break; |
842 | |
843 | default: |
844 | dict_opset_t::process_op (op, env); |
845 | if (!env.argStack.is_empty ()) return; |
846 | break; |
847 | } |
848 | |
849 | if (unlikely (env.in_error ())) return; |
850 | |
851 | dictval.add_op (op, env.str_ref); |
852 | } |
853 | }; |
854 | |
855 | template <typename VAL> |
856 | struct cff1_private_dict_values_base_t : dict_values_t<VAL> |
857 | { |
858 | void init () |
859 | { |
860 | dict_values_t<VAL>::init (); |
861 | subrsOffset = 0; |
862 | localSubrs = &Null(CFF1Subrs); |
863 | } |
864 | void fini () { dict_values_t<VAL>::fini (); } |
865 | |
866 | unsigned int calculate_serialized_size () const |
867 | { |
868 | unsigned int size = 0; |
869 | for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++) |
870 | if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs) |
871 | size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); |
872 | else |
873 | size += dict_values_t<VAL>::get_value (i).str.length; |
874 | return size; |
875 | } |
876 | |
877 | unsigned int subrsOffset; |
878 | const CFF1Subrs *localSubrs; |
879 | }; |
880 | |
881 | typedef cff1_private_dict_values_base_t<op_str_t> cff1_private_dict_values_subset_t; |
882 | typedef cff1_private_dict_values_base_t<num_dict_val_t> cff1_private_dict_values_t; |
883 | |
884 | struct cff1_private_dict_opset_t : dict_opset_t |
885 | { |
886 | static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_t& dictval) |
887 | { |
888 | num_dict_val_t val; |
889 | val.init (); |
890 | |
891 | switch (op) { |
892 | case OpCode_BlueValues: |
893 | case OpCode_OtherBlues: |
894 | case OpCode_FamilyBlues: |
895 | case OpCode_FamilyOtherBlues: |
896 | case OpCode_StemSnapH: |
897 | case OpCode_StemSnapV: |
898 | env.clear_args (); |
899 | break; |
900 | case OpCode_StdHW: |
901 | case OpCode_StdVW: |
902 | case OpCode_BlueScale: |
903 | case OpCode_BlueShift: |
904 | case OpCode_BlueFuzz: |
905 | case OpCode_ForceBold: |
906 | case OpCode_LanguageGroup: |
907 | case OpCode_ExpansionFactor: |
908 | case OpCode_initialRandomSeed: |
909 | case OpCode_defaultWidthX: |
910 | case OpCode_nominalWidthX: |
911 | val.single_val = env.argStack.pop_num (); |
912 | env.clear_args (); |
913 | break; |
914 | case OpCode_Subrs: |
915 | dictval.subrsOffset = env.argStack.pop_uint (); |
916 | env.clear_args (); |
917 | break; |
918 | |
919 | default: |
920 | dict_opset_t::process_op (op, env); |
921 | if (!env.argStack.is_empty ()) return; |
922 | break; |
923 | } |
924 | |
925 | if (unlikely (env.in_error ())) return; |
926 | |
927 | dictval.add_op (op, env.str_ref, val); |
928 | } |
929 | }; |
930 | |
931 | struct cff1_private_dict_opset_subset : dict_opset_t |
932 | { |
933 | static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval) |
934 | { |
935 | switch (op) { |
936 | case OpCode_BlueValues: |
937 | case OpCode_OtherBlues: |
938 | case OpCode_FamilyBlues: |
939 | case OpCode_FamilyOtherBlues: |
940 | case OpCode_StemSnapH: |
941 | case OpCode_StemSnapV: |
942 | case OpCode_StdHW: |
943 | case OpCode_StdVW: |
944 | case OpCode_BlueScale: |
945 | case OpCode_BlueShift: |
946 | case OpCode_BlueFuzz: |
947 | case OpCode_ForceBold: |
948 | case OpCode_LanguageGroup: |
949 | case OpCode_ExpansionFactor: |
950 | case OpCode_initialRandomSeed: |
951 | case OpCode_defaultWidthX: |
952 | case OpCode_nominalWidthX: |
953 | env.clear_args (); |
954 | break; |
955 | |
956 | case OpCode_Subrs: |
957 | dictval.subrsOffset = env.argStack.pop_uint (); |
958 | env.clear_args (); |
959 | break; |
960 | |
961 | default: |
962 | dict_opset_t::process_op (op, env); |
963 | if (!env.argStack.is_empty ()) return; |
964 | break; |
965 | } |
966 | |
967 | if (unlikely (env.in_error ())) return; |
968 | |
969 | dictval.add_op (op, env.str_ref); |
970 | } |
971 | }; |
972 | |
973 | typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_top_dict_interp_env_t> cff1_top_dict_interpreter_t; |
974 | typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t; |
975 | |
976 | typedef CFF1Index CFF1NameIndex; |
977 | typedef CFF1IndexOf<TopDict> CFF1TopDictIndex; |
978 | |
979 | } /* namespace CFF */ |
980 | |
981 | namespace OT { |
982 | |
983 | using namespace CFF; |
984 | |
985 | struct cff1 |
986 | { |
987 | static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1; |
988 | |
989 | bool sanitize (hb_sanitize_context_t *c) const |
990 | { |
991 | TRACE_SANITIZE (this); |
992 | return_trace (c->check_struct (this) && |
993 | likely (version.major == 1)); |
994 | } |
995 | |
996 | template <typename PRIVOPSET, typename PRIVDICTVAL> |
997 | struct accelerator_templ_t |
998 | { |
999 | void init (hb_face_t *face) |
1000 | { |
1001 | topDict.init (); |
1002 | fontDicts.init (); |
1003 | privateDicts.init (); |
1004 | |
1005 | this->blob = sc.reference_table<cff1> (face); |
1006 | |
1007 | /* setup for run-time santization */ |
1008 | sc.init (this->blob); |
1009 | sc.start_processing (); |
1010 | |
1011 | const OT::cff1 *cff = this->blob->template as<OT::cff1> (); |
1012 | |
1013 | if (cff == &Null(OT::cff1)) |
1014 | { fini (); return; } |
1015 | |
1016 | nameIndex = &cff->nameIndex (cff); |
1017 | if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) |
1018 | { fini (); return; } |
1019 | |
1020 | topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ()); |
1021 | if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) |
1022 | { fini (); return; } |
1023 | |
1024 | { /* parse top dict */ |
1025 | const byte_str_t topDictStr = (*topDictIndex)[0]; |
1026 | if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } |
1027 | cff1_top_dict_interpreter_t top_interp; |
1028 | top_interp.env.init (topDictStr); |
1029 | topDict.init (); |
1030 | if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } |
1031 | } |
1032 | |
1033 | if (is_predef_charset ()) |
1034 | charset = &Null(Charset); |
1035 | else |
1036 | { |
1037 | charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset); |
1038 | if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } |
1039 | } |
1040 | |
1041 | fdCount = 1; |
1042 | if (is_CID ()) |
1043 | { |
1044 | fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset); |
1045 | fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset); |
1046 | if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || |
1047 | (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) |
1048 | { fini (); return; } |
1049 | |
1050 | fdCount = fdArray->count; |
1051 | } |
1052 | else |
1053 | { |
1054 | fdArray = &Null(CFF1FDArray); |
1055 | fdSelect = &Null(CFF1FDSelect); |
1056 | } |
1057 | |
1058 | stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ()); |
1059 | if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) |
1060 | { fini (); return; } |
1061 | |
1062 | globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ()); |
1063 | if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) |
1064 | { fini (); return; } |
1065 | |
1066 | charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset); |
1067 | |
1068 | if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) |
1069 | { fini (); return; } |
1070 | |
1071 | num_glyphs = charStrings->count; |
1072 | if (num_glyphs != sc.get_num_glyphs ()) |
1073 | { fini (); return; } |
1074 | |
1075 | privateDicts.resize (fdCount); |
1076 | for (unsigned int i = 0; i < fdCount; i++) |
1077 | privateDicts[i].init (); |
1078 | |
1079 | // parse CID font dicts and gather private dicts |
1080 | if (is_CID ()) |
1081 | { |
1082 | for (unsigned int i = 0; i < fdCount; i++) |
1083 | { |
1084 | byte_str_t fontDictStr = (*fdArray)[i]; |
1085 | if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } |
1086 | cff1_font_dict_values_t *font; |
1087 | cff1_font_dict_interpreter_t font_interp; |
1088 | font_interp.env.init (fontDictStr); |
1089 | font = fontDicts.push (); |
1090 | if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; } |
1091 | font->init (); |
1092 | if (unlikely (!font_interp.interpret (*font))) { fini (); return; } |
1093 | PRIVDICTVAL *priv = &privateDicts[i]; |
1094 | const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); |
1095 | if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } |
1096 | dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; |
1097 | priv_interp.env.init (privDictStr); |
1098 | priv->init (); |
1099 | if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } |
1100 | |
1101 | priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); |
1102 | if (priv->localSubrs != &Null(CFF1Subrs) && |
1103 | unlikely (!priv->localSubrs->sanitize (&sc))) |
1104 | { fini (); return; } |
1105 | } |
1106 | } |
1107 | else /* non-CID */ |
1108 | { |
1109 | cff1_top_dict_values_t *font = &topDict; |
1110 | PRIVDICTVAL *priv = &privateDicts[0]; |
1111 | |
1112 | const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); |
1113 | if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } |
1114 | dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; |
1115 | priv_interp.env.init (privDictStr); |
1116 | priv->init (); |
1117 | if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } |
1118 | |
1119 | priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); |
1120 | if (priv->localSubrs != &Null(CFF1Subrs) && |
1121 | unlikely (!priv->localSubrs->sanitize (&sc))) |
1122 | { fini (); return; } |
1123 | } |
1124 | } |
1125 | |
1126 | void fini () |
1127 | { |
1128 | sc.end_processing (); |
1129 | topDict.fini (); |
1130 | fontDicts.fini_deep (); |
1131 | privateDicts.fini_deep (); |
1132 | hb_blob_destroy (blob); |
1133 | blob = nullptr; |
1134 | } |
1135 | |
1136 | bool is_valid () const { return blob != nullptr; } |
1137 | bool is_CID () const { return topDict.is_CID (); } |
1138 | |
1139 | bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; } |
1140 | |
1141 | unsigned int std_code_to_glyph (hb_codepoint_t code) const |
1142 | { |
1143 | hb_codepoint_t sid = lookup_standard_encoding_for_sid (code); |
1144 | if (unlikely (sid == CFF_UNDEF_SID)) |
1145 | return 0; |
1146 | |
1147 | if (charset != &Null(Charset)) |
1148 | return charset->get_glyph (sid, num_glyphs); |
1149 | else if ((topDict.CharsetOffset == ISOAdobeCharset) |
1150 | && (code <= 228 /*zcaron*/)) return sid; |
1151 | return 0; |
1152 | } |
1153 | |
1154 | protected: |
1155 | hb_blob_t *blob; |
1156 | hb_sanitize_context_t sc; |
1157 | |
1158 | public: |
1159 | const Charset *charset; |
1160 | const CFF1NameIndex *nameIndex; |
1161 | const CFF1TopDictIndex *topDictIndex; |
1162 | const CFF1StringIndex *stringIndex; |
1163 | const CFF1Subrs *globalSubrs; |
1164 | const CFF1CharStrings *charStrings; |
1165 | const CFF1FDArray *fdArray; |
1166 | const CFF1FDSelect *fdSelect; |
1167 | unsigned int fdCount; |
1168 | |
1169 | cff1_top_dict_values_t topDict; |
1170 | hb_vector_t<cff1_font_dict_values_t> fontDicts; |
1171 | hb_vector_t<PRIVDICTVAL> privateDicts; |
1172 | |
1173 | unsigned int num_glyphs; |
1174 | }; |
1175 | |
1176 | struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> |
1177 | { |
1178 | HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; |
1179 | HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; |
1180 | }; |
1181 | |
1182 | struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> |
1183 | { |
1184 | void init (hb_face_t *face) |
1185 | { |
1186 | SUPER::init (face); |
1187 | if (blob == nullptr) return; |
1188 | |
1189 | const OT::cff1 *cff = this->blob->as<OT::cff1> (); |
1190 | encoding = &Null(Encoding); |
1191 | if (is_CID ()) |
1192 | { |
1193 | if (unlikely (charset == &Null(Charset))) { fini (); return; } |
1194 | } |
1195 | else |
1196 | { |
1197 | if (!is_predef_encoding ()) |
1198 | { |
1199 | encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset); |
1200 | if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } |
1201 | } |
1202 | } |
1203 | } |
1204 | |
1205 | bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } |
1206 | |
1207 | hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const |
1208 | { |
1209 | if (encoding != &Null(Encoding)) |
1210 | return encoding->get_code (glyph); |
1211 | else |
1212 | { |
1213 | hb_codepoint_t sid = glyph_to_sid (glyph); |
1214 | if (sid == 0) return 0; |
1215 | hb_codepoint_t code = 0; |
1216 | switch (topDict.EncodingOffset) |
1217 | { |
1218 | case StandardEncoding: |
1219 | code = lookup_standard_encoding_for_code (sid); |
1220 | break; |
1221 | case ExpertEncoding: |
1222 | code = lookup_expert_encoding_for_code (sid); |
1223 | break; |
1224 | default: |
1225 | break; |
1226 | } |
1227 | return code; |
1228 | } |
1229 | } |
1230 | |
1231 | hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const |
1232 | { |
1233 | if (charset != &Null(Charset)) |
1234 | return charset->get_sid (glyph); |
1235 | else |
1236 | { |
1237 | hb_codepoint_t sid = 0; |
1238 | switch (topDict.CharsetOffset) |
1239 | { |
1240 | case ISOAdobeCharset: |
1241 | if (glyph <= 228 /*zcaron*/) sid = glyph; |
1242 | break; |
1243 | case ExpertCharset: |
1244 | sid = lookup_expert_charset_for_sid (glyph); |
1245 | break; |
1246 | case ExpertSubsetCharset: |
1247 | sid = lookup_expert_subset_charset_for_sid (glyph); |
1248 | break; |
1249 | default: |
1250 | break; |
1251 | } |
1252 | return sid; |
1253 | } |
1254 | } |
1255 | |
1256 | const Encoding *encoding; |
1257 | |
1258 | private: |
1259 | typedef accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> SUPER; |
1260 | }; |
1261 | |
1262 | bool subset (hb_subset_plan_t *plan) const |
1263 | { |
1264 | hb_blob_t *cff_prime = nullptr; |
1265 | |
1266 | bool success = true; |
1267 | if (hb_subset_cff1 (plan, &cff_prime)) { |
1268 | success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime); |
1269 | hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source); |
1270 | success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); |
1271 | hb_blob_destroy (head_blob); |
1272 | } else { |
1273 | success = false; |
1274 | } |
1275 | hb_blob_destroy (cff_prime); |
1276 | |
1277 | return success; |
1278 | } |
1279 | |
1280 | protected: |
1281 | HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); |
1282 | HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); |
1283 | HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); |
1284 | HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); |
1285 | HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); |
1286 | |
1287 | public: |
1288 | FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */ |
1289 | OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */ |
1290 | HBUINT8 offSize; /* offset size (unused?) */ |
1291 | |
1292 | public: |
1293 | DEFINE_SIZE_STATIC (4); |
1294 | }; |
1295 | |
1296 | struct cff1_accelerator_t : cff1::accelerator_t {}; |
1297 | } /* namespace OT */ |
1298 | |
1299 | #endif /* HB_OT_CFF1_TABLE_HH */ |
1300 | |