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

source code of flutter_engine/third_party/harfbuzz/src/hb-ot-cff1-table.hh