2 * Copyright © 2018 Adobe Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Adobe Author(s): Michiharu Ariza
27 #ifndef HB_OT_CFF1_TABLE_HH
28 #define HB_OT_CFF1_TABLE_HH
30 #include "hb-ot-head-table.hh"
31 #include "hb-ot-cff-common.hh"
32 #include "hb-subset-cff1.hh"
37 * CFF -- Compact Font Format (CFF)
38 * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
40 #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
42 #define CFF_UNDEF_SID CFF_UNDEF_CODE
44 enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
45 enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
47 typedef CFFIndex<HBUINT16> CFF1Index;
48 template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {};
50 typedef CFFIndex<HBUINT16> CFF1Index;
51 typedef CFF1Index CFF1CharStrings;
52 typedef FDArray<HBUINT16> CFF1FDArray;
53 typedef Subrs<HBUINT16> CFF1Subrs;
55 struct CFF1FDSelect : FDSelect {};
59 bool sanitize (hb_sanitize_context_t *c) const
61 TRACE_SANITIZE (this);
62 return_trace (codes.sanitize (c));
65 hb_codepoint_t get_code (hb_codepoint_t glyph) const
69 if (glyph < nCodes ())
71 return (hb_codepoint_t)codes[glyph];
74 return CFF_UNDEF_CODE;
77 HBUINT8 &nCodes () { return codes.len; }
78 HBUINT8 nCodes () const { return codes.len; }
80 ArrayOf<HBUINT8, HBUINT8> codes;
82 DEFINE_SIZE_ARRAY_SIZED (1, codes);
85 struct Encoding1_Range {
86 bool sanitize (hb_sanitize_context_t *c) const
88 TRACE_SANITIZE (this);
89 return_trace (c->check_struct (this));
95 DEFINE_SIZE_STATIC (2);
99 bool sanitize (hb_sanitize_context_t *c) const
101 TRACE_SANITIZE (this);
102 return_trace (ranges.sanitize (c));
105 hb_codepoint_t get_code (hb_codepoint_t glyph) const
109 for (unsigned int i = 0; i < nRanges (); i++)
111 if (glyph <= ranges[i].nLeft)
113 return (hb_codepoint_t)ranges[i].first + glyph;
115 glyph -= (ranges[i].nLeft + 1);
117 return CFF_UNDEF_CODE;
120 HBUINT8 &nRanges () { return ranges.len; }
121 HBUINT8 nRanges () const { return ranges.len; }
123 ArrayOf<Encoding1_Range, HBUINT8> ranges;
125 DEFINE_SIZE_ARRAY_SIZED (1, ranges);
128 struct SuppEncoding {
129 bool sanitize (hb_sanitize_context_t *c) const
131 TRACE_SANITIZE (this);
132 return_trace (c->check_struct (this));
138 DEFINE_SIZE_STATIC (3);
141 struct CFF1SuppEncData {
142 bool sanitize (hb_sanitize_context_t *c) const
144 TRACE_SANITIZE (this);
145 return_trace (supps.sanitize (c));
148 void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
150 for (unsigned int i = 0; i < nSups (); i++)
151 if (sid == supps[i].glyph)
152 codes.push (supps[i].code);
155 HBUINT8 &nSups () { return supps.len; }
156 HBUINT8 nSups () const { return supps.len; }
158 ArrayOf<SuppEncoding, HBUINT8> supps;
160 DEFINE_SIZE_ARRAY_SIZED (1, supps);
164 bool sanitize (hb_sanitize_context_t *c) const
166 TRACE_SANITIZE (this);
168 if (unlikely (!c->check_struct (this)))
169 return_trace (false);
170 unsigned int fmt = format & 0x7F;
171 if (unlikely (fmt > 1))
172 return_trace (false);
173 if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c))))
174 return_trace (false);
175 return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c));
178 /* serialize a fullset Encoding */
179 bool serialize (hb_serialize_context_t *c, const Encoding &src)
181 TRACE_SERIALIZE (this);
182 unsigned int size = src.get_size ();
183 Encoding *dest = c->allocate_size<Encoding> (size);
184 if (unlikely (dest == nullptr)) return_trace (false);
185 memcpy (dest, &src, size);
189 /* serialize a subset Encoding */
190 bool serialize (hb_serialize_context_t *c,
192 unsigned int enc_count,
193 const hb_vector_t<code_pair_t>& code_ranges,
194 const hb_vector_t<code_pair_t>& supp_codes)
196 TRACE_SERIALIZE (this);
197 Encoding *dest = c->extend_min (*this);
198 if (unlikely (dest == nullptr)) return_trace (false);
199 dest->format.set (format | ((supp_codes.length > 0)? 0x80: 0));
202 Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count);
203 if (unlikely (fmt0 == nullptr)) return_trace (false);
204 fmt0->nCodes ().set (enc_count);
205 unsigned int glyph = 0;
206 for (unsigned int i = 0; i < code_ranges.length; i++)
208 hb_codepoint_t code = code_ranges[i].code;
209 for (int left = (int)code_ranges[i].glyph; left >= 0; left--)
210 fmt0->codes[glyph++].set (code++);
211 if (unlikely (!((glyph <= 0x100) && (code <= 0x100))))
212 return_trace (false);
217 Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length);
218 if (unlikely (fmt1 == nullptr)) return_trace (false);
219 fmt1->nRanges ().set (code_ranges.length);
220 for (unsigned int i = 0; i < code_ranges.length; i++)
222 if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF))))
223 return_trace (false);
224 fmt1->ranges[i].first.set (code_ranges[i].code);
225 fmt1->ranges[i].nLeft.set (code_ranges[i].glyph);
228 if (supp_codes.length > 0)
230 CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length);
231 if (unlikely (suppData == nullptr)) return_trace (false);
232 suppData->nSups ().set (supp_codes.length);
233 for (unsigned int i = 0; i < supp_codes.length; i++)
235 suppData->supps[i].code.set (supp_codes[i].code);
236 suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */
242 /* parallel to above: calculate the size of a subset Encoding */
243 static unsigned int calculate_serialized_size (uint8_t format,
244 unsigned int enc_count,
245 unsigned int supp_count)
247 unsigned int size = min_size;
249 size += Encoding0::min_size + HBUINT8::static_size * enc_count;
251 size += Encoding1::min_size + Encoding1_Range::static_size * enc_count;
253 size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count;
257 unsigned int get_size () const
259 unsigned int size = min_size;
260 if (table_format () == 0)
261 size += u.format0.get_size ();
263 size += u.format1.get_size ();
264 if (has_supplement ())
265 size += suppEncData ().get_size ();
269 hb_codepoint_t get_code (hb_codepoint_t glyph) const
271 if (table_format () == 0)
272 return u.format0.get_code (glyph);
274 return u.format1.get_code (glyph);
277 uint8_t table_format () const { return (format & 0x7F); }
278 bool has_supplement () const { return (format & 0x80) != 0; }
280 void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const
283 if (has_supplement ())
284 suppEncData().get_codes (sid, codes);
288 const CFF1SuppEncData &suppEncData () const
290 if ((format & 0x7F) == 0)
291 return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]);
293 return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]);
303 /* CFF1SuppEncData suppEncData; */
310 bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
312 TRACE_SANITIZE (this);
313 return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
316 hb_codepoint_t get_sid (hb_codepoint_t glyph) const
321 return sids[glyph - 1];
324 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
329 for (unsigned int glyph = 1; glyph < num_glyphs; glyph++)
331 if (sids[glyph-1] == sid)
337 unsigned int get_size (unsigned int num_glyphs) const
339 assert (num_glyphs > 0);
340 return HBUINT16::static_size * (num_glyphs - 1);
345 DEFINE_SIZE_ARRAY(0, sids);
348 template <typename TYPE>
349 struct Charset_Range {
350 bool sanitize (hb_sanitize_context_t *c) const
352 TRACE_SANITIZE (this);
353 return_trace (c->check_struct (this));
359 DEFINE_SIZE_STATIC (HBUINT16::static_size + TYPE::static_size);
362 template <typename TYPE>
364 bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
366 TRACE_SANITIZE (this);
367 if (unlikely (!c->check_struct (this)))
368 return_trace (false);
370 for (unsigned int i = 0; num_glyphs > 0; i++)
372 if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1)))
373 return_trace (false);
374 num_glyphs -= (ranges[i].nLeft + 1);
379 hb_codepoint_t get_sid (hb_codepoint_t glyph) const
381 if (glyph == 0) return 0;
383 for (unsigned int i = 0;; i++)
385 if (glyph <= ranges[i].nLeft)
386 return (hb_codepoint_t)ranges[i].first + glyph;
387 glyph -= (ranges[i].nLeft + 1);
393 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
395 if (sid == 0) return 0;
396 hb_codepoint_t glyph = 1;
397 for (unsigned int i = 0;; i++)
399 if (glyph >= num_glyphs)
401 if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft))
402 return glyph + (sid - ranges[i].first);
403 glyph += (ranges[i].nLeft + 1);
409 unsigned int get_size (unsigned int num_glyphs) const
411 unsigned int size = HBUINT8::static_size;
412 int glyph = (int)num_glyphs;
416 for (unsigned int i = 0; glyph > 0; i++)
418 glyph -= (ranges[i].nLeft + 1);
419 size += Charset_Range<TYPE>::static_size;
425 Charset_Range<TYPE> ranges[VAR];
427 DEFINE_SIZE_ARRAY (0, ranges);
430 typedef Charset1_2<HBUINT8> Charset1;
431 typedef Charset1_2<HBUINT16> Charset2;
432 typedef Charset_Range<HBUINT8> Charset1_Range;
433 typedef Charset_Range<HBUINT16> Charset2_Range;
436 bool sanitize (hb_sanitize_context_t *c) const
438 TRACE_SANITIZE (this);
440 if (unlikely (!c->check_struct (this)))
441 return_trace (false);
443 return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
444 else if (format == 1)
445 return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
446 else if (likely (format == 2))
447 return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
449 return_trace (false);
452 /* serialize a fullset Charset */
453 bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
455 TRACE_SERIALIZE (this);
456 unsigned int size = src.get_size (num_glyphs);
457 Charset *dest = c->allocate_size<Charset> (size);
458 if (unlikely (dest == nullptr)) return_trace (false);
459 memcpy (dest, &src, size);
463 /* serialize a subset Charset */
464 bool serialize (hb_serialize_context_t *c,
466 unsigned int num_glyphs,
467 const hb_vector_t<code_pair_t>& sid_ranges)
469 TRACE_SERIALIZE (this);
470 Charset *dest = c->extend_min (*this);
471 if (unlikely (dest == nullptr)) return_trace (false);
472 dest->format.set (format);
475 Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
476 if (unlikely (fmt0 == nullptr)) return_trace (false);
477 unsigned int glyph = 0;
478 for (unsigned int i = 0; i < sid_ranges.length; i++)
480 hb_codepoint_t sid = sid_ranges[i].code;
481 for (int left = (int)sid_ranges[i].glyph; left >= 0; left--)
482 fmt0->sids[glyph++].set (sid++);
485 else if (format == 1)
487 Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
488 if (unlikely (fmt1 == nullptr)) return_trace (false);
489 for (unsigned int i = 0; i < sid_ranges.length; i++)
491 if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
492 return_trace (false);
493 fmt1->ranges[i].first.set (sid_ranges[i].code);
494 fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph);
499 Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
500 if (unlikely (fmt2 == nullptr)) return_trace (false);
501 for (unsigned int i = 0; i < sid_ranges.length; i++)
503 if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
504 return_trace (false);
505 fmt2->ranges[i].first.set (sid_ranges[i].code);
506 fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph);
512 /* parallel to above: calculate the size of a subset Charset */
513 static unsigned int calculate_serialized_size (
517 unsigned int size = min_size;
519 size += Charset0::min_size + HBUINT16::static_size * (count - 1);
520 else if (format == 1)
521 size += Charset1::min_size + Charset1_Range::static_size * count;
523 size += Charset2::min_size + Charset2_Range::static_size * count;
528 unsigned int get_size (unsigned int num_glyphs) const
530 unsigned int size = min_size;
532 size += u.format0.get_size (num_glyphs);
533 else if (format == 1)
534 size += u.format1.get_size (num_glyphs);
536 size += u.format2.get_size (num_glyphs);
540 hb_codepoint_t get_sid (hb_codepoint_t glyph) const
543 return u.format0.get_sid (glyph);
544 else if (format == 1)
545 return u.format1.get_sid (glyph);
547 return u.format2.get_sid (glyph);
550 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
553 return u.format0.get_glyph (sid, num_glyphs);
554 else if (format == 1)
555 return u.format1.get_glyph (sid, num_glyphs);
557 return u.format2.get_glyph (sid, num_glyphs);
570 struct CFF1StringIndex : CFF1Index
572 bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
573 unsigned int offSize_, const remap_t &sidmap)
575 TRACE_SERIALIZE (this);
576 if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
578 if (!unlikely (c->extend_min (this->count)))
579 return_trace (false);
584 byte_str_array_t bytesArray;
586 if (!bytesArray.resize (sidmap.get_count ()))
587 return_trace (false);
588 for (unsigned int i = 0; i < strings.count; i++)
590 hb_codepoint_t j = sidmap[i];
591 if (j != CFF_UNDEF_CODE)
592 bytesArray[j] = strings[i];
595 bool result = CFF1Index::serialize (c, offSize_, bytesArray);
597 return_trace (result);
600 /* in parallel to above */
601 unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const remap_t &sidmap) const
604 if ((count == 0) || (sidmap.get_count () == 0))
605 return count.static_size;
607 unsigned int dataSize = 0;
608 for (unsigned int i = 0; i < count; i++)
609 if (sidmap[i] != CFF_UNDEF_CODE)
610 dataSize += length_at (i);
612 offSize = calcOffSize(dataSize);
613 return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize);
617 struct cff1_top_dict_interp_env_t : num_interp_env_t
619 cff1_top_dict_interp_env_t ()
620 : num_interp_env_t(), prev_offset(0), last_offset(0) {}
622 unsigned int prev_offset;
623 unsigned int last_offset;
626 struct name_dict_values_t
628 enum name_dict_val_index_t
647 for (unsigned int i = 0; i < ValCount; i++)
648 values[i] = CFF_UNDEF_SID;
651 unsigned int& operator[] (unsigned int i)
652 { assert (i < ValCount); return values[i]; }
654 unsigned int operator[] (unsigned int i) const
655 { assert (i < ValCount); return values[i]; }
657 static enum name_dict_val_index_t name_op_to_index (op_code_t op)
660 default: // can't happen - just make some compiler happy
665 case OpCode_Copyright:
667 case OpCode_FullName:
669 case OpCode_FamilyName:
673 case OpCode_PostScript:
675 case OpCode_FontName:
677 case OpCode_BaseFontName:
682 unsigned int values[ValCount];
685 struct cff1_top_dict_val_t : op_str_t
687 unsigned int last_arg_offset;
690 struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
694 top_dict_values_t<cff1_top_dict_val_t>::init ();
702 privateDictInfo.init ();
704 void fini () { top_dict_values_t<cff1_top_dict_val_t>::fini (); }
707 { return nameSIDs[name_dict_values_t::registry] != CFF_UNDEF_SID; }
709 name_dict_values_t nameSIDs;
710 unsigned int ros_supplement_offset;
711 unsigned int ros_supplement;
712 unsigned int cidCount;
714 unsigned int EncodingOffset;
715 unsigned int CharsetOffset;
716 unsigned int FDSelectOffset;
717 table_info_t privateDictInfo;
720 struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
722 static void process_op (op_code_t op, cff1_top_dict_interp_env_t& env, cff1_top_dict_values_t& dictval)
724 cff1_top_dict_val_t val;
725 val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */
730 case OpCode_Copyright:
731 case OpCode_FullName:
732 case OpCode_FamilyName:
734 case OpCode_PostScript:
735 case OpCode_BaseFontName:
736 dictval.nameSIDs[name_dict_values_t::name_op_to_index (op)] = env.argStack.pop_uint ();
739 case OpCode_isFixedPitch:
740 case OpCode_ItalicAngle:
741 case OpCode_UnderlinePosition:
742 case OpCode_UnderlineThickness:
743 case OpCode_PaintType:
744 case OpCode_CharstringType:
745 case OpCode_UniqueID:
746 case OpCode_StrokeWidth:
747 case OpCode_SyntheticBase:
748 case OpCode_CIDFontVersion:
749 case OpCode_CIDFontRevision:
750 case OpCode_CIDFontType:
752 case OpCode_FontBBox:
754 case OpCode_BaseFontBlend:
758 case OpCode_CIDCount:
759 dictval.cidCount = env.argStack.pop_uint ();
764 dictval.ros_supplement = env.argStack.pop_uint ();
765 dictval.nameSIDs[name_dict_values_t::ordering] = env.argStack.pop_uint ();
766 dictval.nameSIDs[name_dict_values_t::registry] = env.argStack.pop_uint ();
770 case OpCode_Encoding:
771 dictval.EncodingOffset = env.argStack.pop_uint ();
773 if (unlikely (dictval.EncodingOffset == 0)) return;
777 dictval.CharsetOffset = env.argStack.pop_uint ();
779 if (unlikely (dictval.CharsetOffset == 0)) return;
782 case OpCode_FDSelect:
783 dictval.FDSelectOffset = env.argStack.pop_uint ();
788 dictval.privateDictInfo.offset = env.argStack.pop_uint ();
789 dictval.privateDictInfo.size = env.argStack.pop_uint ();
794 env.last_offset = env.str_ref.offset;
795 top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval);
796 /* Record this operand below if stack is empty, otherwise done */
797 if (!env.argStack.is_empty ()) return;
801 if (unlikely (env.in_error ())) return;
803 dictval.add_op (op, env.str_ref, val);
807 struct cff1_font_dict_values_t : dict_values_t<op_str_t>
811 dict_values_t<op_str_t>::init ();
812 privateDictInfo.init ();
813 fontName = CFF_UNDEF_SID;
815 void fini () { dict_values_t<op_str_t>::fini (); }
817 table_info_t privateDictInfo;
818 unsigned int fontName;
821 struct cff1_font_dict_opset_t : dict_opset_t
823 static void process_op (op_code_t op, num_interp_env_t& env, cff1_font_dict_values_t& dictval)
826 case OpCode_FontName:
827 dictval.fontName = env.argStack.pop_uint ();
830 case OpCode_FontMatrix:
831 case OpCode_PaintType:
835 dictval.privateDictInfo.offset = env.argStack.pop_uint ();
836 dictval.privateDictInfo.size = env.argStack.pop_uint ();
841 dict_opset_t::process_op (op, env);
842 if (!env.argStack.is_empty ()) return;
846 if (unlikely (env.in_error ())) return;
848 dictval.add_op (op, env.str_ref);
852 template <typename VAL>
853 struct cff1_private_dict_values_base_t : dict_values_t<VAL>
857 dict_values_t<VAL>::init ();
859 localSubrs = &Null(CFF1Subrs);
861 void fini () { dict_values_t<VAL>::fini (); }
863 unsigned int calculate_serialized_size () const
865 unsigned int size = 0;
866 for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
867 if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
868 size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
870 size += dict_values_t<VAL>::get_value (i).str.length;
874 unsigned int subrsOffset;
875 const CFF1Subrs *localSubrs;
878 typedef cff1_private_dict_values_base_t<op_str_t> cff1_private_dict_values_subset_t;
879 typedef cff1_private_dict_values_base_t<num_dict_val_t> cff1_private_dict_values_t;
881 struct cff1_private_dict_opset_t : dict_opset_t
883 static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_t& dictval)
889 case OpCode_BlueValues:
890 case OpCode_OtherBlues:
891 case OpCode_FamilyBlues:
892 case OpCode_FamilyOtherBlues:
893 case OpCode_StemSnapH:
894 case OpCode_StemSnapV:
899 case OpCode_BlueScale:
900 case OpCode_BlueShift:
901 case OpCode_BlueFuzz:
902 case OpCode_ForceBold:
903 case OpCode_LanguageGroup:
904 case OpCode_ExpansionFactor:
905 case OpCode_initialRandomSeed:
906 case OpCode_defaultWidthX:
907 case OpCode_nominalWidthX:
908 val.single_val = env.argStack.pop_num ();
912 dictval.subrsOffset = env.argStack.pop_uint ();
917 dict_opset_t::process_op (op, env);
918 if (!env.argStack.is_empty ()) return;
922 if (unlikely (env.in_error ())) return;
924 dictval.add_op (op, env.str_ref, val);
928 struct cff1_private_dict_opset_subset : dict_opset_t
930 static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval)
933 case OpCode_BlueValues:
934 case OpCode_OtherBlues:
935 case OpCode_FamilyBlues:
936 case OpCode_FamilyOtherBlues:
937 case OpCode_StemSnapH:
938 case OpCode_StemSnapV:
941 case OpCode_BlueScale:
942 case OpCode_BlueShift:
943 case OpCode_BlueFuzz:
944 case OpCode_ForceBold:
945 case OpCode_LanguageGroup:
946 case OpCode_ExpansionFactor:
947 case OpCode_initialRandomSeed:
948 case OpCode_defaultWidthX:
949 case OpCode_nominalWidthX:
954 dictval.subrsOffset = env.argStack.pop_uint ();
959 dict_opset_t::process_op (op, env);
960 if (!env.argStack.is_empty ()) return;
964 if (unlikely (env.in_error ())) return;
966 dictval.add_op (op, env.str_ref);
970 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;
971 typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t;
973 typedef CFF1Index CFF1NameIndex;
974 typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
976 } /* namespace CFF */
984 static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
986 bool sanitize (hb_sanitize_context_t *c) const
988 TRACE_SANITIZE (this);
989 return_trace (c->check_struct (this) &&
990 likely (version.major == 1));
993 template <typename PRIVOPSET, typename PRIVDICTVAL>
994 struct accelerator_templ_t
996 void init (hb_face_t *face)
1000 privateDicts.init ();
1002 this->blob = sc.reference_table<cff1> (face);
1004 /* setup for run-time santization */
1005 sc.init (this->blob);
1006 sc.start_processing ();
1008 const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
1010 if (cff == &Null(OT::cff1))
1011 { fini (); return; }
1013 nameIndex = &cff->nameIndex (cff);
1014 if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
1015 { fini (); return; }
1017 topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
1018 if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
1019 { fini (); return; }
1021 { /* parse top dict */
1022 const byte_str_t topDictStr = (*topDictIndex)[0];
1023 if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
1024 cff1_top_dict_interpreter_t top_interp;
1025 top_interp.env.init (topDictStr);
1027 if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
1030 if (is_predef_charset ())
1031 charset = &Null(Charset);
1034 charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
1035 if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; }
1041 fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
1042 fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
1043 if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) ||
1044 (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
1045 { fini (); return; }
1047 fdCount = fdArray->count;
1051 fdArray = &Null(CFF1FDArray);
1052 fdSelect = &Null(CFF1FDSelect);
1055 stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
1056 if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
1057 { fini (); return; }
1059 globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
1060 if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
1061 { fini (); return; }
1063 charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
1065 if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
1066 { fini (); return; }
1068 num_glyphs = charStrings->count;
1069 if (num_glyphs != sc.get_num_glyphs ())
1070 { fini (); return; }
1072 privateDicts.resize (fdCount);
1073 for (unsigned int i = 0; i < fdCount; i++)
1074 privateDicts[i].init ();
1076 // parse CID font dicts and gather private dicts
1079 for (unsigned int i = 0; i < fdCount; i++)
1081 byte_str_t fontDictStr = (*fdArray)[i];
1082 if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
1083 cff1_font_dict_values_t *font;
1084 cff1_font_dict_interpreter_t font_interp;
1085 font_interp.env.init (fontDictStr);
1086 font = fontDicts.push ();
1087 if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; }
1089 if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
1090 PRIVDICTVAL *priv = &privateDicts[i];
1091 const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
1092 if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
1093 dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp;
1094 priv_interp.env.init (privDictStr);
1096 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
1098 priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
1099 if (priv->localSubrs != &Null(CFF1Subrs) &&
1100 unlikely (!priv->localSubrs->sanitize (&sc)))
1101 { fini (); return; }
1106 cff1_top_dict_values_t *font = &topDict;
1107 PRIVDICTVAL *priv = &privateDicts[0];
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);
1114 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
1116 priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
1117 if (priv->localSubrs != &Null(CFF1Subrs) &&
1118 unlikely (!priv->localSubrs->sanitize (&sc)))
1119 { fini (); return; }
1125 sc.end_processing ();
1127 fontDicts.fini_deep ();
1128 privateDicts.fini_deep ();
1129 hb_blob_destroy (blob);
1133 bool is_valid () const { return blob != nullptr; }
1134 bool is_CID () const { return topDict.is_CID (); }
1136 bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; }
1138 unsigned int std_code_to_glyph (hb_codepoint_t code) const
1140 hb_codepoint_t sid = lookup_standard_encoding_for_sid (code);
1141 if (unlikely (sid == CFF_UNDEF_SID))
1144 if (charset != &Null(Charset))
1145 return charset->get_glyph (sid, num_glyphs);
1146 else if ((topDict.CharsetOffset == ISOAdobeCharset)
1147 && (code <= 228 /*zcaron*/)) return sid;
1153 hb_sanitize_context_t sc;
1156 const Charset *charset;
1157 const CFF1NameIndex *nameIndex;
1158 const CFF1TopDictIndex *topDictIndex;
1159 const CFF1StringIndex *stringIndex;
1160 const CFF1Subrs *globalSubrs;
1161 const CFF1CharStrings *charStrings;
1162 const CFF1FDArray *fdArray;
1163 const CFF1FDSelect *fdSelect;
1164 unsigned int fdCount;
1166 cff1_top_dict_values_t topDict;
1167 hb_vector_t<cff1_font_dict_values_t> fontDicts;
1168 hb_vector_t<PRIVDICTVAL> privateDicts;
1170 unsigned int num_glyphs;
1173 struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
1175 HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
1176 HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
1179 struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t>
1181 void init (hb_face_t *face)
1184 if (blob == nullptr) return;
1186 const OT::cff1 *cff = this->blob->as<OT::cff1> ();
1187 encoding = &Null(Encoding);
1190 if (unlikely (charset == &Null(Charset))) { fini (); return; }
1194 if (!is_predef_encoding ())
1196 encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
1197 if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
1202 bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
1204 hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
1206 if (encoding != &Null(Encoding))
1207 return encoding->get_code (glyph);
1210 hb_codepoint_t sid = glyph_to_sid (glyph);
1211 if (sid == 0) return 0;
1212 hb_codepoint_t code = 0;
1213 switch (topDict.EncodingOffset)
1215 case StandardEncoding:
1216 code = lookup_standard_encoding_for_code (sid);
1218 case ExpertEncoding:
1219 code = lookup_expert_encoding_for_code (sid);
1228 hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
1230 if (charset != &Null(Charset))
1231 return charset->get_sid (glyph);
1234 hb_codepoint_t sid = 0;
1235 switch (topDict.CharsetOffset)
1237 case ISOAdobeCharset:
1238 if (glyph <= 228 /*zcaron*/) sid = glyph;
1241 sid = lookup_expert_charset_for_sid (glyph);
1243 case ExpertSubsetCharset:
1244 sid = lookup_expert_subset_charset_for_sid (glyph);
1253 const Encoding *encoding;
1256 typedef accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> SUPER;
1259 bool subset (hb_subset_plan_t *plan) const
1261 hb_blob_t *cff_prime = nullptr;
1263 bool success = true;
1264 if (hb_subset_cff1 (plan, &cff_prime)) {
1265 success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime);
1266 hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
1267 success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
1268 hb_blob_destroy (head_blob);
1272 hb_blob_destroy (cff_prime);
1278 HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
1279 HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid);
1280 HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph);
1281 HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph);
1282 HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code);
1285 FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */
1286 OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
1287 HBUINT8 offSize; /* offset size (unused?) */
1290 DEFINE_SIZE_STATIC (4);
1293 struct cff1_accelerator_t : cff1::accelerator_t {};
1294 } /* namespace OT */
1296 #endif /* HB_OT_CFF1_TABLE_HH */