diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh index 9e22b1e64..a07ca0d87 100644 --- a/src/hb-cff-interp-cs-common.hh +++ b/src/hb-cff-interp-cs-common.hh @@ -282,6 +282,25 @@ struct CSOpSet : OpSet } } + /* hint operators (excluding hint/counter mask) */ + static inline bool is_hint_op (OpCode op) + { + switch (op) + { + case OpCode_hstem: + case OpCode_vstem: + case OpCode_hstemhm: + case OpCode_vstemhm: + case OpCode_hflex: + case OpCode_flex: + case OpCode_hflex1: + case OpCode_flex1: + return true; + default: + return false; + } + } + static inline bool is_subr_op (OpCode op) { switch (op) @@ -301,7 +320,6 @@ struct CSInterpreter : Interpreter { inline bool interpret (PARAM& param) { - param.init (); Interpreter &super = *this; super.env.set_endchar (false); diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index f7294cce2..56d7a57a0 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -252,13 +252,21 @@ struct CFFPrivateDict_OpSerializer : OpSerializer const bool flatten_subrs; }; +struct FlattenParam +{ + ByteStrBuff &flatStr; + bool drop_hints; +}; template struct SubrFlattener { - inline SubrFlattener (const ACCESSOR &acc_, const hb_vector_t &glyphs_) + inline SubrFlattener (const ACCESSOR &acc_, + const hb_vector_t &glyphs_, + bool drop_hints_) : acc (acc_), - glyphs (glyphs_) + glyphs (glyphs_), + drop_hints (drop_hints_) {} inline bool flatten (ByteStrBuffArray &flat_charstrings) @@ -272,9 +280,10 @@ struct SubrFlattener hb_codepoint_t glyph = glyphs[i]; const ByteStr str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); - CSInterpreter interp; + CSInterpreter interp; interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); - if (unlikely (!interp.interpret (flat_charstrings[i]))) + FlattenParam param = { flat_charstrings[i], drop_hints }; + if (unlikely (!interp.interpret (param))) return false; } return true; @@ -282,6 +291,7 @@ struct SubrFlattener const ACCESSOR &acc; const hb_vector_t &glyphs; + bool drop_hints; }; struct SubrRefMaps diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 769eb5ef5..26859346f 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -104,40 +104,50 @@ struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer } }; -struct CFF1CSOpSet_Flatten : CFF1CSOpSet +struct CFF1CSOpSet_Flatten : CFF1CSOpSet { - static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, ByteStrBuff& flatStr) + static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param) { - if (unlikely (!SUPER::process_op (op, env, flatStr))) + if (param.drop_hints && CSOPSET::is_hint_op (op)) + { + env.clear_stack (); + return true; + } + if (unlikely (!SUPER::process_op (op, env, param))) return false; switch (op) { case OpCode_hintmask: case OpCode_cntrmask: - if (unlikely (!flatStr.encode_op (op))) + if (param.drop_hints) + { + env.clear_stack (); + return true; + } + if (unlikely (!param.flatStr.encode_op (op))) return false; for (int i = -env.hintmask_size; i < 0; i++) - if (unlikely (!flatStr.encode_byte (env.substr[i]))) + if (unlikely (!param.flatStr.encode_byte (env.substr[i]))) return false; break; default: if (!CSOPSET::is_subr_op (op) && !CSOPSET::is_arg_op (op)) - return flatStr.encode_op (op); + return param.flatStr.encode_op (op); } return true; } - static inline void flush_stack (CFF1CSInterpEnv &env, ByteStrBuff& flatStr) + static inline void flush_stack (CFF1CSInterpEnv &env, FlattenParam& param) { for (unsigned int i = 0; i < env.argStack.size; i++) - flatStr.encode_num (env.argStack.elements[i]); - SUPER::flush_stack (env, flatStr); + param.flatStr.encode_num (env.argStack.elements[i]); + SUPER::flush_stack (env, param); } private: - typedef CFF1CSOpSet SUPER; - typedef CSOpSet CSOPSET; + typedef CFF1CSOpSet SUPER; + typedef CSOpSet CSOPSET; }; struct CFF1CSOpSet_SubsetSubrs : CFF1CSOpSet @@ -226,7 +236,8 @@ struct cff_subset_plan { if (flatten_subrs) { /* Flatten global & local subrs */ - SubrFlattener flattener(acc, plan->glyphs); + SubrFlattener + flattener(acc, plan->glyphs, plan->drop_hints); if (!flattener.flatten (flat_charstrings)) return false; diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 59535e6f4..0edca282a 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -75,20 +75,30 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer } }; -struct CFF2CSOpSet_Flatten : CFF2CSOpSet +struct CFF2CSOpSet_Flatten : CFF2CSOpSet { - static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, ByteStrBuff& flatStr) + static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param) { - if (unlikely (!SUPER::process_op (op, env, flatStr))) + if (param.drop_hints && CSOPSET::is_hint_op (op)) + { + env.clear_stack (); + return true; + } + if (unlikely (!SUPER::process_op (op, env, param))) return false; switch (op) { case OpCode_hintmask: case OpCode_cntrmask: - if (unlikely (!flatStr.encode_op (op))) + if (param.drop_hints) + { + env.clear_stack (); + return true; + } + if (unlikely (!param.flatStr.encode_op (op))) return false; for (int i = -env.hintmask_size; i < 0; i++) - if (unlikely (!flatStr.encode_byte (env.substr[i]))) + if (unlikely (!param.flatStr.encode_byte (env.substr[i]))) return false; break; case OpCode_return: @@ -98,33 +108,33 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet default: if (!CSOPSET::is_subr_op (op) && !CSOPSET::is_arg_op (op)) - return flatStr.encode_op (op); + return param.flatStr.encode_op (op); } return true; } - static inline bool process_blend (CFF2CSInterpEnv &env, ByteStrBuff& flatStr) + static inline bool process_blend (CFF2CSInterpEnv &env, FlattenParam& param) { - flush_stack (env, flatStr); + flush_stack (env, param); return true; } - static inline bool process_vsindex (CFF2CSInterpEnv &env, ByteStrBuff& flatStr) + static inline bool process_vsindex (CFF2CSInterpEnv &env, FlattenParam& param) { - flush_stack (env, flatStr); + flush_stack (env, param); return true; } - static inline void flush_stack (CFF2CSInterpEnv &env, ByteStrBuff& flatStr) + static inline void flush_stack (CFF2CSInterpEnv &env, FlattenParam& param) { for (unsigned int i = 0; i < env.argStack.size; i++) - flatStr.encode_num (env.argStack.elements[i]); - SUPER::flush_stack (env, flatStr); + param.flatStr.encode_num (env.argStack.elements[i]); + SUPER::flush_stack (env, param); } private: - typedef CFF2CSOpSet SUPER; - typedef CSOpSet CSOPSET; + typedef CFF2CSOpSet SUPER; + typedef CSOpSet CSOPSET; }; struct CFF2CSOpSet_SubsetSubrs : CFF2CSOpSet @@ -200,7 +210,8 @@ struct cff2_subset_plan { if (flatten_subrs) { /* Flatten global & local subrs */ - SubrFlattener flattener(acc, plan->glyphs); + SubrFlattener + flattener(acc, plan->glyphs, plan->drop_hints); if (!flattener.flatten (flat_charstrings)) return false;