From: Michiharu Ariza Date: Fri, 17 Aug 2018 20:13:18 +0000 (-0700) Subject: Added CFF2 Subr nullifier X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=cef75ea41a513a612a683bced27ced31761204b5;p=platform%2Fupstream%2FlibHarfBuzzSharp.git Added CFF2 Subr nullifier along with CFF2 charstring interpreter factored out common code between CFF1 & CFF2 to CSInterpreter moved fetch_op from Interpreter to InterpEnv misc code clean up & bug fixes --- diff --git a/src/Makefile.sources b/src/Makefile.sources index f5e1a6d..f7ae086 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -155,6 +155,7 @@ HB_OT_sources = \ hb-cff-interp-common-private.hh \ hb-cff-interp-cs-common-private.hh \ hb-cff1-interp-cs.hh \ + hb-cff2-interp-cs.hh \ hb-cff-interp-dict-common-private.hh \ $(NULL) diff --git a/src/hb-cff-interp-common-private.hh b/src/hb-cff-interp-common-private.hh index 0f81b48..9b4d488 100644 --- a/src/hb-cff-interp-common-private.hh +++ b/src/hb-cff-interp-common-private.hh @@ -56,7 +56,7 @@ enum OpCode { OpCode_Subrs, /* 19 CFF Private, CFF2 Private */ OpCode_defaultWidthX, /* 20 CFF Private (0) */ OpCode_nominalWidthX, /* 21 CFF Private (0) */ - OpCode_vsindex, /* 22 CFF2 Private/CS */ + OpCode_vsindexdict, /* 22 CFF2 Private/CS */ OpCode_blenddict, /* 23 CFF2 Private/CS */ OpCode_vstore, /* 24 CFF2 Top */ OpCode_reserved25, /* 25 */ @@ -142,8 +142,8 @@ enum OpCode { // OpCode_escape, /* 12 CFF, CFF2 */ OpCode_Reserved13 = 13, OpCode_endchar, /* 14 CFF */ - // OpCode_vsindex, /* 15 CFF2 */ - OpCode_blendcs = 16, /* 16 CFF2 */ + OpCode_vsindexcs, /* 15 CFF2 */ + OpCode_blendcs, /* 16 CFF2 */ OpCode_Reserved17, OpCode_hstemhm, /* 18 CFF, CFF2 */ OpCode_hintmask, /* 19 CFF, CFF2 */ @@ -365,8 +365,8 @@ struct Stack inline void clear (void) { size = 0; } - inline bool check_overflow (unsigned int count) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); } - inline bool check_underflow (unsigned int count) const { return (count <= size); } + inline bool check_overflow (unsigned int count=1) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); } + inline bool check_underflow (unsigned int count=1) const { return (count <= size); } inline unsigned int get_size (void) const { return size; } inline bool is_empty (void) const { return size == 0; } @@ -396,7 +396,7 @@ struct ArgStack : Stack inline bool check_pop_num (Number& n) { - if (unlikely (!this->check_underflow (1))) + if (unlikely (!this->check_underflow ())) return false; n = this->pop (); return true; @@ -413,7 +413,7 @@ struct ArgStack : Stack inline bool check_pop_int (int& v) { - if (unlikely (!this->check_underflow (1))) + if (unlikely (!this->check_underflow ())) return false; v = this->pop ().to_int (); return true; @@ -501,6 +501,21 @@ struct InterpEnv argStack.fini (); } + inline bool fetch_op (OpCode &op) + { + if (unlikely (!substr.avail ())) + return false; + op = (OpCode)(unsigned char)substr[0]; + if (op == OpCode_escape) { + if (unlikely (!substr.avail ())) + return false; + op = Make_OpCode_ESC (substr[1]); + substr.inc (); + } + substr.inc (); + return true; + } + SubByteStr substr; ArgStack argStack; }; @@ -558,21 +573,6 @@ struct Interpreter { inline void fini (void) { env.fini (); } - inline bool fetch_op (OpCode &op) - { - if (unlikely (!env.substr.avail ())) - return false; - op = (OpCode)(unsigned char)env.substr[0]; - if (op == OpCode_escape) { - if (unlikely (!env.substr.avail ())) - return false; - op = Make_OpCode_ESC (env.substr[1]); - env.substr.inc (); - } - env.substr.inc (); - return true; - } - ENV env; }; diff --git a/src/hb-cff-interp-cs-common-private.hh b/src/hb-cff-interp-cs-common-private.hh index cf98e0f..3172535 100644 --- a/src/hb-cff-interp-cs-common-private.hh +++ b/src/hb-cff-interp-cs-common-private.hh @@ -64,6 +64,11 @@ struct CSInterpEnv : InterpEnv { InterpEnv::init (str); + stack_cleared = false; + seen_moveto = true; + seen_hintmask = false; + hstem_count = 0; + vstem_count = 0; callStack.init (); globalSubrs.init (globalSubrs_); localSubrs.init (localSubrs_); @@ -105,20 +110,55 @@ struct CSInterpEnv : InterpEnv inline bool returnFromSubr (void) { - if (unlikely (!callStack.check_underflow (1))) + if (unlikely (!callStack.check_underflow ())) return false; substr = callStack.pop (); return true; } + inline void determine_hintmask_size (void) + { + if (!seen_hintmask) + { + vstem_count += argStack.size / 2; + hintmask_size = (hstem_count + vstem_count + 7) >> 3; + seen_hintmask = true; + } + clear_stack (); + } + + inline void process_moveto (void) + { + clear_stack (); + + if (!seen_moveto) + { + determine_hintmask_size (); + seen_moveto = true; + } + } + + inline void clear_stack (void) + { + stack_cleared = true; + argStack.clear (); + } + inline void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; } inline bool is_endchar (void) const { return endchar_flag; } + inline bool is_stack_cleared (void) const { return stack_cleared; } protected: - bool endchar_flag; + bool endchar_flag; + bool stack_cleared; + bool seen_moveto; + bool seen_hintmask; public: + unsigned int hstem_count; + unsigned int vstem_count; + unsigned int hintmask_size; CallStack callStack; BiasedSubrs globalSubrs; BiasedSubrs localSubrs; @@ -131,6 +171,12 @@ struct CSOpSet : OpSet { switch (op) { + case OpCode_return: + return env.returnFromSubr (); + case OpCode_endchar: + env.set_endchar (true); + return true; + case OpCode_longintcs: return env.argStack.push_longint_from_substr (env.substr); @@ -140,9 +186,50 @@ struct CSOpSet : OpSet case OpCode_callgsubr: return env.callSubr (env.globalSubrs); + case OpCode_hstem: + case OpCode_hstemhm: + env.hstem_count += env.argStack.size / 2; + env.clear_stack (); + break; + case OpCode_vstem: + case OpCode_vstemhm: + env.vstem_count += env.argStack.size / 2; + env.clear_stack (); + break; + case OpCode_hintmask: + case OpCode_cntrmask: + env.determine_hintmask_size (); + if (unlikely (!env.substr.avail (env.hintmask_size))) + return false; + env.substr.inc (env.hintmask_size); + break; + + case OpCode_vmoveto: + case OpCode_rlineto: + case OpCode_hlineto: + case OpCode_vlineto: + case OpCode_rmoveto: + case OpCode_hmoveto: + env.process_moveto (); + break; + case OpCode_rrcurveto: + case OpCode_rcurveline: + case OpCode_rlinecurve: + case OpCode_vvcurveto: + case OpCode_hhcurveto: + case OpCode_vhcurveto: + case OpCode_hvcurveto: + case OpCode_hflex: + case OpCode_flex: + case OpCode_hflex1: + case OpCode_flex1: + env.clear_stack (); + break; + default: return OpSet::process_op (op, env); } + return true; } }; @@ -157,13 +244,11 @@ struct CSInterpreter : Interpreter for (;;) { OpCode op; - if (unlikely (!super.fetch_op (op) || + if (unlikely (!super.env.fetch_op (op) || !OPSET::process_op (op, super.env, param))) return false; if (super.env.is_endchar ()) break; - if (!super.env.substr.avail ()) - return false; } return true; diff --git a/src/hb-cff-interp-dict-common-private.hh b/src/hb-cff-interp-dict-common-private.hh index 60764fd..62041c9 100644 --- a/src/hb-cff-interp-dict-common-private.hh +++ b/src/hb-cff-interp-dict-common-private.hh @@ -170,7 +170,8 @@ struct DictInterpreter : Interpreter do { OpCode op; - if (unlikely (!super.fetch_op (op) || !OPSET::process_op (op, super.env, param))) + if (unlikely (!super.env.fetch_op (op) || + !OPSET::process_op (op, super.env, param))) return false; } while (super.env.substr.avail ()); diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh index 6767d0f..c76a788 100644 --- a/src/hb-cff1-interp-cs.hh +++ b/src/hb-cff1-interp-cs.hh @@ -38,11 +38,6 @@ struct CFF1CSInterpEnv : CSInterpEnv inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs) { CSInterpEnv::init (str, globalSubrs, localSubrs); - seen_width = false; - seen_moveto = true; - seen_hintmask = false; - hstem_count = 0; - vstem_count = 0; for (unsigned int i = 0; i < kTransientArraySize; i++) transient_array[i].set_int (0); } @@ -50,34 +45,6 @@ struct CFF1CSInterpEnv : CSInterpEnv bool check_transient_array_index (unsigned int i) const { return i < kTransientArraySize; } - inline void determine_hintmask_size (void) - { - if (!seen_hintmask) - { - vstem_count += argStack.size / 2; - hintmask_size = (hstem_count + vstem_count + 7) >> 3; - seen_hintmask = true; - } - clear_stack (); - } - - inline void process_moveto (void) - { - clear_stack (); - - if (!seen_moveto) - { - determine_hintmask_size (); - seen_moveto = true; - } - } - - inline void clear_stack (void) - { - seen_width = true; - argStack.clear (); - } - inline void process_width (void) { if (!seen_width && (argStack.size > 0)) @@ -90,11 +57,6 @@ struct CFF1CSInterpEnv : CSInterpEnv bool seen_width; Number width; - bool seen_moveto; - bool seen_hintmask; - unsigned int hintmask_size; - unsigned int hstem_count; - unsigned int vstem_count; static const unsigned int kTransientArraySize = 32; Number transient_array[kTransientArraySize]; @@ -109,11 +71,6 @@ struct CFF1CSOpSet : CSOpSet switch (op) { - case OpCode_return: - return env.returnFromSubr (); - case OpCode_endchar: - env.set_endchar (true); - return true; case OpCode_and: if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f)); @@ -223,45 +180,6 @@ struct CFF1CSOpSet : CSOpSet } } break; - case OpCode_hstem: - case OpCode_hstemhm: - env.hstem_count += env.argStack.size / 2; - env.clear_stack (); - break; - case OpCode_vstem: - case OpCode_vstemhm: - env.vstem_count += env.argStack.size / 2; - env.clear_stack (); - break; - case OpCode_hintmask: - case OpCode_cntrmask: - env.determine_hintmask_size (); - if (unlikely (!env.substr.avail (env.hintmask_size))) - return false; - env.substr.inc (env.hintmask_size); - break; - - case OpCode_vmoveto: - case OpCode_rlineto: - case OpCode_hlineto: - case OpCode_vlineto: - case OpCode_rmoveto: - case OpCode_hmoveto: - env.process_moveto (); - break; - case OpCode_rrcurveto: - case OpCode_rcurveline: - case OpCode_rlinecurve: - case OpCode_vvcurveto: - case OpCode_hhcurveto: - case OpCode_vhcurveto: - case OpCode_hvcurveto: - case OpCode_hflex: - case OpCode_flex: - case OpCode_hflex1: - case OpCode_flex1: - env.clear_stack (); - break; default: typedef CSOpSet SUPER; if (unlikely (!SUPER::process_op (op, env, param))) diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh new file mode 100644 index 0000000..519b5fc --- /dev/null +++ b/src/hb-cff2-interp-cs.hh @@ -0,0 +1,97 @@ +/* + * Copyright © 2018 Adobe Systems Incorporated. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ +#ifndef HB_CFF2_INTERP_CS_HH +#define HB_CFF2_INTERP_CS_HH + +#include "hb-private.hh" +#include "hb-cff-interp-cs-common-private.hh" + +namespace CFF { + +using namespace OT; + +struct CFF2CSInterpEnv : CSInterpEnv +{ + inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_) + { + CSInterpEnv::init (str, globalSubrs_, localSubrs_); + ivs = 0; + } + + inline bool fetch_op (OpCode &op) + { + if (unlikely (substr.avail ())) + return CSInterpEnv::fetch_op (op); + + /* make up return or endchar op */ + if (callStack.check_underflow ()) + op = OpCode_return; + else + op = OpCode_endchar; + return true; + } + + inline unsigned int get_ivs (void) const { return ivs; } + inline void set_ivs (unsigned int ivs_) { ivs = ivs_; } + + protected: + unsigned int ivs; +}; + +template +struct CFF2CSOpSet : CSOpSet +{ + static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param) + { + switch (op) { + + case OpCode_blendcs: + env.clear_stack (); // XXX: TODO + break; + case OpCode_vsindexcs: + { + unsigned int ivs; + if (unlikely (!env.argStack.check_pop_uint (ivs))) return false; + env.set_ivs (ivs); + env.clear_stack (); + } + break; + default: + typedef CSOpSet SUPER; + if (unlikely (!SUPER::process_op (op, env, param))) + return false; + break; + } + return true; + } +}; + +template +struct CFF2CSInterpreter : CSInterpreter {}; + +} /* namespace CFF */ + +#endif /* HB_CFF2_INTERP_CS_HH */ diff --git a/src/hb-ot-cff-common-private.hh b/src/hb-ot-cff-common-private.hh index e22ee87..3f9f865 100644 --- a/src/hb-ot-cff-common-private.hh +++ b/src/hb-ot-cff-common-private.hh @@ -557,6 +557,8 @@ struct Subrs : CFFIndex inline bool serialize (hb_serialize_context_t *c, const Subrs &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr()) { TRACE_SERIALIZE (this); + if (&subrs == &Null(Subrs)) + return_trace (true); if ((subrs.count == 0) || (hb_set_get_population (set) == 0)) { if (!unlikely (c->allocate_size (COUNT::static_size))) @@ -580,6 +582,8 @@ struct Subrs : CFFIndex /* in parallel to above */ inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const { + if (this == &Null(Subrs)) + return 0; unsigned int count_ = CFFIndex::count; offSize = 0; if ((count_ == 0) || (hb_set_get_population (set) == 0)) diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index f5d356d..da4acf4 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -318,6 +318,7 @@ struct CFF2PrivateDictOpSet : DictOpSet return false; env.argStack.clear (); break; + case OpCode_vsindexdict: case OpCode_blenddict: // XXX: TODO return true; @@ -442,10 +443,11 @@ struct cff2 if (num_glyphs != sc.get_num_glyphs ()) { fini (); return; } - privateDicts.resize (fdArray->count); + fdCount = fdArray->count; + privateDicts.resize (fdCount); /* parse font dicts and gather private dicts */ - for (unsigned int i = 0; i < fdArray->count; i++) + for (unsigned int i = 0; i < fdCount; i++) { const ByteStr fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } @@ -500,6 +502,7 @@ struct cff2 const CFF2CharStrings *charStrings; const CFF2FDArray *fdArray; const CFF2FDSelect *fdSelect; + unsigned int fdCount; hb_vector_t fontDicts; hb_vector_t privateDicts; diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 5e54349..921b1df 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -555,6 +555,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, } } + assert (c.head == c.end); c.end_serialize (); return true; diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 7835523..ab876c9 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -30,6 +30,7 @@ #include "hb-subset-cff2.hh" #include "hb-subset-plan.hh" #include "hb-subset-cff-common-private.hh" +#include "hb-cff2-interp-cs.hh" using namespace CFF; @@ -37,6 +38,12 @@ struct CFF2SubTableOffsets { inline CFF2SubTableOffsets (void) { memset (this, 0, sizeof(*this)); + localSubrsInfos.init (); + } + + inline ~CFF2SubTableOffsets (void) + { + localSubrsInfos.fini (); } unsigned int topDictSize; @@ -45,6 +52,8 @@ struct CFF2SubTableOffsets { TableInfo FDArrayInfo; TableInfo charStringsInfo; unsigned int privateDictsOffset; + TableInfo globalSubrsInfo; + hb_vector_t localSubrsInfos; }; struct CFF2TopDict_OpSerializer : OpSerializer @@ -157,6 +166,31 @@ struct CFF2PrivateDict_OpSerializer : OpSerializer } }; +struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet +{ + static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, SubrRefMapPair& refMapPair) + { + unsigned int subr_num; + switch (op) { + case OpCode_callsubr: + if (!unlikely (env.popSubrNum(env.localSubrs, subr_num))) + return false; + env.argStack.unpop (); + refMapPair.local_map->add (subr_num); + break; + case OpCode_callgsubr: + if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num))) + return false; + env.argStack.unpop (); + refMapPair.global_map->add (subr_num); + break; + default: + break; + } + return CFF2CSOpSet::process_op (op, env, refMapPair); + } +}; + struct cff2_subset_plan { inline cff2_subset_plan (void) : final_size (0), @@ -176,6 +210,7 @@ struct cff2_subset_plan { fdmap.fini (); subset_charstrings.fini (); privateDictInfos.fini (); + subrRefMaps.fini (); } inline bool create (const OT::cff2::accelerator_subset_t &acc, @@ -194,8 +229,22 @@ struct cff2_subset_plan { final_size += offsets.topDictSize; } + /* Subset global & local subrs */ + { + SubrSubsetter subsetter(acc, plan->glyphs); + if (!subsetter.collect_refs (subrRefMaps)) + return false; + + offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map); + if (!offsets.localSubrsInfos.resize (orig_fdcount)) + return false; + for (unsigned int i = 0; i < orig_fdcount; i++) + offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i]); + } + /* global subrs */ - final_size += acc.globalSubrs->get_size (); + offsets.globalSubrsInfo.offset = final_size; + final_size += offsets.globalSubrsInfo.size; /* variation store */ if (acc.varStore != &Null(CFF2VariationStore)) @@ -253,7 +302,7 @@ struct cff2_subset_plan { CFF2PrivateDict_OpSerializer privSzr; TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr), 0 }; privateDictInfos.push (privInfo); - final_size += privInfo.size + acc.privateDicts[i].localSubrs->get_size (); + final_size += privInfo.size + offsets.localSubrsInfos[i].size; } } @@ -275,6 +324,8 @@ struct cff2_subset_plan { hb_vector_t subset_charstrings; hb_vector_t privateDictInfos; + + SubrRefMaps subrRefMaps; }; static inline bool _write_cff2 (const cff2_subset_plan &plan, @@ -312,8 +363,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start); CFF2Subrs *dest = c.start_embed (); if (unlikely (dest == nullptr)) return false; - CFFIndex *super = dest; - if (unlikely (!super->serialize (&c, *acc.globalSubrs))) + if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs"); return false; @@ -409,8 +459,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i); return false; } - CFFIndex *super = subrs; - if (unlikely (!super->serialize (&c, *acc.privateDicts[i].localSubrs))) + if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i]))) { DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i); return false; @@ -419,6 +468,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, } } + assert (c.head == c.end); c.end_serialize (); return true;