From f2d299b0b75fd110cdc6b16de31e7212e292cc14 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 4 Sep 2018 10:25:21 -0700 Subject: [PATCH] Drop hints from CFF2 charstrings Templatized ArgStack so it may store the default value along with blend deltas as BlendArg while parsing blend operator arguments in CFF2 charstring Added get_region_count() method to VarRegionList & VariationStore --- src/hb-cff-interp-common.hh | 67 ++++++++++++++++++++++----- src/hb-cff1-interp-cs.hh | 5 +- src/hb-cff2-interp-cs.hh | 91 ++++++++++++++++++++++++++++++++----- src/hb-ot-cff2-table.hh | 22 +++++---- src/hb-ot-layout-common.hh | 6 +++ src/hb-subset-cff-common.hh | 60 ++++++++++++------------ src/hb-subset-cff1.cc | 5 +- src/hb-subset-cff2.cc | 54 ++++++++++++++++++---- 8 files changed, 235 insertions(+), 75 deletions(-) diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index f9894ac41..8ec319022 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -210,7 +210,10 @@ inline unsigned int OpCode_Size (OpCode op) { return Is_OpCode_ESC (op)? 2: 1; } struct Number { - inline Number (void) { set_int (0); } + inline void init (void) + { set_int (0); } + inline void fini (void) + {} inline void set_int (int v) { format = NumInt; u.int_val = v; }; inline int to_int (void) const { return is_int ()? u.int_val: (int)to_real (); } @@ -336,7 +339,15 @@ struct ByteStr struct SubByteStr { inline SubByteStr (void) - : str (), offset (0) {} + { init (); } + + inline void init (void) + { + str = ByteStr (0); + offset = 0; + } + + inline void fini (void) {} inline SubByteStr (const ByteStr &str_, unsigned int offset_ = 0) : str (str_), offset (offset_) {} @@ -379,15 +390,35 @@ inline float parse_bcd (SubByteStr& substr, float& v) template struct Stack { - inline void init (void) { count = 0; } - inline void fini (void) { } + inline void init (void) + { + count = 0; + elements.init (); + elements.resize (kSizeLimit); + for (unsigned int i = 0; i < elements.len; i++) + elements[i].init (); + } + + inline void fini (void) + { + for (unsigned int i = 0; i < elements.len; i++) + elements[i].fini (); + } inline void push (const ELEM &v) { - if (likely (count < kSizeLimit)) + if (likely (count < elements.len)) elements[count++] = v; } + inline ELEM &push (void) + { + if (likely (count < elements.len)) + return elements[count++]; + else + return Crap(ELEM); + } + inline const ELEM& pop (void) { if (likely (count > 0)) @@ -396,9 +427,17 @@ struct Stack return Null(ELEM); } + inline const ELEM& peek (void) + { + if (likely (count > 0)) + return elements[count]; + else + return Null(ELEM); + } + inline void unpop (void) { - if (likely (count < kSizeLimit)) + if (likely (count < elements.len)) count++; } @@ -413,7 +452,7 @@ struct Stack static const unsigned int kSizeLimit = LIMIT; unsigned int count; - ELEM elements[kSizeLimit]; + hb_vector_t elements; }; /* argument stack */ @@ -422,16 +461,20 @@ struct ArgStack : Stack { inline void push_int (int v) { - ARG n; + ARG &n = S::push (); n.set_int (v); - S::push (n); + } + + inline void push_fixed (int32_t v) + { + ARG &n = S::push (); + n.set_fixed (v); } inline void push_real (float v) { - ARG n; + ARG &n = S::push (); n.set_real (v); - S::push (n); } inline bool check_pop_num (ARG& n) @@ -495,7 +538,7 @@ struct ArgStack : Stack { if (unlikely (!substr.avail (4) || !S::check_overflow (1))) return false; - push_real ((int32_t)*(const HBUINT32*)&substr[0] / 65536.0); + push_fixed ((int32_t)*(const HBUINT32*)&substr[0]); substr.inc (4); return true; } diff --git a/src/hb-cff1-interp-cs.hh b/src/hb-cff1-interp-cs.hh index 9f858573c..01faa44ba 100644 --- a/src/hb-cff1-interp-cs.hh +++ b/src/hb-cff1-interp-cs.hh @@ -35,9 +35,10 @@ using namespace OT; struct CFF1CSInterpEnv : CSInterpEnv { - inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs) + template + inline void init (const ByteStr &str, ACC &acc, unsigned int fd) { - SUPER::init (str, globalSubrs, localSubrs); + SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); processed_width = false; has_width = false; for (unsigned int i = 0; i < kTransientArraySize; i++) diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh index 3c94853c4..02bcaa1a8 100644 --- a/src/hb-cff2-interp-cs.hh +++ b/src/hb-cff2-interp-cs.hh @@ -33,12 +33,60 @@ namespace CFF { using namespace OT; +struct BlendArg : Number +{ + inline void init (void) + { + Number::init (); + deltas.init (); + } + + inline void fini (void) + { + Number::fini (); + + for (unsigned int i = 0; i < deltas.len; i++) + deltas[i].fini (); + deltas.fini (); + } + + inline void set_int (int v) { reset_blends (); Number::set_int (v); } + inline void set_fixed (int32_t v) { reset_blends (); Number::set_fixed (v); } + inline void set_real (float v) { reset_blends (); Number::set_real (v); } + + inline void set_blends (unsigned int numValues_, unsigned int valueIndex_, + unsigned int numBlends, const BlendArg *blends_) + { + numValues = numValues_; + valueIndex = valueIndex_; + deltas.resize (numBlends); + for (unsigned int i = 0; i < numBlends; i++) + deltas[i] = blends_[i]; + } + + inline bool blended (void) const { return deltas.len > 0; } + inline void reset_blends (void) + { + numValues = valueIndex = 0; + deltas.resize (0); + } + + unsigned int numValues; + unsigned int valueIndex; + hb_vector_t deltas; +}; + +typedef InterpEnv BlendInterpEnv; +typedef DictVal BlendDictVal; + struct CFF2CSInterpEnv : CSInterpEnv { - inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_) + template + inline void init (const ByteStr &str, ACC &acc, unsigned int fd) { - SUPER::init (str, globalSubrs_, localSubrs_); - ivs = 0; + SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + set_region_count (acc.region_count); + set_vsindex (acc.privateDicts[fd].vsindex); } inline bool fetch_op (OpCode &op) @@ -58,14 +106,17 @@ struct CFF2CSInterpEnv : CSInterpEnv { unsigned int index; if (likely (argStack.check_pop_uint (index))) - set_ivs (argStack.check_pop_uint (index)); + set_vsindex (argStack.check_pop_uint (index)); } - inline unsigned int get_ivs (void) const { return ivs; } - inline void set_ivs (unsigned int ivs_) { ivs = ivs_; } + inline unsigned int get_region_count (void) const { return region_count; } + inline void set_region_count (unsigned int region_count_) { region_count = region_count_; } + inline unsigned int get_vsindex (void) const { return vsindex; } + inline void set_vsindex (unsigned int vsindex_) { vsindex = vsindex_; } protected: - unsigned int ivs; + unsigned int region_count; + unsigned int vsindex; typedef CSInterpEnv SUPER; }; @@ -76,26 +127,42 @@ struct CFF2CSOpSet : CSOpSet static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param) { switch (op) { + case OpCode_callsubr: + case OpCode_callgsubr: + /* a subroutine number shoudln't be a blended value */ + return (!env.argStack.peek ().blended () && + SUPER::process_op (op, env, param)); case OpCode_blendcs: return OPSET::process_blend (env, param); case OpCode_vsindexcs: + if (unlikely (env.argStack.peek ().blended ())) + return false; OPSET::process_vsindex (env, param); break; default: - if (unlikely (!SUPER::process_op (op, env, param))) - return false; - break; + return SUPER::process_op (op, env, param); } return true; } static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param) { - // XXX: TODO leave default values? - OPSET::flush_args (env, param); + unsigned int n, k; + + k = env.get_region_count (); + if (unlikely (!env.argStack.check_pop_uint (n) || + (k+1) * n > env.argStack.get_count ())) + return false; + /* copy the blend values into blend array of the default values */ + unsigned int start = env.argStack.get_count () - ((k+1) * n); + for (unsigned int i = 0; i < n; i++) + env.argStack.elements[start + i].set_blends (n, i, k, &env.argStack.elements[start + n + (i * k)]); + + /* pop off blend values leaving default values now adorned with blend values */ + env.argStack.count -= k * n; return true; } diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index 639415373..d6874eaa6 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -48,13 +48,6 @@ typedef Subrs CFF2Subrs; typedef FDSelect3_4 FDSelect4; typedef FDSelect3_4_Range FDSelect4_Range; -struct BlendArg : Number -{ - // XXX: TODO -}; - -typedef InterpEnv BlendInterpEnv; - struct CFF2FDSelect { inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const @@ -271,6 +264,7 @@ struct CFF2PrivateDictValues_Base : DictValues DictValues::init (); subrsOffset = 0; localSubrs = &Null(CFF2Subrs); + vsindex = 0; } inline void fini (void) @@ -291,9 +285,9 @@ struct CFF2PrivateDictValues_Base : DictValues unsigned int subrsOffset; const CFF2Subrs *localSubrs; + unsigned int vsindex; }; -typedef DictVal BlendDictVal; typedef CFF2PrivateDictValues_Base CFF2PrivateDictValues_Subset; typedef CFF2PrivateDictValues_Base CFF2PrivateDictValues; @@ -332,9 +326,11 @@ struct CFF2PrivateDictOpSet : DictOpSet<> env.clear_args (); break; case OpCode_vsindexdict: + if (unlikely (!env.argStack.check_pop_uint (dictval.vsindex))) + return false; + break; case OpCode_blenddict: - // XXX: TODO - return true; + break; default: if (unlikely (!DictOpSet::process_op (op, env))) @@ -458,6 +454,11 @@ struct cff2 if (num_glyphs != sc.get_num_glyphs ()) { fini (); return; } + if (varStore != &Null(CFF2VariationStore)) + region_count = varStore->varStore.get_region_count (); + else + region_count = 0; + fdCount = fdArray->count; privateDicts.resize (fdCount); @@ -523,6 +524,7 @@ struct cff2 hb_vector_t privateDicts; unsigned int num_glyphs; + unsigned int region_count; }; typedef accelerator_templ_t accelerator_t; diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 887f27e9e..07e50daa0 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -1346,6 +1346,9 @@ struct VarRegionList axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount)); } + inline unsigned int get_region_count (void) const + { return regionCount; } + protected: HBUINT16 axisCount; HBUINT16 regionCount; @@ -1444,6 +1447,9 @@ struct VariationStore dataSets.sanitize (c, this)); } + inline unsigned int get_region_count (void) const + { return (this+regions).get_region_count (); } + protected: HBUINT16 format; LOffsetTo regions; diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index f06123b3c..ff6d7ed1c 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -42,30 +42,34 @@ struct ByteStrBuff : hb_vector_t return (push ((const char)b) != &Crap(char)); } - inline bool encode_num (const Number& n) + inline bool encode_int (int v) { - if (n.in_int_range ()) + if ((-1131 <= v) && (v <= 1131)) { - int v = n.to_int (); - if ((-1131 <= v) && (v <= 1131)) + if ((-107 <= v) && (v <= 107)) + return encode_byte (v + 139); + else if (v > 0) { - if ((-107 <= v) && (v <= 107)) - return encode_byte (v + 139); - else if (v > 0) - { - v -= 108; - return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF); - } - else - { - v = -v - 108; - return encode_byte ((v >> 8) + OpCode_TwoByteNegInt0) && encode_byte (v & 0xFF); - } + v -= 108; + return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF); } - assert ((v & ~0xFFFF) == 0); - return encode_byte (OpCode_shortint) && - encode_byte ((v >> 8) & 0xFF) && - encode_byte (v & 0xFF); + else + { + v = -v - 108; + return encode_byte ((v >> 8) + OpCode_TwoByteNegInt0) && encode_byte (v & 0xFF); + } + } + assert ((v & ~0xFFFF) == 0); + return encode_byte (OpCode_shortint) && + encode_byte ((v >> 8) & 0xFF) && + encode_byte (v & 0xFF); + } + + inline bool encode_num (const Number& n) + { + if (n.in_int_range ()) + { + return encode_int (n.to_int ()); } else { @@ -258,10 +262,10 @@ struct FlattenParam bool drop_hints; }; -template +template struct SubrFlattener { - inline SubrFlattener (const ACCESSOR &acc_, + inline SubrFlattener (const ACC &acc_, const hb_vector_t &glyphs_, bool drop_hints_) : acc (acc_), @@ -281,7 +285,7 @@ struct SubrFlattener const ByteStr str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); CSInterpreter interp; - interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + interp.env.init (str, acc, fd); FlattenParam param = { flat_charstrings[i], drop_hints }; if (unlikely (!interp.interpret (param))) return false; @@ -289,7 +293,7 @@ struct SubrFlattener return true; } - const ACCESSOR &acc; + const ACC &acc; const hb_vector_t &glyphs; bool drop_hints; }; @@ -342,10 +346,10 @@ struct SubrRefMapPair hb_set_t *local_map; }; -template +template struct SubrSubsetter { - inline SubrSubsetter (const ACCESSOR &acc_, const hb_vector_t &glyphs_) + inline SubrSubsetter (const ACC &acc_, const hb_vector_t &glyphs_) : acc (acc_), glyphs (glyphs_) {} @@ -361,14 +365,14 @@ struct SubrSubsetter unsigned int fd = acc.fdSelect->get_fd (glyph); SubrRefMapPair pair = { refmaps.global_map, refmaps.local_maps[fd] }; CSInterpreter interp; - interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + interp.env.init (str, acc, fd); if (unlikely (!interp.interpret (pair))) return false; } return true; } - const ACCESSOR &acc; + const ACC &acc; const hb_vector_t &glyphs; }; diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index b5828fc5f..932699be0 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -148,8 +148,9 @@ struct CFF1CSOpSet_Flatten : CFF1CSOpSet static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param) { SUPER::flush_hintmask (op, env, param); - for (unsigned int i = 0; i < env.hintmask_size; i++) - param.flatStr.encode_byte (env.substr[i]); + if (!param.drop_hints) + for (unsigned int i = 0; i < env.hintmask_size; i++) + param.flatStr.encode_byte (env.substr[i]); } private: diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index 0942a51bc..e00fda580 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -77,12 +77,6 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer struct CFF2CSOpSet_Flatten : CFF2CSOpSet { - static inline bool process_blend (CFF2CSInterpEnv &env, FlattenParam& param) - { - flush_args (env, param); - return true; - } - static inline void flush_args_and_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param) { switch (op) @@ -117,14 +111,56 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet static inline void flush_n_args (unsigned int n, CFF2CSInterpEnv &env, FlattenParam& param) { - for (unsigned int i = env.argStack.count - n; i < env.argStack.count; i++) - param.flatStr.encode_num (env.argStack.elements[i]); + for (unsigned int i = env.argStack.count - n; i < env.argStack.count;) + { + const BlendArg &arg = env.argStack.elements[i]; + if (arg.blended ()) + { + assert ((arg.numValues > 0) && (n >= arg.numValues)); + flatten_blends (arg, i, env, param); + i += arg.numValues; + } + else + { + param.flatStr.encode_num (arg); + i++; + } + } SUPER::flush_n_args (n, env, param); } + static inline void flatten_blends (const BlendArg &arg, unsigned int i, CFF2CSInterpEnv &env, FlattenParam& param) + { + /* flatten the default values */ + for (unsigned int j = 0; j < arg.numValues; j++) + { + const BlendArg &arg1 = env.argStack.elements[i + j]; + assert (arg1.blended () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) && + (arg1.deltas.len == env.get_region_count ())); + param.flatStr.encode_num (arg1); + } + /* flatten deltas for each value */ + for (unsigned int j = 0; j < arg.numValues; j++) + { + const BlendArg &arg1 = env.argStack.elements[i + j]; + for (unsigned int k = 0; k < arg1.deltas.len; k++) + param.flatStr.encode_num (arg1.deltas[k]); + } + /* flatten the number of values followed by blend operator */ + param.flatStr.encode_int (arg.numValues); + param.flatStr.encode_op (OpCode_blendcs); + } + static inline void flush_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param) { - param.flatStr.encode_op (op); + switch (op) + { + case OpCode_return: + case OpCode_endchar: + return; + default: + param.flatStr.encode_op (op); + } } private: