From c05458ec7f11753be95d1c3cdd7c377d07d7b981 Mon Sep 17 00:00:00 2001 From: ariza Date: Mon, 2 Mar 2020 16:51:19 -0800 Subject: [PATCH] update cff & cff2 subsetters --- src/hb-ot-cff-common.hh | 199 +++--- src/hb-ot-cff1-table.hh | 58 +- src/hb-ot-cff2-table.hh | 9 +- src/hb-subset-cff-common.hh | 57 +- src/hb-subset-cff1.cc | 574 ++++++------------ src/hb-subset-cff2.cc | 336 +++------- .../api/fonts/AdobeVFPrototype.ac.nohints.otf | Bin 6220 -> 4212 bytes .../AdobeVFPrototype.ac.nosubrs.nohints.otf | Bin 6100 -> 4092 bytes test/api/fonts/cff1_expert.2D,F6E9,FB00.otf | Bin 3096 -> 1412 bytes 9 files changed, 458 insertions(+), 775 deletions(-) diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh index 840ba6fda..a79ad9ff5 100644 --- a/src/hb-ot-cff-common.hh +++ b/src/hb-ot-cff-common.hh @@ -38,6 +38,9 @@ using namespace OT; #define CFF_UNDEF_CODE 0xFFFFFFFF +using objidx_t = hb_serialize_context_t::objidx_t; +using whence_t = hb_serialize_context_t::whence_t; + /* utility macro */ template static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) @@ -89,6 +92,16 @@ struct CFFIndex unsigned int offset_array_size () const { return calculate_offset_array_size (offSize, count); } + CFFIndex *copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + unsigned int size = get_size (); + CFFIndex *out = c->allocate_size (size); + if (likely (out)) + memcpy (out, this, size); + return_trace (out); + } + static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count, unsigned int dataSize) { @@ -163,6 +176,72 @@ struct CFFIndex return result; } + template + bool serialize (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + if (it.len () == 0) + { + COUNT *dest = c->allocate_min (); + if (unlikely (dest == nullptr)) return_trace (false); + *dest = 0; + } + else + { + serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; })); + + it | hb_apply ([&] (const byte_str_t &_) { _.copy (c); }); + } + return_trace (true); + } + + bool serialize (hb_serialize_context_t *c, + const byte_str_array_t &byteArray) + { return serialize (c, + hb_iter (byteArray)); } + + bool serialize (hb_serialize_context_t *c, + const str_buff_vec_t &buffArray) + { + auto it = + + hb_iter (buffArray) + | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); }) + ; + return serialize (c, it); + } + + template + bool serialize_header (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + + unsigned total = + it | hb_reduce (hb_add, 0); + unsigned off_size = calcOffSize (total); + + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count = it.len (); + this->offSize = off_size; + if (unlikely (!c->allocate_size (off_size * (it.len () + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + + it + | hb_apply ([&] (unsigned _) + { + CFFIndex::set_offset_at (i++, offset); + offset += _; + }) + ; + CFFIndex::set_offset_at (i, offset); + + return_trace (true); + } + void set_offset_at (unsigned int index, unsigned int offset) { HBUINT8 *p = offsets + offSize * index + offSize; @@ -316,15 +395,15 @@ struct CFFIndexOf : CFFIndex /* Top Dict, Font Dict, Private Dict */ struct Dict : UnsizedByteStr { - template + template bool serialize (hb_serialize_context_t *c, const DICTVAL &dictval, OP_SERIALIZER& opszr, - PARAM& param) + Ts&&... ds) { TRACE_SERIALIZE (this); for (unsigned int i = 0; i < dictval.get_count (); i++) - if (unlikely (!opszr.serialize (c, dictval[i], param))) + if (unlikely (!opszr.serialize (c, dictval[i], hb_forward (ds)...))) return_trace (false); return_trace (true); @@ -386,6 +465,21 @@ struct Dict : UnsizedByteStr static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, unsigned value) { return serialize_int2_op (c, op, value); } + + template + static bool serialize_link_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence) + { + T &ofs = *(T *) (c->head + OpCode_Size (int_op)); + if (unlikely (!serialize_int_op (c, op, 0, int_op))) return false; + c->add_link (ofs, link, nullptr, whence); + return true; + } + + static bool serialize_link4_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head) + { return serialize_link_op (c, op, link, whence); } + + static bool serialize_link2_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head) + { return serialize_link_op (c, op, link, whence); } }; struct TopDict : Dict {}; @@ -394,105 +488,40 @@ struct PrivateDict : Dict {}; struct table_info_t { - void init () { offSize = offset = size = 0; } + void init () { offSize = offset = size = 0; link = 0; } unsigned int offset; unsigned int size; unsigned int offSize; + objidx_t link; }; template struct FDArray : CFFIndexOf { - /* used by CFF1 */ - template + template bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const hb_vector_t &fontDicts, + Iterator it, OP_SERIALIZER& opszr) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count = fontDicts.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (fontDicts.length + 1)))) - return_trace (false); - /* serialize font dict offsets */ - unsigned int offset = 1; - unsigned int fid = 0; - for (; fid < fontDicts.length; fid++) - { - CFFIndexOf::set_offset_at (fid, offset); - offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr); - } - CFFIndexOf::set_offset_at (fid, offset); - - /* serialize font dicts */ - for (unsigned int i = 0; i < fontDicts.length; i++) + /* serialize INDEX data */ + hb_vector_t sizes; + c->push (); + + it + | hb_map ([&] (const hb_pair_t &_) { FontDict *dict = c->start_embed (); - if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i]))) - return_trace (false); - } - return_trace (true); - } + dict->serialize (c, _.first, opszr, _.second); + return c->head - (const char*)dict; + }) + | hb_sink (sizes) + ; + c->pop_pack (false); - /* used by CFF2 */ - template - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const hb_vector_t &fontDicts, - unsigned int fdCount, - const hb_inc_bimap_t &fdmap, - OP_SERIALIZER& opszr, - const hb_vector_t &privateInfos) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count = fdCount; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (fdCount + 1)))) - return_trace (false); - - /* serialize font dict offsets */ - unsigned int offset = 1; - unsigned int fid = 0; - for (unsigned i = 0; i < fontDicts.length; i++) - if (fdmap.has (i)) - { - if (unlikely (fid >= fdCount)) return_trace (false); - CFFIndexOf::set_offset_at (fid++, offset); - offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); - } - CFFIndexOf::set_offset_at (fid, offset); - - /* serialize font dicts */ - for (unsigned int i = 0; i < fontDicts.length; i++) - if (fdmap.has (i)) - { - FontDict *dict = c->start_embed (); - if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) - return_trace (false); - } - return_trace (true); - } - - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, - const hb_vector_t &fontDicts, - unsigned int fdCount, - const hb_inc_bimap_t &fdmap, - OP_SERIALIZER& opszr) - { - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < fontDicts.len; i++) - if (fdmap.has (i)) - dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); - - offSize_ = calcOffSize (dictsSize); - return CFFIndex::calculate_serialized_size (offSize_, fdCount, dictsSize); + /* serialize INDEX header */ + return_trace (CFFIndex::serialize_header (c, hb_iter (sizes))); } }; diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index 3070dbd55..9b8de95df 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -55,7 +55,6 @@ template struct CFF1IndexOf : CFFIndexOf {}; typedef CFFIndex CFF1Index; typedef CFF1Index CFF1CharStrings; -typedef FDArray CFF1FDArray; typedef Subrs CFF1Subrs; struct CFF1FDSelect : FDSelect {}; @@ -601,13 +600,13 @@ struct Charset struct CFF1StringIndex : CFF1Index { bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, - unsigned int offSize_, const hb_inc_bimap_t &sidmap) + const hb_inc_bimap_t &sidmap) { TRACE_SERIALIZE (this); if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0))) { if (unlikely (!c->extend_min (this->count))) - return_trace (false); + return_trace (false); count = 0; return_trace (true); } @@ -620,29 +619,13 @@ struct CFF1StringIndex : CFF1Index { hb_codepoint_t j = sidmap[i]; if (j != HB_MAP_VALUE_INVALID) - bytesArray[j] = strings[i]; + bytesArray[j] = strings[i]; } - bool result = CFF1Index::serialize (c, offSize_, bytesArray); + bool result = CFF1Index::serialize (c, bytesArray); bytesArray.fini (); return_trace (result); } - - /* in parallel to above */ - unsigned int calculate_serialized_size (unsigned int &offSize_ /*OUT*/, const hb_inc_bimap_t &sidmap) const - { - offSize_ = 0; - if ((count == 0) || (sidmap.get_population () == 0)) - return count.static_size; - - unsigned int dataSize = 0; - for (unsigned int i = 0; i < count; i++) - if (sidmap[i] != HB_MAP_VALUE_INVALID) - dataSize += length_at (i); - - offSize_ = calcOffSize(dataSize); - return CFF1Index::calculate_serialized_size (offSize_, sidmap.get_population (), dataSize); - } }; struct cff1_top_dict_interp_env_t : num_interp_env_t @@ -745,7 +728,7 @@ struct cff1_top_dict_values_t : top_dict_values_t unsigned int EncodingOffset; unsigned int CharsetOffset; unsigned int FDSelectOffset; - table_info_t privateDictInfo; + table_info_t privateDictInfo; }; struct cff1_top_dict_opset_t : top_dict_opset_t @@ -1004,6 +987,37 @@ typedef dict_interpreter_t cff1 typedef CFF1Index CFF1NameIndex; typedef CFF1IndexOf CFF1TopDictIndex; +struct cff1_font_dict_values_mod_t +{ + cff1_font_dict_values_mod_t() { init (); } + + void init () { init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID ); } + + void init (const cff1_font_dict_values_t *base_, + unsigned int fontName_) + { + base = base_; + fontName = fontName_; + privateDictInfo.init (); + } + + unsigned get_count () const { return base->get_count (); } + + const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } + + const cff1_font_dict_values_t *base; + table_info_t privateDictInfo; + unsigned int fontName; +}; + +struct CFF1FDArray : FDArray +{ + /* FDArray::serialize() requires this partial specialization to compile */ + template + bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) + { return FDArray::serialize (c, it, opszr); } +}; + } /* namespace CFF */ namespace OT { diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index b2e9af626..7d12aa3da 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -43,7 +43,6 @@ typedef CFFIndex CFF2Index; template struct CFF2IndexOf : CFFIndexOf {}; typedef CFF2Index CFF2CharStrings; -typedef FDArray CFF2FDArray; typedef Subrs CFF2Subrs; typedef FDSelect3_4 FDSelect4; @@ -404,6 +403,14 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t typedef dict_interpreter_t cff2_top_dict_interpreter_t; typedef dict_interpreter_t cff2_font_dict_interpreter_t; +struct CFF2FDArray : FDArray +{ + /* FDArray::serialize does not compile without this partial specialization */ + template + bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) + { return FDArray::serialize (c, it, opszr); } +}; + } /* namespace CFF */ namespace OT { diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index e9adb4278..44e352728 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -128,26 +128,23 @@ struct str_encoder_t bool error; }; -struct cff_sub_table_offsets_t { - cff_sub_table_offsets_t () : privateDictsOffset (0) +struct cff_sub_table_info_t { + cff_sub_table_info_t () + : fd_array_link (0), + char_strings_link (0), + private_dicts_offset (0) { - topDictInfo.init (); - FDSelectInfo.init (); - FDArrayInfo.init (); - charStringsInfo.init (); - globalSubrsInfo.init (); - localSubrsInfos.init (); + top_dict.init (); + fd_select.init (); + global_subrs.init (); } - ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); } - - table_info_t topDictInfo; - table_info_t FDSelectInfo; - table_info_t FDArrayInfo; - table_info_t charStringsInfo; - unsigned int privateDictsOffset; - table_info_t globalSubrsInfo; - hb_vector_t localSubrsInfos; + table_info_t top_dict; + table_info_t fd_select; + objidx_t fd_array_link; + objidx_t char_strings_link; + unsigned int private_dicts_offset; + table_info_t global_subrs; }; template @@ -155,20 +152,20 @@ struct cff_top_dict_op_serializer_t : op_serializer_t { bool serialize (hb_serialize_context_t *c, const OPSTR &opstr, - const cff_sub_table_offsets_t &offsets) const + const cff_sub_table_info_t &info) const { TRACE_SERIALIZE (this); switch (opstr.op) { case OpCode_CharStrings: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute)); case OpCode_FDArray: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute)); case OpCode_FDSelect: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute)); default: return_trace (copy_opstr (c, opstr)); @@ -202,16 +199,8 @@ struct cff_font_dict_op_serializer_t : op_serializer_t if (opstr.op == OpCode_Private) { /* serialize the private dict size & offset as 2-byte & 4-byte integers */ - if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) || - !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset))) - return_trace (false); - - /* serialize the opcode */ - HBUINT8 *p = c->allocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - *p = OpCode_Private; - - return_trace (true); + return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) && + Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute)); } else { @@ -238,7 +227,7 @@ struct cff_private_dict_op_serializer_t : op_serializer_t bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const unsigned int subrsOffset) const + objidx_t subrs_link) const { TRACE_SERIALIZE (this); @@ -246,10 +235,10 @@ struct cff_private_dict_op_serializer_t : op_serializer_t return true; if (opstr.op == OpCode_Subrs) { - if (desubroutinize || (subrsOffset == 0)) + if (desubroutinize || !subrs_link) return_trace (true); else - return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset)); + return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link)); } else return_trace (copy_opstr (c, opstr)); diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index b70825268..a39db08aa 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -64,22 +64,18 @@ struct remap_sid_t : hb_inc_bimap_t static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } }; -struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t +struct cff1_sub_table_info_t : cff_sub_table_info_t { - cff1_sub_table_offsets_t () - : cff_sub_table_offsets_t (), - nameIndexOffset (0), - encodingOffset (0) - { - stringIndexInfo.init (); - charsetInfo.init (); + cff1_sub_table_info_t () + : cff_sub_table_info_t (), + encoding_link (0), + charset_link (0) + { privateDictInfo.init (); } - unsigned int nameIndexOffset; - table_info_t stringIndexInfo; - unsigned int encodingOffset; - table_info_t charsetInfo; + objidx_t encoding_link; + objidx_t charset_link; table_info_t privateDictInfo; }; @@ -117,13 +113,13 @@ struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t struct top_dict_modifiers_t { - top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_, + top_dict_modifiers_t (const cff1_sub_table_info_t &info_, const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) - : offsets (offsets_), + : info (info_), nameSIDs (nameSIDs_) {} - const cff1_sub_table_offsets_t &offsets; + const cff1_sub_table_info_t &info; const unsigned int (&nameSIDs)[name_dict_values_t::ValCount]; }; @@ -139,22 +135,20 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_tallocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - *p = OpCode_Private; - } - break; + return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) && + Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute)); case OpCode_version: case OpCode_Notice: @@ -180,69 +174,20 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t::serialize (c, opstr, mod.offsets)); + return_trace (cff_top_dict_op_serializer_t::serialize (c, opstr, mod.info)); } return_trace (true); } - unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const - { - op_code_t op = opstr.op; - switch (op) - { - case OpCode_charset: - case OpCode_Encoding: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); - - case OpCode_Private: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); - - case OpCode_version: - case OpCode_Notice: - case OpCode_Copyright: - case OpCode_FullName: - case OpCode_FamilyName: - case OpCode_Weight: - case OpCode_PostScript: - case OpCode_BaseFontName: - case OpCode_FontName: - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op); - - case OpCode_ROS: - return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */; - - default: - return cff_top_dict_op_serializer_t::calculate_serialized_size (opstr); - } - } -}; - -struct font_dict_values_mod_t -{ - void init (const cff1_font_dict_values_t *base_, - unsigned int fontName_, - const table_info_t &privateDictInfo_) - { - base = base_; - fontName = fontName_; - privateDictInfo = privateDictInfo_; - } - - unsigned get_count () const { return base->get_count (); } - - const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } - - const cff1_font_dict_values_t *base; - table_info_t privateDictInfo; - unsigned int fontName; }; struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t { bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const font_dict_values_mod_t &mod) const + const cff1_font_dict_values_mod_t &mod) const { TRACE_SERIALIZE (this); @@ -252,14 +197,6 @@ struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); } - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - if (opstr.op == OpCode_FontName) - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName); - else - return SUPER::calculate_serialized_size (opstr); - } - private: typedef cff_font_dict_op_serializer_t SUPER; }; @@ -425,8 +362,7 @@ struct cff1_subr_subsetter_t : subr_subsetter_tnum_output_glyphs ()); } bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) @@ -609,7 +536,6 @@ struct cff_subset_plan { hb_codepoint_t old_glyph; if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false; - final_size = 0; num_glyphs = plan->num_output_glyphs (); orig_fdcount = acc.fdCount; drop_hints = plan->drop_hints; @@ -630,13 +556,6 @@ struct cff_subset_plan { subset_charset = gid_renum || !acc.is_predef_charset (); subset_encoding = !acc.is_CID() && !acc.is_predef_encoding (); - /* CFF header */ - final_size += OT::cff1::static_size; - - /* Name INDEX */ - offsets.nameIndexOffset = final_size; - final_size += acc.nameIndex->get_size (); - /* top dict INDEX */ { /* Add encoding/charset to a (copy of) top dict as necessary */ @@ -650,15 +569,6 @@ struct cff_subset_plan { if (need_to_add_set) topdict_mod.add_op (OpCode_charset); } - offsets.topDictInfo.offset = final_size; - cff1_top_dict_op_serializer_t topSzr; - unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr); - offsets.topDictInfo.offSize = calcOffSize(topDictSize); - if (unlikely (offsets.topDictInfo.offSize > 4)) - return false; - final_size += CFF1IndexOf::calculate_serialized_size - (offsets.topDictInfo.offSize, - &topdict_mod, 1, topdict_sizes, topSzr); } /* Determine re-mapping of font index as fdmap among other info */ @@ -668,7 +578,7 @@ struct cff_subset_plan { orig_fdcount, *acc.fdSelect, subset_fdcount, - offsets.FDSelectInfo.size, + info.fd_select.size, subset_fdselect_format, subset_fdselect_ranges, fdmap))) @@ -684,19 +594,12 @@ struct cff_subset_plan { return false; if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */ return false; - if (subset_charset) - offsets.charsetInfo.size = plan_subset_charset (acc, plan); + + if (subset_charset) plan_subset_charset (acc, plan); topdict_mod.reassignSIDs (sidmap); } - /* String INDEX */ - { - offsets.stringIndexInfo.offset = final_size; - offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap); - final_size += offsets.stringIndexInfo.size; - } - if (desubroutinize) { /* Flatten global & local subrs */ @@ -704,9 +607,6 @@ struct cff_subset_plan { flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; - - /* no global/local subroutines */ - offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0); } else { @@ -723,131 +623,49 @@ struct cff_subset_plan { if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) return false; - /* global subrs */ - unsigned int dataSize = subset_globalsubrs.total_size (); - offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); - if (unlikely (offsets.globalSubrsInfo.offSize > 4)) - return false; - offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); - /* local subrs */ - if (!offsets.localSubrsInfos.resize (orig_fdcount)) - return false; if (!subset_localsubrs.resize (orig_fdcount)) return false; for (unsigned int fd = 0; fd < orig_fdcount; fd++) { subset_localsubrs[fd].init (); - offsets.localSubrsInfos[fd].init (); if (fdmap.has (fd)) { if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) return false; - - unsigned int dataSize = subset_localsubrs[fd].total_size (); - if (dataSize > 0) - { - offsets.localSubrsInfos[fd].offset = final_size; - offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); - if (unlikely (offsets.localSubrsInfos[fd].offSize > 4)) - return false; - offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); - } } } } - /* global subrs */ - offsets.globalSubrsInfo.offset = final_size; - final_size += offsets.globalSubrsInfo.size; - /* Encoding */ - if (!subset_encoding) - offsets.encodingOffset = acc.topDict.EncodingOffset; - else - { - offsets.encodingOffset = final_size; - final_size += plan_subset_encoding (acc, plan); - } - - /* Charset */ - if (!subset_charset && acc.is_predef_charset ()) - offsets.charsetInfo.offset = acc.topDict.CharsetOffset; - else - offsets.charsetInfo.offset = final_size; - final_size += offsets.charsetInfo.size; - - /* FDSelect */ - if (acc.fdSelect != &Null(CFF1FDSelect)) - { - offsets.FDSelectInfo.offset = final_size; - final_size += offsets.FDSelectInfo.size; - } - - /* FDArray (FDIndex) */ - if (acc.fdArray != &Null(CFF1FDArray)) { - offsets.FDArrayInfo.offset = final_size; - cff1_font_dict_op_serializer_t fontSzr; - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < acc.fontDicts.length; i++) - if (fdmap.has (i)) - dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); - - offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); - if (unlikely (offsets.FDArrayInfo.offSize > 4)) - return false; - final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); - } - - /* CharStrings */ - { - offsets.charStringsInfo.offset = final_size; - unsigned int dataSize = subset_charstrings.total_size (); - offsets.charStringsInfo.offSize = calcOffSize (dataSize); - if (unlikely (offsets.charStringsInfo.offSize > 4)) - return false; - final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize); - } + if (subset_encoding) + plan_subset_encoding (acc, plan); /* private dicts & local subrs */ - offsets.privateDictInfo.offset = final_size; - for (unsigned int i = 0; i < orig_fdcount; i++) - { - if (fdmap.has (i)) - { - bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; - cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints); - unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); - table_info_t privInfo = { final_size, priv_size, 0 }; - font_dict_values_mod_t fontdict_mod; - if (!acc.is_CID ()) - fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo ); - else - fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo ); - fontdicts_mod.push (fontdict_mod); - final_size += privInfo.size; - - if (!plan->desubroutinize && has_localsubrs) - { - offsets.localSubrsInfos[i].offset = final_size; - final_size += offsets.localSubrsInfos[i].size; - } - } - } - if (!acc.is_CID ()) - offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; + fontdicts_mod.push (cff1_font_dict_values_mod_t ()); + else + { + + hb_iter (acc.fontDicts) + | hb_filter ([&] (const cff1_font_dict_values_t &_) + { return fdmap.has (&_ - &acc.fontDicts[0]); } ) + | hb_map ([&] (const cff1_font_dict_values_t &_) + { + cff1_font_dict_values_mod_t mod; + mod.init (&_, sidmap[_.fontName]); + return mod; + }) + | hb_sink (fontdicts_mod) + ; + } return ((subset_charstrings.length == plan->num_output_glyphs ()) && (fontdicts_mod.length == subset_fdcount)); } - unsigned int get_final_size () const { return final_size; } - - unsigned int final_size; hb_vector_t topdict_sizes; cff1_top_dict_values_mod_t topdict_mod; - cff1_sub_table_offsets_t offsets; + cff1_sub_table_info_t info; unsigned int num_glyphs; unsigned int orig_fdcount; @@ -862,7 +680,7 @@ struct cff_subset_plan { str_buff_vec_t subset_charstrings; str_buff_vec_t subset_globalsubrs; hb_vector_t subset_localsubrs; - hb_vector_t fontdicts_mod; + hb_vector_t fontdicts_mod; bool drop_hints; @@ -883,11 +701,119 @@ struct cff_subset_plan { bool desubroutinize; }; -static inline bool _write_cff1 (hb_serialize_context_t *c, - const cff_subset_plan &plan, - const OT::cff1::accelerator_subset_t &acc, - unsigned int num_glyphs) +static bool _serialize_cff1 (hb_serialize_context_t *c, + cff_subset_plan &plan, + const OT::cff1::accelerator_subset_t &acc, + unsigned int num_glyphs) { + /* private dicts & local subrs */ + for (int i = (int)acc.privateDicts.length; --i >= 0 ;) + { + if (plan.fdmap.has (i)) + { + objidx_t subrs_link = 0; + if (plan.subset_localsubrs[i].length > 0) + { + c->push (); + CFF1Subrs *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (c, plan.subset_localsubrs[i]))) return false; + subrs_link = c->pop_pack (); + } + + c->push (); + PrivateDict *pd = c->start_embed (); + if (unlikely (pd == nullptr)) return false; + bool result; + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ + result = pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link); + if (unlikely (!result)) return false; + unsigned fd = plan.fdmap[i]; + plan.fontdicts_mod[fd].privateDictInfo.size = c->length (); + plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack (); + } + } + + if (!acc.is_CID ()) + plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo; + + /* CharStrings */ + { + c->push (); + CFF1CharStrings *cs = c->start_embed (); + if (unlikely (cs == nullptr)) return false; + if (unlikely (!cs->serialize (c, plan.subset_charstrings))) return false; + plan.info.char_strings_link = c->pop_pack (); + } + + /* FDArray (FD Index) */ + if (acc.fdArray != &Null(CFF1FDArray)) + { + c->push (); + CFF1FDArray *fda = c->start_embed (); + if (unlikely (fda == nullptr)) return false; + cff1_font_dict_op_serializer_t fontSzr; + auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod)); + if (unlikely (!fda->serialize (c, it, fontSzr))) return false; + plan.info.fd_array_link = c->pop_pack (false); + } + + /* FDSelect */ + if (acc.fdSelect != &Null(CFF1FDSelect)) + { + c->push (); + if (unlikely (!hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, + plan.subset_fdselect_format, plan.info.fd_select.size, + plan.subset_fdselect_ranges))) return false; + plan.info.fd_select.link = c->pop_pack (); + } + + /* Charset */ + if (plan.subset_charset) + { + c->push (); + Charset *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (c, + plan.subset_charset_format, + plan.num_glyphs, + plan.subset_charset_ranges))) return false; + plan.info.charset_link = c->pop_pack (); + } + + /* Encoding */ + if (plan.subset_encoding) + { + Encoding *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + c->push (); + if (unlikely (!dest->serialize (c, + plan.subset_enc_format, + plan.subset_enc_num_codes, + plan.subset_enc_code_ranges, + plan.subset_enc_supp_codes))) return false; + plan.info.encoding_link = c->pop_pack (); + } + + /* global subrs */ + { + c->push (); + CFF1Subrs *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (c, plan.subset_globalsubrs))) return false; + c->pop_pack (); + } + + /* String INDEX */ + { + c->push (); + CFF1StringIndex *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (c, *acc.stringIndex, plan.sidmap))) return false; + c->pop_pack (); + } + OT::cff1 *cff = c->allocate_min (); if (unlikely (!cff)) return false; @@ -899,170 +825,29 @@ static inline bool _write_cff1 (hb_serialize_context_t *c, cff->offSize = 4; /* unused? */ /* name INDEX */ - { - assert (cff->nameIndex == (unsigned) (c->head - c->start)); - CFF1NameIndex *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, *acc.nameIndex))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX"); - return false; - } - } + if (unlikely (!(*acc.nameIndex).copy (c))) return false; /* top dict INDEX */ { - assert (plan.offsets.topDictInfo.offset == (unsigned) (c->head - c->start)); - CFF1IndexOf *dest = c->start_embed< CFF1IndexOf> (); - if (dest == nullptr) return false; + /* serialize singleton TopDict */ + c->push (); + TopDict *top = c->start_embed (); + if (top == nullptr) return false; cff1_top_dict_op_serializer_t topSzr; - top_dict_modifiers_t modifier (plan.offsets, plan.topDictModSIDs); - if (unlikely (!dest->serialize (c, plan.offsets.topDictInfo.offSize, - &plan.topdict_mod, 1, - plan.topdict_sizes, topSzr, modifier))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); + top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs); + if (unlikely (!top->serialize (c, plan.topdict_mod, topSzr, modifier))) return false; - } + unsigned top_size = c->length (); + c->pop_pack (false); + + /* serialize INDEX header for above */ + CFF1Index *dest = c->start_embed (); + if (dest == nullptr) return false; + return dest->serialize_header (c, hb_iter (hb_array_t (&top_size, 1))); } - - /* String INDEX */ - { - assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c->head - c->start)); - CFF1StringIndex *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX"); - return false; - } - } - - /* global subrs */ - { - assert (plan.offsets.globalSubrsInfo.offset != 0); - assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c->head - c->start)); - - CFF1Subrs *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); - return false; - } - } - - /* Encoding */ - if (plan.subset_encoding) - { - assert (plan.offsets.encodingOffset == (unsigned) (c->head - c->start)); - Encoding *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, - plan.subset_enc_format, - plan.subset_enc_num_codes, - plan.subset_enc_code_ranges, - plan.subset_enc_supp_codes))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding"); - return false; - } - } - - /* Charset */ - if (plan.subset_charset) - { - assert (plan.offsets.charsetInfo.offset == (unsigned) (c->head - c->start)); - Charset *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, - plan.subset_charset_format, - plan.num_glyphs, - plan.subset_charset_ranges))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset"); - return false; - } - } - - /* FDSelect */ - if (acc.fdSelect != &Null(CFF1FDSelect)) - { - assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c->head - c->start)); - - if (unlikely (!hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, - plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subset_fdselect_ranges))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect"); - return false; - } - } - - /* FDArray (FD Index) */ - if (acc.fdArray != &Null(CFF1FDArray)) - { - assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c->head - c->start)); - CFF1FDArray *fda = c->start_embed (); - if (unlikely (fda == nullptr)) return false; - cff1_font_dict_op_serializer_t fontSzr; - if (unlikely (!fda->serialize (c, plan.offsets.FDArrayInfo.offSize, - plan.fontdicts_mod, - fontSzr))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); - return false; - } - } - - /* CharStrings */ - { - assert (plan.offsets.charStringsInfo.offset == (unsigned) (c->head - c->start)); - CFF1CharStrings *cs = c->start_embed (); - if (unlikely (cs == nullptr)) return false; - if (unlikely (!cs->serialize (c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings"); - return false; - } - } - - /* private dicts & local subrs */ - assert (plan.offsets.privateDictInfo.offset == (unsigned) (c->head - c->start)); - for (unsigned int i = 0; i < acc.privateDicts.length; i++) - { - if (plan.fdmap.has (i)) - { - PrivateDict *pd = c->start_embed (); - if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size; - bool result; - cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); - /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0; - result = pd->serialize (c, acc.privateDicts[i], privSzr, subroffset); - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); - return false; - } - if (plan.offsets.localSubrsInfos[i].size > 0) - { - CFF1Subrs *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); - return false; - } - } - } - } - - return true; } -static inline bool +static bool _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, hb_subset_context_t *c) { @@ -1074,12 +859,7 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, return false; } - if (unlikely (!_write_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()))) { - DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff."); - return false; - } - - return true; + return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()); } /** diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 1cc94bbb3..bd7790dc5 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -38,43 +38,31 @@ using namespace CFF; -struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t +struct cff2_sub_table_info_t : cff_sub_table_info_t { - cff2_sub_table_offsets_t () - : cff_sub_table_offsets_t (), - varStoreOffset (0) + cff2_sub_table_info_t () + : cff_sub_table_info_t (), + var_store_link (0) {} - unsigned int varStoreOffset; + objidx_t var_store_link; }; struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> { bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const cff2_sub_table_offsets_t &offsets) const + const cff2_sub_table_info_t &info) const { TRACE_SERIALIZE (this); switch (opstr.op) { case OpCode_vstore: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link)); default: - return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets)); - } - } - - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - switch (opstr.op) - { - case OpCode_vstore: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr); + return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, info)); } } }; @@ -246,9 +234,9 @@ struct cff2_subr_subsetter_t : subr_subsetter_tcount; drop_hints = plan->drop_hints; desubroutinize = plan->desubroutinize; - /* CFF2 header */ - final_size += OT::cff2::static_size; - - /* top dict */ - { - cff2_top_dict_op_serializer_t topSzr; - offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr); - final_size += offsets.topDictInfo.size; - } - if (desubroutinize) { /* Flatten global & local subrs */ @@ -297,9 +272,6 @@ struct cff2_subset_plan { flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; - - /* no global/local subroutines */ - offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0); } else { @@ -316,115 +288,41 @@ struct cff2_subset_plan { if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) return false; - /* global subrs */ - unsigned int dataSize = subset_globalsubrs.total_size (); - offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); - offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); - /* local subrs */ - if (!offsets.localSubrsInfos.resize (orig_fdcount)) - return false; if (!subset_localsubrs.resize (orig_fdcount)) return false; for (unsigned int fd = 0; fd < orig_fdcount; fd++) { subset_localsubrs[fd].init (); - offsets.localSubrsInfos[fd].init (); if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) return false; - - unsigned int dataSize = subset_localsubrs[fd].total_size (); - if (dataSize > 0) - { - offsets.localSubrsInfos[fd].offset = final_size; - offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); - offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); - } } } - /* global subrs */ - offsets.globalSubrsInfo.offset = final_size; - final_size += offsets.globalSubrsInfo.size; - - /* variation store */ - if (acc.varStore != &Null(CFF2VariationStore)) - { - offsets.varStoreOffset = final_size; - final_size += acc.varStore->get_size (); - } - /* FDSelect */ if (acc.fdSelect != &Null(CFF2FDSelect)) { - offsets.FDSelectInfo.offset = final_size; if (unlikely (!hb_plan_subset_cff_fdselect (plan, orig_fdcount, *(const FDSelect *)acc.fdSelect, subset_fdcount, - offsets.FDSelectInfo.size, + subset_fdselect_size, subset_fdselect_format, subset_fdselect_ranges, fdmap))) return false; - - final_size += offsets.FDSelectInfo.size; } else fdmap.identity (1); - /* FDArray (FDIndex) */ - { - offsets.FDArrayInfo.offset = final_size; - cff_font_dict_op_serializer_t fontSzr; - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < acc.fontDicts.length; i++) - if (fdmap.has (i)) - dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); - - offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); - final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); - } - - /* CharStrings */ - { - offsets.charStringsInfo.offset = final_size; - unsigned int dataSize = subset_charstrings.total_size (); - offsets.charStringsInfo.offSize = calcOffSize (dataSize); - final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize); - } - - /* private dicts & local subrs */ - offsets.privateDictsOffset = final_size; - for (unsigned int i = 0; i < orig_fdcount; i++) - { - if (fdmap.has (i)) - { - bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; - cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints); - unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); - table_info_t privInfo = { final_size, priv_size, 0 }; - privateDictInfos.push (privInfo); - final_size += privInfo.size; - - if (!plan->desubroutinize && has_localsubrs) - { - offsets.localSubrsInfos[i].offset = final_size; - final_size += offsets.localSubrsInfos[i].size; - } - } - } - return true; } - unsigned int get_final_size () const { return final_size; } - - unsigned int final_size; - cff2_sub_table_offsets_t offsets; + cff2_sub_table_info_t info; unsigned int orig_fdcount; unsigned int subset_fdcount; + unsigned int subset_fdselect_size; unsigned int subset_fdselect_format; hb_vector_t subset_fdselect_ranges; @@ -433,20 +331,94 @@ struct cff2_subset_plan { str_buff_vec_t subset_charstrings; str_buff_vec_t subset_globalsubrs; hb_vector_t subset_localsubrs; - hb_vector_t privateDictInfos; bool drop_hints; bool desubroutinize; }; -static inline bool _write_cff2 (hb_serialize_context_t *c, - const cff2_subset_plan &plan, - const OT::cff2::accelerator_subset_t &acc, - unsigned int num_glyphs) +static bool _serialize_cff2 (hb_serialize_context_t *c, + cff2_subset_plan &plan, + const OT::cff2::accelerator_subset_t &acc, + unsigned int num_glyphs) { + /* private dicts & local subrs */ + hb_vector_t private_dict_infos; + private_dict_infos.resize (plan.subset_fdcount); + + for (int i = (int)acc.privateDicts.length; --i >= 0 ;) + { + if (plan.fdmap.has (i)) + { + objidx_t subrs_link = 0; + + if (plan.subset_localsubrs[i].length > 0) + { + c->push (); + CFF2Subrs *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (c, plan.subset_localsubrs[i]))) return false; + subrs_link = c->pop_pack (); + } + c->push (); + PrivateDict *pd = c->start_embed (); + if (unlikely (pd == nullptr)) return false; + bool result; + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + result = pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link); + if (unlikely (!result)) return false; + unsigned fd = plan.fdmap[i]; + private_dict_infos[fd].size = c->length (); + private_dict_infos[fd].link = c->pop_pack (); + } + } + + /* CharStrings */ + { + c->push (); + CFF2CharStrings *cs = c->start_embed (); + if (unlikely (cs == nullptr)) return false; + if (unlikely (!cs->serialize (c, plan.subset_charstrings))) return false; + plan.info.char_strings_link = c->pop_pack (); + } + + /* FDSelect */ + if (acc.fdSelect != &Null(CFF2FDSelect)) + { + c->push (); + if (unlikely (!hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, plan.orig_fdcount, + plan.subset_fdselect_format, plan.subset_fdselect_size, + plan.subset_fdselect_ranges))) return false; + plan.info.fd_select.link = c->pop_pack (); + } + + /* FDArray (FD Index) */ + { + c->push (); + CFF2FDArray *fda = c->start_embed (); + if (unlikely (fda == nullptr)) return false; + cff_font_dict_op_serializer_t fontSzr; + auto it = + + hb_zip (+ hb_iter (acc.fontDicts) + | hb_filter ([&] (const cff2_font_dict_values_t &_) + { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }), + hb_iter (private_dict_infos)) + ; + if (unlikely (!fda->serialize (c, it, fontSzr))) return false; + plan.info.fd_array_link = c->pop_pack (); + } + + /* variation store */ + if (acc.varStore != &Null(CFF2VariationStore)) + { + c->push (); + CFF2VariationStore *dest = c->start_embed (); + if (unlikely (dest == nullptr)) return false; + if (unlikely (!dest->serialize (c, acc.varStore))) return false; + plan.info.var_store_link = c->pop_pack (); + } + OT::cff2 *cff2 = c->allocate_min (); - if (unlikely (!cff2)) - return false; + if (unlikely (!cff2)) return false; /* header */ cff2->version.major = 0x02; @@ -455,135 +427,28 @@ static inline bool _write_cff2 (hb_serialize_context_t *c, /* top dict */ { - assert (cff2->topDict == (unsigned) (c->head - c->start)); - cff2->topDictSize = plan.offsets.topDictInfo.size; TopDict &dict = cff2 + cff2->topDict; cff2_top_dict_op_serializer_t topSzr; - if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.offsets))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict"); - return false; - } + if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false; + cff2->topDictSize = c->head - (const char *)&dict; } /* global subrs */ { - assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c->head - c->start)); CFF2Subrs *dest = c->start_embed (); if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); - return false; - } + return dest->serialize (c, plan.subset_globalsubrs); } - - /* variation store */ - if (acc.varStore != &Null(CFF2VariationStore)) - { - assert (plan.offsets.varStoreOffset == (unsigned) (c->head - c->start)); - CFF2VariationStore *dest = c->start_embed (); - if (unlikely (!dest->serialize (c, acc.varStore))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store"); - return false; - } - } - - /* FDSelect */ - if (acc.fdSelect != &Null(CFF2FDSelect)) - { - assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c->head - c->start)); - - if (unlikely (!hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count, - plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subset_fdselect_ranges))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect"); - return false; - } - } - - /* FDArray (FD Index) */ - { - assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c->head - c->start)); - CFF2FDArray *fda = c->start_embed (); - if (unlikely (fda == nullptr)) return false; - cff_font_dict_op_serializer_t fontSzr; - if (unlikely (!fda->serialize (c, plan.offsets.FDArrayInfo.offSize, - acc.fontDicts, plan.subset_fdcount, plan.fdmap, - fontSzr, plan.privateDictInfos))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray"); - return false; - } - } - - /* CharStrings */ - { - assert (plan.offsets.charStringsInfo.offset == (unsigned) (c->head - c->start)); - CFF2CharStrings *cs = c->start_embed (); - if (unlikely (cs == nullptr)) return false; - if (unlikely (!cs->serialize (c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings"); - return false; - } - } - - /* private dicts & local subrs */ - assert (plan.offsets.privateDictsOffset == (unsigned) (c->head - c->start)); - for (unsigned int i = 0; i < acc.privateDicts.length; i++) - { - if (plan.fdmap.has (i)) - { - PrivateDict *pd = c->start_embed (); - if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size; - bool result; - cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); - /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0; - result = pd->serialize (c, acc.privateDicts[i], privSzr, subroffset); - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); - return false; - } - if (plan.offsets.localSubrsInfos[i].size > 0) - { - CFF2Subrs *dest = c->start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); - return false; - } - } - } - } - - return true; } -static inline bool +static bool _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, hb_subset_context_t *c) { cff2_subset_plan cff2_plan; - if (unlikely (!cff2_plan.create (acc, c->plan))) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan."); - return false; - } - - if (unlikely (!_write_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ()))) { - DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2."); - return false; - } - - return true; + if (unlikely (!cff2_plan.create (acc, c->plan))) return false; + return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ()); } /** @@ -606,5 +471,4 @@ hb_subset_cff2 (hb_subset_context_t *c) return result; } - #endif diff --git a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf index 89e1973191f08f028b4e51df050e361c3e529984..19b78973be4ce0792b5fe94f9d6eb22ef25c5a73 100644 GIT binary patch delta 603 zcmYk&ze`(D6bJC{x$h-;?-}EJ{&+8 zDB^55OACTH>84fiA7}>$2OY$vba2jKp+mR!#-7qH_kK9v!##(4mj993@)g~wCZE#J zY9*~utA6Ou9t>a20?s)QSzj)#RDNBc0JzftQXqX2zFcN9YaEZ|KGoWz$3wADd806H z!}{&$rcOS!@A9sl=VMae;) zHl^MGm)?rwDA4VP=(&xs=;3_{66mI8ag!ckiCyIIRqUY~N8)CT#7Zb)9wU6{5AdE};E#TSJul6RzQg1XH$1?5R8Yno zCiz=id*(5o;}sV0Qdh@CQ@S><{RWGeL<#TM^?G^7E%THcHikM~&{zX98{SyBK1 delta 2494 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 literal 3096 zcmbVOU1%It6h3!mcau%FNn315A(jiZf7;A$wn-sP!KP`0p&=WyY3mPKC%co~CE1yE zX11FY!GeOeMNp9DMW`=Aeel^wqfnnpKv1ktRS;=k6cKAB*!Z2fv)%1df7)5@z31ni zbI;FrFPoW}$xximkxm;&$HwGSD|tag9}tO4nQSus!fz`d5orsMy^<@Nl|MFqUjTm% z{JElK=DV(HSHKT|KTw1~|L*RuMEV5yCyHf%5i35uf~liyE>n{u7LX{%6OFkRN9dc|ARE8Z5p z;(P+c1^sYBe;lzt-Hn;V#$Gzi?8(hMk8Pre5K-%!AJaxUrJTx=Cr#q7{0JD+r1=|JPkoKv-Zw`6(7 zs8d;TONF8@)2aT{KAzLTJn(NP>?!(w1t(BMC zT4e2z#kYSrdpZ%nnCM*XxY49)pertkKxHCkV9Q0rgE zw?&l=g!mG{%(&){{q}_eesAAWgMF<*%tM{1U%&ecGvUWEG=D8Ta^zfzdc>|EUaoC7 zc(qTXHgJm8X%}q`=}6O_DDKOlP#&W#WOE#mIDC9bZ-lgwEkj9Z_uUwPDpprKtRE196M>bUdgeg z+Ff+~oMWGn{YJ{@PYn&1&3Vi5=d48w8wQO7gM&l+ALxueCW&&Vs2@WD5Or<<)ClFt zp;@v(XK9H%@#+v3?Er@^|^OkfqBRr zocX97E(N)A$2j5>;JAOPUs+HJ3+i+m=O%HQ8=R?Zm}cx$Vac(TVCy00N5R_^PUFr> zbke~5Oz8FhW6%e(D~MnQ`KX#TFvk_0LyWbcZk(;!v49oWL;Q?Z#wq8*73SRPmC53k zOn}b>{uv()&lC4~;9Jm&CB_R6*%aCR=hmY!fiDyO7~iv)InKtNVg!t#w$Eba&K$&g ze|0?M!d<99%Y9%xFJR@a70|s5>?c|xX=L(GHOj*azZmR!7WJtkMBNm=p?s4^fNy?H zvbe_*cZzv%!Mkt@)C@YB0mf#aJq7JFej|7bW}rJ3*k&M+G>To5zyMo}2Q>TT$Qk96 z^gPz%(C{9vwuPt~Xyn^hL8OdB#;w9@3HPOfN-#e2LH=1#T-}H7ump~j*Sf72pdttF za~L^z<^I{Icok~_=Wv{iOc!x*E$i=0<7Tl9N6EQxZ`C`*`T|blH`IkkzOMzymLTI- zlhMk!t-k^s(SIS|cqGhZgPc6rs#|h4h{!?T)SFa7T#QA|V+4aS!V#+%gz@?yX#w`U Xk1MDAj`Keb{zrpveHD-B1HQijZ@D^w