diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index 8ec319022..5b3477e34 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -562,8 +562,6 @@ struct ArgStack : Stack /* an operator prefixed by its operands in a byte string */ struct OpStr { - inline void init (void) {} - OpCode op; ByteStr str; }; diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index 1badbaaf7..f33ec9a42 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -97,21 +97,22 @@ struct DictValues hb_vector_t values; }; -struct TopDictValues : DictValues +template +struct TopDictValues : DictValues { inline void init (void) { - DictValues::init (); + DictValues::init (); charStringsOffset = 0; FDArrayOffset = 0; } inline void fini (void) { - DictValues::fini (); + DictValues::fini (); } - inline unsigned int calculate_serialized_op_size (const OpStr& opstr) const + inline unsigned int calculate_serialized_op_size (const OPSTR& opstr) const { switch (opstr.op) { @@ -174,9 +175,10 @@ struct DictOpSet : OpSet } }; +template struct TopDictOpSet : DictOpSet { - static inline bool process_op (OpCode op, InterpEnv& env, TopDictValues& dictval) + static inline bool process_op (OpCode op, InterpEnv& env, TopDictValues & dictval) { switch (op) { case OpCode_CharStrings: diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh index f948f5dfd..8b6b6b26b 100644 --- a/src/hb-ot-cff-common.hh +++ b/src/hb-ot-cff-common.hh @@ -35,6 +35,8 @@ namespace CFF { using namespace OT; +#define CFF_UNDEF_CODE 0xFFFFFFFF + /* utility macro */ template static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset) @@ -291,10 +293,8 @@ struct Dict : UnsizedByteStr } template - inline static bool serialize_offset_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp) + inline static bool serialize_int_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp) { - if (value == 0) - return true; // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation if (/*unlikely*/ (!serialize_int (c, intOp, value))) return false; @@ -313,11 +313,23 @@ struct Dict : UnsizedByteStr return_trace (true); } + inline static bool serialize_uint4_op (hb_serialize_context_t *c, OpCode op, int value) + { return serialize_int_op (c, op, value, OpCode_longintdict); } + + inline static bool serialize_uint2_op (hb_serialize_context_t *c, OpCode op, int value) + { return serialize_int_op (c, op, value, OpCode_shortint); } + inline static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value) - { return serialize_offset_op (c, op, value, OpCode_longintdict); } + { + if (value == 0) return true; + return serialize_uint4_op (c, op, value); + } inline static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value) - { return serialize_offset_op (c, op, value, OpCode_shortint); } + { + if (value == 0) return true; + return serialize_uint2_op (c, op, value); + } }; struct TopDict : Dict {}; @@ -333,9 +345,9 @@ struct TableInfo unsigned int offSize; }; -/* font dict index remap table from fullset FDArray to subset FDArray. - * set to HB_SET_VALUE_INVALID if excluded from subset */ -struct FDMap : hb_vector_t +/* used to remap font index or SID from fullset to subset. + * set to CFF_UNDEF_CODE if excluded from subset */ +struct Remap : hb_vector_t { inline void init (void) { hb_vector_t::init (); } @@ -343,16 +355,26 @@ struct FDMap : hb_vector_t inline void fini (void) { hb_vector_t::fini (); } + inline bool reset (unsigned int count) + { + if (unlikely (!hb_vector_t::resize (count))) + return false; + for (unsigned int i = 0; i < len; i++) + (*this)[i] = CFF_UNDEF_CODE; + count = 0; + return true; + } + inline bool fullset (void) const { for (unsigned int i = 0; i < len; i++) - if (hb_vector_t::operator[] (i) == HB_SET_VALUE_INVALID) + if (hb_vector_t::operator[] (i) == CFF_UNDEF_CODE) return false; return true; } - inline bool excludes (hb_codepoint_t fd) const - { return (fd < len) && ((*this)[fd] == HB_SET_VALUE_INVALID); } + inline bool excludes (hb_codepoint_t id) const + { return (id < len) && ((*this)[id] == CFF_UNDEF_CODE); } inline hb_codepoint_t operator[] (hb_codepoint_t i) const { @@ -367,17 +389,65 @@ struct FDMap : hb_vector_t assert (i < len); return hb_vector_t::operator[] (i); } + + inline unsigned int add (unsigned int i) + { + if ((*this)[i] == CFF_UNDEF_CODE) + (*this)[i] = count++; + return (*this)[i]; + } + + inline hb_codepoint_t get_count (void) const + { return count; } + + protected: + hb_codepoint_t count; }; template struct FDArray : CFFIndexOf { + /* used by CFF1 */ + template + inline bool serialize (hb_serialize_context_t *c, + unsigned int offSize_, + const hb_vector_t &fontDicts, + OP_SERIALIZER& opszr) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count.set (fontDicts.len); + this->offSize.set (offSize_); + if (!unlikely (c->allocate_size (offSize_ * (fontDicts.len + 1)))) + return_trace (false); + + /* serialize font dict offsets */ + unsigned int offset = 1; + unsigned int fid = 0; + for (; fid < fontDicts.len; 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.len; i++) + { + FontDict *dict = c->start_embed (); + if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i]))) + return_trace (false); + } + return_trace (true); + } + + /* used by CFF2 */ template inline bool serialize (hb_serialize_context_t *c, unsigned int offSize_, const hb_vector_t &fontDicts, unsigned int fdCount, - const FDMap &fdmap, + const Remap &fdmap, OP_SERIALIZER& opszr, const hb_vector_t &privateInfos) { @@ -415,7 +485,7 @@ struct FDArray : CFFIndexOf inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, const hb_vector_t &fontDicts, unsigned int fdCount, - const FDMap &fdmap, + const Remap &fdmap, OP_SERIALIZER& opszr) { unsigned int dictsSize = 0; diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index d00892b2a..c7ff0c960 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -38,7 +38,7 @@ namespace CFF { */ #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') -#define CFF_UNDEF_CODE 0xFFFFFFFF +#define CFF_UNDEF_SID CFF_UNDEF_CODE enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; @@ -529,13 +529,132 @@ struct Charset { DEFINE_SIZE_MIN (1); }; -struct CFF1TopDictValues : TopDictValues +struct CFF1StringIndex : CFF1Index +{ + inline bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, unsigned int offSize_, const Remap &sidmap) + { + TRACE_SERIALIZE (this); + if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) + { + if (!unlikely (c->extend_min (*this))) + return_trace (false); + count.set (0); + return_trace (true); + } + + hb_vector_t bytesArray; + bytesArray.init (); + if (!bytesArray.resize (sidmap.get_count ())) + return_trace (false); + for (unsigned int i = 0; i < strings.count; i++) + { + hb_codepoint_t j = sidmap[i]; + if (j != CFF_UNDEF_CODE) + bytesArray[j] = strings[i]; + } + + bool result = CFF1Index::serialize (c, offSize_, bytesArray); + bytesArray.fini (); + return_trace (result); + } + + /* in parallel to above */ + inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const Remap &sidmap) const + { + offSize = 0; + if ((count == 0) || (sidmap.get_count () == 0)) + return count.static_size; + + unsigned int dataSize = 0; + for (unsigned int i = 0; i < count; i++) + if (sidmap[i] != CFF_UNDEF_CODE) + dataSize += length_at (i); + + offSize = calcOffSize(dataSize); + return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize); + } +}; + +struct CFF1TopDictInterpEnv : NumInterpEnv +{ + inline CFF1TopDictInterpEnv (void) + : NumInterpEnv(), prev_offset(0), last_offset(0) {} + + unsigned int prev_offset; + unsigned int last_offset; +}; + +enum NameDictValIndex +{ + version, + notice, + copyright, + fullName, + familyName, + weight, + postscript, + fontName, + baseFontName, + registry, + ordering, + + NameDictValCount +}; + +struct NameDictValues +{ + inline void init (void) + { + for (unsigned int i = 0; i < NameDictValCount; i++) + values[i] = CFF_UNDEF_SID; + } + + inline unsigned int& operator[] (unsigned int i) + { assert (i < NameDictValCount); return values[i]; } + + inline unsigned int operator[] (unsigned int i) const + { assert (i < NameDictValCount); return values[i]; } + + static inline enum NameDictValIndex name_op_to_index (OpCode op) + { + switch (op) { + case OpCode_version: + return NameDictValIndex::version; + case OpCode_Notice: + return NameDictValIndex::notice; + case OpCode_Copyright: + return NameDictValIndex::copyright; + case OpCode_FullName: + return NameDictValIndex::fullName; + case OpCode_FamilyName: + return NameDictValIndex::familyName; + case OpCode_Weight: + return NameDictValIndex::weight; + case OpCode_PostScript: + return NameDictValIndex::postscript; + case OpCode_FontName: + return NameDictValIndex::fontName; + default: + assert (0); + } + } + + unsigned int values[NameDictValCount]; +}; + +struct CFF1TopDictVal : OpStr +{ + unsigned int last_arg_offset; +}; + +struct CFF1TopDictValues : TopDictValues { inline void init (void) { TopDictValues::init (); - ros[0] = ros[1] = ros[2] = 0; + nameSIDs.init (); + ros_supplement = 0; cidCount = 8720; EncodingOffset = 0; CharsetOffset = 0; @@ -549,73 +668,26 @@ struct CFF1TopDictValues : TopDictValues } inline bool is_CID (void) const - { return ros[0] != 0; } + { return nameSIDs[NameDictValIndex::registry] != CFF_UNDEF_SID; } - inline unsigned int calculate_serialized_size (void) const - { - unsigned int size = 0; - for (unsigned int i = 0; i < getNumValues (); i++) - { - OpCode op = getValue (i).op; - switch (op) - { - case OpCode_FDSelect: - size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); - break; - default: - size += TopDictValues::calculate_serialized_op_size (getValue (i)); - break; - } - } - return size; - } + NameDictValues nameSIDs; + unsigned int ros_supplement_offset; + unsigned int ros_supplement; + unsigned int cidCount; - unsigned int ros[3]; /* registry, ordering, supplement */ - unsigned int cidCount; - - unsigned int EncodingOffset; - unsigned int CharsetOffset; - unsigned int FDSelectOffset; - TableInfo privateDictInfo; + unsigned int EncodingOffset; + unsigned int CharsetOffset; + unsigned int FDSelectOffset; + TableInfo privateDictInfo; }; -/* a copy of a parsed out CFF1TopDictValues augmented with additional operators */ -struct CFF1TopDictValuesMod : CFF1TopDictValues +struct CFF1TopDictOpSet : TopDictOpSet { - inline void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues)) + static inline bool process_op (OpCode op, CFF1TopDictInterpEnv& env, CFF1TopDictValues& dictval) { - SUPER::init (); - base = base_; - } + CFF1TopDictVal val; + val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ - inline void fini (void) - { - SUPER::fini (); - } - - inline unsigned getNumValues (void) const - { - return base->getNumValues () + SUPER::getNumValues (); - } - inline const OpStr &getValue (unsigned int i) const - { - if (i < base->getNumValues ()) - return (*base)[i]; - else - return SUPER::values[i - base->getNumValues ()]; - } - inline const OpStr &operator [] (unsigned int i) const { return getValue (i); } - - protected: - typedef CFF1TopDictValues SUPER; - const CFF1TopDictValues *base; -}; - -struct CFF1TopDictOpSet : TopDictOpSet -{ - static inline bool process_op (OpCode op, NumInterpEnv& env, CFF1TopDictValues& dictval) - { - switch (op) { case OpCode_version: case OpCode_Notice: @@ -623,6 +695,12 @@ struct CFF1TopDictOpSet : TopDictOpSet case OpCode_FullName: case OpCode_FamilyName: case OpCode_Weight: + case OpCode_PostScript: + case OpCode_BaseFontName: + if (unlikely (!env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValues::name_op_to_index (op)]))) + return false; + env.clear_args (); + break; case OpCode_isFixedPitch: case OpCode_ItalicAngle: case OpCode_UnderlinePosition: @@ -632,8 +710,6 @@ struct CFF1TopDictOpSet : TopDictOpSet case OpCode_UniqueID: case OpCode_StrokeWidth: case OpCode_SyntheticBase: - case OpCode_PostScript: - case OpCode_BaseFontName: case OpCode_CIDFontVersion: case OpCode_CIDFontRevision: case OpCode_CIDFontType: @@ -651,9 +727,9 @@ struct CFF1TopDictOpSet : TopDictOpSet break; case OpCode_ROS: - if (unlikely (!env.argStack.check_pop_uint (dictval.ros[2]) || - !env.argStack.check_pop_uint (dictval.ros[1]) || - !env.argStack.check_pop_uint (dictval.ros[0]))) + if (unlikely (!env.argStack.check_pop_uint (dictval.ros_supplement) || + !env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValIndex::ordering]) || + !env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValIndex::registry]))) return false; env.clear_args (); break; @@ -685,6 +761,7 @@ struct CFF1TopDictOpSet : TopDictOpSet break; default: + env.last_offset = env.substr.offset; if (unlikely (!TopDictOpSet::process_op (op, env, dictval))) return false; /* Record this operand below if stack is empty, otherwise done */ @@ -692,7 +769,7 @@ struct CFF1TopDictOpSet : TopDictOpSet break; } - dictval.addOp (op, env.substr); + dictval.addOp (op, env.substr, val); return true; } }; @@ -703,6 +780,7 @@ struct CFF1FontDictValues : DictValues { DictValues::init (); privateDictInfo.init (); + fontName = CFF_UNDEF_SID; } inline void fini (void) @@ -710,7 +788,8 @@ struct CFF1FontDictValues : DictValues DictValues::fini (); } - TableInfo privateDictInfo; + TableInfo privateDictInfo; + unsigned int fontName; }; struct CFF1FontDictOpSet : DictOpSet @@ -719,6 +798,10 @@ struct CFF1FontDictOpSet : DictOpSet { switch (op) { case OpCode_FontName: + if (unlikely (!env.argStack.check_pop_uint (dictval.fontName))) + return false; + env.clear_args (); + break; case OpCode_FontMatrix: case OpCode_PaintType: env.clear_args (); @@ -869,13 +952,12 @@ struct CFF1PrivateDictOpSet_Subset : DictOpSet } }; -typedef DictInterpreter CFF1TopDict_Interpreter; +typedef DictInterpreter CFF1TopDict_Interpreter; typedef DictInterpreter CFF1FontDict_Interpreter; typedef DictInterpreter CFF1PrivateDict_Interpreter; typedef CFF1Index CFF1NameIndex; typedef CFF1IndexOf CFF1TopDictIndex; -typedef CFF1Index CFF1StringIndex; }; /* namespace CFF */ @@ -899,9 +981,7 @@ struct cff1 { inline void init (hb_face_t *face) { - topDicts.init (); - topDicts.resize (1); - topDicts[0].init (); + topDict.init (); fontDicts.init (); privateDicts.init (); @@ -929,19 +1009,19 @@ struct cff1 if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } CFF1TopDict_Interpreter top_interp; top_interp.env.init (topDictStr); - if (unlikely (!top_interp.interpret (topDicts[0]))) { fini (); return; } + if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } } encoding = &Null(Encoding); - charset = &StructAtOffsetOrNull (cff, topDicts[0].CharsetOffset); + charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset); if (unlikely (is_CID () && (charset == &Null(Charset)))) { fini (); return; } fdCount = 1; if (is_CID ()) { - fdArray = &StructAtOffsetOrNull (cff, topDicts[0].FDArrayOffset); - fdSelect = &StructAtOffsetOrNull (cff, topDicts[0].FDSelectOffset); + fdArray = &StructAtOffsetOrNull (cff, topDict.FDArrayOffset); + fdSelect = &StructAtOffsetOrNull (cff, topDict.FDSelectOffset); if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) { fini (); return; } @@ -954,7 +1034,7 @@ struct cff1 fdSelect = &Null(CFF1FDSelect); if (!is_predef_encoding ()) { - encoding = &StructAtOffsetOrNull (cff, topDicts[0].EncodingOffset); + encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset); if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc)) { fini (); return; } } @@ -968,7 +1048,7 @@ struct cff1 if ((globalSubrs != &Null (CFF1Subrs)) && !stringIndex->sanitize (&sc)) { fini (); return; } - charStrings = &StructAtOffsetOrNull (cff, topDicts[0].charStringsOffset); + charStrings = &StructAtOffsetOrNull (cff, topDict.charStringsOffset); if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) { fini (); return; } @@ -1008,7 +1088,7 @@ struct cff1 } else /* non-CID */ { - CFF1TopDictValues *font = &topDicts[0]; + CFF1TopDictValues *font = &topDict; PRIVDICTVAL *priv = &privateDicts[0]; const ByteStr privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); @@ -1027,8 +1107,7 @@ struct cff1 inline void fini (void) { sc.end_processing (); - topDicts[0].fini (); - topDicts.fini (); + topDict.fini (); fontDicts.fini (); privateDicts.fini (); hb_blob_destroy (blob); @@ -1036,10 +1115,10 @@ struct cff1 } inline bool is_valid (void) const { return blob != nullptr; } - inline bool is_CID (void) const { return topDicts[0].is_CID (); } + inline bool is_CID (void) const { return topDict.is_CID (); } - inline bool is_predef_encoding (void) const { return topDicts[0].EncodingOffset <= ExpertEncoding; } - inline bool is_predef_charset (void) const { return topDicts[0].CharsetOffset <= ExpertSubsetCharset; } + inline bool is_predef_encoding (void) const { return topDict.EncodingOffset <= ExpertEncoding; } + inline bool is_predef_charset (void) const { return topDict.CharsetOffset <= ExpertSubsetCharset; } inline hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const { @@ -1050,7 +1129,7 @@ struct cff1 hb_codepoint_t sid = glyph_to_sid (glyph); if (sid == 0) return 0; hb_codepoint_t code = 0; - switch (topDicts[0].EncodingOffset) + switch (topDict.EncodingOffset) { case StandardEncoding: code = lookup_standard_encoding (sid); @@ -1072,7 +1151,7 @@ struct cff1 else { hb_codepoint_t sid = 0; - switch (topDicts[0].CharsetOffset) + switch (topDict.CharsetOffset) { case ISOAdobeCharset: if (glyph <= 228 /*zcaron*/) sid = glyph; @@ -1116,7 +1195,7 @@ struct cff1 const CFF1FDSelect *fdSelect; unsigned int fdCount; - hb_vector_t topDicts; + CFF1TopDictValues topDict; hb_vector_t fontDicts; hb_vector_t privateDicts; diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index 19e480211..8e2ee3487 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -135,18 +135,18 @@ struct CFF2VariationStore DEFINE_SIZE_MIN (2 + VariationStore::min_size); }; -struct CFF2TopDictValues : TopDictValues +struct CFF2TopDictValues : TopDictValues<> { inline void init (void) { - TopDictValues::init (); + TopDictValues<>::init (); vstoreOffset = 0; FDSelectOffset = 0; } inline void fini (void) { - TopDictValues::fini (); + TopDictValues<>::fini (); } inline unsigned int calculate_serialized_size (void) const @@ -162,7 +162,7 @@ struct CFF2TopDictValues : TopDictValues size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); break; default: - size += TopDictValues::calculate_serialized_op_size (getValue (i)); + size += TopDictValues<>::calculate_serialized_op_size (getValue (i)); break; } } @@ -173,7 +173,7 @@ struct CFF2TopDictValues : TopDictValues unsigned int FDSelectOffset; }; -struct CFF2TopDictOpSet : TopDictOpSet +struct CFF2TopDictOpSet : TopDictOpSet<> { static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval) { @@ -209,7 +209,7 @@ struct CFF2TopDictOpSet : TopDictOpSet return true; } - typedef TopDictOpSet SUPER; + typedef TopDictOpSet<> SUPER; }; struct CFF2FontDictValues : DictValues diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc index ec196ca9b..c62f83a7b 100644 --- a/src/hb-subset-cff-common.cc +++ b/src/hb-subset-cff-common.cc @@ -46,7 +46,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, unsigned int &subst_fdselect_size /* OUT */, unsigned int &subst_fdselect_format /* OUT */, hb_vector_t &subst_first_glyphs /* OUT */, - FDMap &fdmap /* OUT */) + Remap &fdmap /* OUT */) { subset_fd_count = 0; subst_fdselect_size = 0; @@ -62,7 +62,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, hb_set_t *set = hb_set_create (); if (set == &Null (hb_set_t)) return false; - hb_codepoint_t prev_fd = HB_SET_VALUE_INVALID; + hb_codepoint_t prev_fd = CFF_UNDEF_CODE; for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) { hb_codepoint_t fd = src.get_fd (glyphs[i]); @@ -85,14 +85,16 @@ hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, } /* create a fdmap */ - fdmap.resize (fdCount); - for (unsigned int i = 0; i < fdmap.len; i++) - fdmap[i] = HB_SET_VALUE_INVALID; - hb_codepoint_t fd = HB_SET_VALUE_INVALID; - unsigned int fdindex = 0; + if (!fdmap.reset (fdCount)) + { + hb_set_destroy (set); + return false; + } + + hb_codepoint_t fd = CFF_UNDEF_CODE; while (set->next (&fd)) - fdmap[fd] = fdindex++; - assert (fdindex == subset_fd_count); + fdmap.add (fd); + assert (fdmap.get_count () == subset_fd_count); hb_set_destroy (set); } @@ -131,7 +133,7 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c, const FDSelect &src, unsigned int size, const hb_vector_t &first_glyphs, - const FDMap &fdmap) + const Remap &fdmap) { TRACE_SERIALIZE (this); FDSELECT3_4 *p = c->allocate_size (size); @@ -159,7 +161,7 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c, unsigned int fdselect_format, unsigned int size, const hb_vector_t &first_glyphs, - const FDMap &fdmap) + const Remap &fdmap) { TRACE_SERIALIZE (this); FDSelect *p = c->allocate_min (); diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index 03b93a0f3..38290085a 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -129,10 +129,11 @@ struct CFFSubTableOffsets { hb_vector_t localSubrsInfos; }; +template struct CFFTopDict_OpSerializer : OpSerializer { inline bool serialize (hb_serialize_context_t *c, - const OpStr &opstr, + const OPSTR &opstr, const CFFSubTableOffsets &offsets) const { TRACE_SERIALIZE (this); @@ -154,7 +155,7 @@ struct CFFTopDict_OpSerializer : OpSerializer return_trace (true); } - inline unsigned int calculate_serialized_size (const OpStr &opstr) const + inline unsigned int calculate_serialized_size (const OPSTR &opstr) const { switch (opstr.op) { @@ -162,7 +163,7 @@ struct CFFTopDict_OpSerializer : OpSerializer case OpCode_FDArray: case OpCode_FDSelect: return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - + default: return opstr.str.len; } @@ -179,12 +180,9 @@ struct CFFFontDict_OpSerializer : OpSerializer if (opstr.op == OpCode_Private) { - /* serialize the private dict size as a 2-byte integer */ - if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size))) - return_trace (false); - - /* serialize the private dict offset as a 4-byte integer */ - if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset))) + /* 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 */ @@ -386,7 +384,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, unsigned int &subst_fdselect_size /* OUT */, unsigned int &subst_fdselect_format /* OUT */, hb_vector_t &subst_first_glyphs /* OUT */, - CFF::FDMap &fdmap /* OUT */); + CFF::Remap &fdmap /* OUT */); HB_INTERNAL bool hb_serialize_cff_fdselect (hb_serialize_context_t *c, @@ -396,6 +394,6 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c, unsigned int fdselect_format, unsigned int size, const hb_vector_t &first_glyphs, - const CFF::FDMap &fdmap); + const CFF::Remap &fdmap); #endif /* HB_SUBSET_CFF_COMMON_HH */ diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 6d28599b9..7b68ea1ac 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -34,46 +34,122 @@ using namespace CFF; +struct RemapSID : Remap +{ + inline unsigned int add (unsigned int sid) + { + if ((sid != CFF_UNDEF_SID) && !is_std_std (sid)) + return offset_sid (Remap::add (unoffset_sid (sid))); + else + return sid; + } + + inline unsigned int operator[] (unsigned int sid) const + { + if (is_std_std (sid)) + return sid; + else + return offset_sid (Remap::operator [] (unoffset_sid (sid))); + } + + static const unsigned int num_std_strings = 391; + + static inline bool is_std_std (unsigned int sid) { return sid < num_std_strings; } + static inline unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; } + static inline unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } +}; + struct CFF1SubTableOffsets : CFFSubTableOffsets { inline CFF1SubTableOffsets (void) : CFFSubTableOffsets (), nameIndexOffset (0), - stringIndexOffset (0), - encodingOffset (0), - charsetOffset (0) + encodingOffset (0) { + stringIndexInfo.init (); + charsetInfo.init (); privateDictInfo.init (); } unsigned int nameIndexOffset; - unsigned int stringIndexOffset; + TableInfo stringIndexInfo; unsigned int encodingOffset; - unsigned int charsetOffset; + TableInfo charsetInfo; TableInfo privateDictInfo; }; -struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer +/* a copy of a parsed out CFF1TopDictValues augmented with additional operators */ +struct CFF1TopDictValuesMod : CFF1TopDictValues +{ + inline void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues)) + { + SUPER::init (); + base = base_; + } + + inline void fini (void) + { + SUPER::fini (); + } + + inline unsigned getNumValues (void) const + { + return base->getNumValues () + SUPER::getNumValues (); + } + inline const CFF1TopDictVal &getValue (unsigned int i) const + { + if (i < base->getNumValues ()) + return (*base)[i]; + else + return SUPER::values[i - base->getNumValues ()]; + } + inline const CFF1TopDictVal &operator [] (unsigned int i) const { return getValue (i); } + + inline void reassignSIDs (const RemapSID& sidmap) + { + for (unsigned int i = 0; i < NameDictValCount; i++) + nameSIDs[i] = sidmap[base->nameSIDs[i]]; + } + + protected: + typedef CFF1TopDictValues SUPER; + const CFF1TopDictValues *base; +}; + +struct TopDictModifiers +{ + inline TopDictModifiers (const CFF1SubTableOffsets &offsets_, + const unsigned int (&nameSIDs_)[NameDictValCount]) + : offsets (offsets_), + nameSIDs (nameSIDs_) + {} + + const CFF1SubTableOffsets &offsets; + const unsigned int (&nameSIDs)[NameDictValCount]; +}; + +struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer { inline bool serialize (hb_serialize_context_t *c, - const OpStr &opstr, - const CFF1SubTableOffsets &offsets) const + const CFF1TopDictVal &opstr, + const TopDictModifiers &mod) const { TRACE_SERIALIZE (this); - switch (opstr.op) + OpCode op = opstr.op; + switch (op) { case OpCode_charset: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charsetOffset)); + return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset)); case OpCode_Encoding: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset)); + return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset)); case OpCode_Private: { - if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size))) + if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size))) return_trace (false); - if (unlikely (!UnsizedByteStr::serialize_int4 (c, offsets.privateDictInfo.offset))) + if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset))) return_trace (false); HBUINT8 *p = c->allocate_size (1); if (unlikely (p == nullptr)) return_trace (false); @@ -81,29 +157,117 @@ struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer } break; + 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_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[NameDictValues::name_op_to_index (op)])); + + case OpCode_ROS: + { + /* for registry & ordering, reassigned SIDs are serialized + * for supplement, the original byte string is copied along with the op code */ + OpStr supp_op; + supp_op.op = op; + supp_op.str.str = opstr.str.str + opstr.last_arg_offset; + assert (opstr.str.len >= opstr.last_arg_offset + 3); + supp_op.str.len = opstr.str.len - opstr.last_arg_offset; + return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValIndex::registry]) && + UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValIndex::ordering]) && + copy_opstr (c, supp_op)); + } default: - return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets)); + return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, mod.offsets)); } return_trace (true); } - inline unsigned int calculate_serialized_size (const OpStr &opstr) const + inline unsigned int calculate_serialized_size (const CFF1TopDictVal &opstr) const { - switch (opstr.op) + OpCode op = opstr.op; + switch (op) { case OpCode_charset: case OpCode_Encoding: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); + 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.len - opstr.last_arg_offset)/* supplement + op */; + default: - return CFFTopDict_OpSerializer::calculate_serialized_size (opstr); + return CFFTopDict_OpSerializer::calculate_serialized_size (opstr); } } }; +struct FontDictValuesMod +{ + inline void init (const CFF1FontDictValues *base_, + unsigned int fontName_, + const TableInfo &privateDictInfo_) + { + base = base_; + fontName = fontName_; + privateDictInfo = privateDictInfo_; + } + + inline unsigned getNumValues (void) const + { + return base->getNumValues (); + } + + inline const OpStr &operator [] (unsigned int i) const { return (*base)[i]; } + + const CFF1FontDictValues *base; + TableInfo privateDictInfo; + unsigned int fontName; +}; + +struct CFF1FontDict_OpSerializer : CFFFontDict_OpSerializer +{ + inline bool serialize (hb_serialize_context_t *c, + const OpStr &opstr, + const FontDictValuesMod &mod) const + { + TRACE_SERIALIZE (this); + + if (opstr.op == OpCode_FontName) + return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName)); + else + return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); + } + + inline unsigned int calculate_serialized_size (const OpStr &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 CFFFontDict_OpSerializer SUPER; +}; + struct CFF1CSOpSet_Flatten : CFF1CSOpSet { static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param) @@ -199,11 +363,14 @@ struct cff_subset_plan { fdmap.init (); subset_charstrings.init (); flat_charstrings.init (); - privateDictInfos.init (); + fontdicts_mod.init (); subrRefMaps.init (); subset_enc_code_ranges.init (); subset_enc_supp_codes.init (); subset_charset_ranges.init (); + sidmap.init (); + for (unsigned int i = 0; i < NameDictValCount; i++) + topDictModSIDs[i] = CFF_UNDEF_SID; } inline ~cff_subset_plan (void) @@ -214,11 +381,13 @@ struct cff_subset_plan { fdmap.fini (); subset_charstrings.fini (); flat_charstrings.fini (); - privateDictInfos.fini (); + fontdicts_mod.fini (); subrRefMaps.fini (); subset_enc_code_ranges.fini (); subset_enc_supp_codes.init (); subset_charset_ranges.fini (); + sidmap.fini (); + fontdicts_mod.fini (); } inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) @@ -303,6 +472,9 @@ struct cff_subset_plan { hb_codepoint_t orig_glyph = plan->glyphs[glyph]; sid = acc.glyph_to_sid (orig_glyph); + if (!acc.is_CID ()) + sid = sidmap.add (sid); + if (sid != last_sid + 1) { if (subset_charset_ranges.len > 0) @@ -342,6 +514,29 @@ struct cff_subset_plan { subset_charset_format? subset_charset_ranges.len: plan->glyphs.len); } + inline bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) + { + if (unlikely (!sidmap.reset (acc.stringIndex->count))) + return false; + + for (unsigned int i = 0; i < NameDictValCount; i++) + { + unsigned int sid = acc.topDict.nameSIDs[i]; + if (sid != CFF_UNDEF_SID) + { + (void)sidmap.add (sid); + topDictModSIDs[i] = sidmap[sid]; + } + } + + if (acc.fdArray != &Null(CFF1FDArray)) + for (unsigned int fd = 0; fd < orig_fdcount; fd++) + if (!fdmap.excludes (fd)) + (void)sidmap.add (acc.fontDicts[fd].fontName); + + return true; + } + inline bool create (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { @@ -376,9 +571,9 @@ struct cff_subset_plan { /* top dict INDEX */ { /* Add encoding/charset to a (copy of) top dict as necessary */ - topdict_mod.init (&acc.topDicts[0]); - bool need_to_add_enc = (subset_encoding && !acc.topDicts[0].hasOp (OpCode_Encoding)); - bool need_to_add_set = (subset_charset && !acc.topDicts[0].hasOp (OpCode_charset)); + topdict_mod.init (&acc.topDict); + bool need_to_add_enc = (subset_encoding && !acc.topDict.hasOp (OpCode_Encoding)); + bool need_to_add_set = (subset_charset && !acc.topDict.hasOp (OpCode_charset)); if (need_to_add_enc || need_to_add_set) { if (need_to_add_enc) @@ -395,9 +590,36 @@ struct cff_subset_plan { &topdict_mod, 1, topdict_sizes, topSzr); } + /* Determine re-mapping of font index as fdmap among other info */ + if (acc.fdSelect != &Null(CFF1FDSelect) + && unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, + orig_fdcount, + *acc.fdSelect, + subset_fdcount, + offsets.FDSelectInfo.size, + subset_fdselect_format, + subset_fdselect_first_glyphs, + fdmap))) + return false; + + /* remove unused SIDs & reassign SIDs */ + { + /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */ + if (unlikely (!collect_sids_in_dicts (acc))) + return false; + assert (sidmap.get_count () <= 0x8000); + if (subset_charset) + offsets.charsetInfo.size = plan_subset_charset (acc, plan); + + topdict_mod.reassignSIDs (sidmap); + } + /* String INDEX */ - offsets.stringIndexOffset = final_size; - final_size += acc.stringIndex->get_size (); + { + offsets.stringIndexInfo.offset = final_size; + offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap); + final_size += offsets.stringIndexInfo.size; + } if (flatten_subrs) { @@ -433,24 +655,13 @@ struct cff_subset_plan { final_size += plan_subset_encoding (acc, plan); /* Charset */ - offsets.charsetOffset = final_size; - if (subset_charset) - final_size += plan_subset_charset (acc, plan); + offsets.charsetInfo.offset = final_size; + final_size += offsets.charsetInfo.size; /* FDSelect */ if (acc.fdSelect != &Null(CFF1FDSelect)) { offsets.FDSelectInfo.offset = final_size; - if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, - orig_fdcount, - *acc.fdSelect, - subset_fdcount, - offsets.FDSelectInfo.size, - subset_fdselect_format, - subset_fdselect_first_glyphs, - fdmap))) - return false; - if (!is_fds_subsetted ()) offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs); final_size += offsets.FDSelectInfo.size; @@ -459,8 +670,14 @@ struct cff_subset_plan { /* FDArray (FDIndex) */ if (acc.fdArray != &Null(CFF1FDArray)) { offsets.FDArrayInfo.offset = final_size; - CFFFontDict_OpSerializer fontSzr; - final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subset_fdcount, fdmap, fontSzr); + CFF1FontDict_OpSerializer fontSzr; + unsigned int dictsSize = 0; + for (unsigned int i = 0; i < acc.fontDicts.len; i++) + if (!fdmap.excludes (i)) + dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); + + offsets.FDArrayInfo.offSize = calcOffSize (dictsSize + 1); + final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); } /* CharStrings */ @@ -493,11 +710,12 @@ struct cff_subset_plan { { if (!fdmap.excludes (i)) { - unsigned int priv_size; CFFPrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs); - priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr); + unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr); TableInfo privInfo = { final_size, priv_size, 0 }; - privateDictInfos.push (privInfo); + FontDictValuesMod fontdict_mod; + fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo ); + fontdicts_mod.push (fontdict_mod); final_size += privInfo.size; if (!flatten_subrs) final_size += offsets.localSubrsInfos[i].size; @@ -505,10 +723,10 @@ struct cff_subset_plan { } if (!acc.is_CID ()) - offsets.privateDictInfo = privateDictInfos[0]; + offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; return ((subset_charstrings.len == plan->glyphs.len) && - (privateDictInfos.len == subset_fdcount)); + (fontdicts_mod.len == subset_fdcount)); } inline unsigned int get_final_size (void) const { return final_size; } @@ -526,12 +744,12 @@ struct cff_subset_plan { hb_vector_t subset_fdselect_first_glyphs; /* font dict index remap table from fullset FDArray to subset FDArray. - * set to HB_SET_VALUE_INVALID if excluded from subset */ - FDMap fdmap; + * set to CFF_UNDEF_CODE if excluded from subset */ + Remap fdmap; hb_vector_t subset_charstrings; ByteStrBuffArray flat_charstrings; - hb_vector_t privateDictInfos; + hb_vector_t fontdicts_mod; SubrRefMaps subrRefMaps; @@ -548,6 +766,9 @@ struct cff_subset_plan { uint8_t subset_charset_format; hb_vector_t subset_charset_ranges; bool subset_charset; + + RemapSID sidmap; + unsigned int topDictModSIDs[NameDictValCount]; }; static inline bool _write_cff1 (const cff_subset_plan &plan, @@ -589,9 +810,10 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, CFF1IndexOf *dest = c.start_embed< CFF1IndexOf > (); if (dest == nullptr) return false; CFF1TopDict_OpSerializer topSzr; + TopDictModifiers modifier (plan.offsets, plan.topDictModSIDs); if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, &plan.topdict_mod, 1, - plan.topdict_sizes, topSzr, plan.offsets))) + plan.topdict_sizes, topSzr, modifier))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); return false; @@ -600,10 +822,10 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, /* String INDEX */ { - assert (plan.offsets.stringIndexOffset == c.head - c.start); + assert (plan.offsets.stringIndexInfo.offset == c.head - c.start); CFF1StringIndex *dest = c.start_embed (); if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.stringIndex))) + 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; @@ -643,7 +865,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, /* Charset */ if (plan.subset_charset) { - assert (plan.offsets.charsetOffset == c.head - c.start); + assert (plan.offsets.charsetInfo.offset == c.head - c.start); Charset *dest = c.start_embed (); if (unlikely (dest == nullptr)) return false; if (unlikely (!dest->serialize (&c, @@ -689,10 +911,10 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, assert (plan.offsets.FDArrayInfo.offset == c.head - c.start); CFF1FDArray *fda = c.start_embed (); if (unlikely (fda == nullptr)) return false; - CFFFontDict_OpSerializer fontSzr; + CFF1FontDict_OpSerializer fontSzr; if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - acc.fontDicts, plan.subset_fdcount, plan.fdmap, - fontSzr, plan.privateDictInfos))) + plan.fontdicts_mod, + fontSzr))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); return false; @@ -719,7 +941,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, { PrivateDict *pd = c.start_embed (); if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size; + unsigned int priv_size = plan.flatten_subrs? 0: plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size; bool result; CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs); /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 391304a65..56bba57d0 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -44,7 +44,7 @@ struct CFF2SubTableOffsets : CFFSubTableOffsets unsigned int varStoreOffset; }; -struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer +struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer<> { inline bool serialize (hb_serialize_context_t *c, const OpStr &opstr, @@ -58,7 +58,7 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); default: - return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets)); + return_trace (CFFTopDict_OpSerializer<>::serialize (c, opstr, offsets)); } } @@ -70,7 +70,7 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); default: - return CFFTopDict_OpSerializer::calculate_serialized_size (opstr); + return CFFTopDict_OpSerializer<>::calculate_serialized_size (opstr); } } }; @@ -355,7 +355,7 @@ struct cff2_subset_plan { unsigned int subset_fdselect_format; hb_vector_t subset_fdselect_first_glyphs; - FDMap fdmap; + Remap fdmap; hb_vector_t subset_charstrings; ByteStrBuffArray flat_charstrings;