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