提交 cef75ea4 编写于 作者: M Michiharu Ariza

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
上级 f57d6bcb
...@@ -155,6 +155,7 @@ HB_OT_sources = \ ...@@ -155,6 +155,7 @@ HB_OT_sources = \
hb-cff-interp-common-private.hh \ hb-cff-interp-common-private.hh \
hb-cff-interp-cs-common-private.hh \ hb-cff-interp-cs-common-private.hh \
hb-cff1-interp-cs.hh \ hb-cff1-interp-cs.hh \
hb-cff2-interp-cs.hh \
hb-cff-interp-dict-common-private.hh \ hb-cff-interp-dict-common-private.hh \
$(NULL) $(NULL)
......
...@@ -56,7 +56,7 @@ enum OpCode { ...@@ -56,7 +56,7 @@ enum OpCode {
OpCode_Subrs, /* 19 CFF Private, CFF2 Private */ OpCode_Subrs, /* 19 CFF Private, CFF2 Private */
OpCode_defaultWidthX, /* 20 CFF Private (0) */ OpCode_defaultWidthX, /* 20 CFF Private (0) */
OpCode_nominalWidthX, /* 21 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_blenddict, /* 23 CFF2 Private/CS */
OpCode_vstore, /* 24 CFF2 Top */ OpCode_vstore, /* 24 CFF2 Top */
OpCode_reserved25, /* 25 */ OpCode_reserved25, /* 25 */
...@@ -142,8 +142,8 @@ enum OpCode { ...@@ -142,8 +142,8 @@ enum OpCode {
// OpCode_escape, /* 12 CFF, CFF2 */ // OpCode_escape, /* 12 CFF, CFF2 */
OpCode_Reserved13 = 13, OpCode_Reserved13 = 13,
OpCode_endchar, /* 14 CFF */ OpCode_endchar, /* 14 CFF */
// OpCode_vsindex, /* 15 CFF2 */ OpCode_vsindexcs, /* 15 CFF2 */
OpCode_blendcs = 16, /* 16 CFF2 */ OpCode_blendcs, /* 16 CFF2 */
OpCode_Reserved17, OpCode_Reserved17,
OpCode_hstemhm, /* 18 CFF, CFF2 */ OpCode_hstemhm, /* 18 CFF, CFF2 */
OpCode_hintmask, /* 19 CFF, CFF2 */ OpCode_hintmask, /* 19 CFF, CFF2 */
...@@ -365,8 +365,8 @@ struct Stack ...@@ -365,8 +365,8 @@ struct Stack
inline void clear (void) { size = 0; } inline void clear (void) { size = 0; }
inline bool check_overflow (unsigned int count) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); } inline bool check_overflow (unsigned int count=1) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
inline bool check_underflow (unsigned int count) const { return (count <= size); } inline bool check_underflow (unsigned int count=1) const { return (count <= size); }
inline unsigned int get_size (void) const { return size; } inline unsigned int get_size (void) const { return size; }
inline bool is_empty (void) const { return size == 0; } inline bool is_empty (void) const { return size == 0; }
...@@ -396,7 +396,7 @@ struct ArgStack : Stack<Number, 513> ...@@ -396,7 +396,7 @@ struct ArgStack : Stack<Number, 513>
inline bool check_pop_num (Number& n) inline bool check_pop_num (Number& n)
{ {
if (unlikely (!this->check_underflow (1))) if (unlikely (!this->check_underflow ()))
return false; return false;
n = this->pop (); n = this->pop ();
return true; return true;
...@@ -413,7 +413,7 @@ struct ArgStack : Stack<Number, 513> ...@@ -413,7 +413,7 @@ struct ArgStack : Stack<Number, 513>
inline bool check_pop_int (int& v) inline bool check_pop_int (int& v)
{ {
if (unlikely (!this->check_underflow (1))) if (unlikely (!this->check_underflow ()))
return false; return false;
v = this->pop ().to_int (); v = this->pop ().to_int ();
return true; return true;
...@@ -501,6 +501,21 @@ struct InterpEnv ...@@ -501,6 +501,21 @@ struct InterpEnv
argStack.fini (); 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; SubByteStr substr;
ArgStack argStack; ArgStack argStack;
}; };
...@@ -558,21 +573,6 @@ struct Interpreter { ...@@ -558,21 +573,6 @@ struct Interpreter {
inline void fini (void) { env.fini (); } 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; ENV env;
}; };
......
...@@ -64,6 +64,11 @@ struct CSInterpEnv : InterpEnv ...@@ -64,6 +64,11 @@ struct CSInterpEnv : InterpEnv
{ {
InterpEnv::init (str); InterpEnv::init (str);
stack_cleared = false;
seen_moveto = true;
seen_hintmask = false;
hstem_count = 0;
vstem_count = 0;
callStack.init (); callStack.init ();
globalSubrs.init (globalSubrs_); globalSubrs.init (globalSubrs_);
localSubrs.init (localSubrs_); localSubrs.init (localSubrs_);
...@@ -105,20 +110,55 @@ struct CSInterpEnv : InterpEnv ...@@ -105,20 +110,55 @@ struct CSInterpEnv : InterpEnv
inline bool returnFromSubr (void) inline bool returnFromSubr (void)
{ {
if (unlikely (!callStack.check_underflow (1))) if (unlikely (!callStack.check_underflow ()))
return false; return false;
substr = callStack.pop (); substr = callStack.pop ();
return true; 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 void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
inline bool is_endchar (void) const { return endchar_flag; } inline bool is_endchar (void) const { return endchar_flag; }
inline bool is_stack_cleared (void) const { return stack_cleared; }
protected: protected:
bool endchar_flag; bool endchar_flag;
bool stack_cleared;
bool seen_moveto;
bool seen_hintmask;
public: public:
unsigned int hstem_count;
unsigned int vstem_count;
unsigned int hintmask_size;
CallStack callStack; CallStack callStack;
BiasedSubrs<SUBRS> globalSubrs; BiasedSubrs<SUBRS> globalSubrs;
BiasedSubrs<SUBRS> localSubrs; BiasedSubrs<SUBRS> localSubrs;
...@@ -131,6 +171,12 @@ struct CSOpSet : OpSet ...@@ -131,6 +171,12 @@ struct CSOpSet : OpSet
{ {
switch (op) { switch (op) {
case OpCode_return:
return env.returnFromSubr ();
case OpCode_endchar:
env.set_endchar (true);
return true;
case OpCode_longintcs: case OpCode_longintcs:
return env.argStack.push_longint_from_substr (env.substr); return env.argStack.push_longint_from_substr (env.substr);
...@@ -140,9 +186,50 @@ struct CSOpSet : OpSet ...@@ -140,9 +186,50 @@ struct CSOpSet : OpSet
case OpCode_callgsubr: case OpCode_callgsubr:
return env.callSubr (env.globalSubrs); 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: default:
return OpSet::process_op (op, env); return OpSet::process_op (op, env);
} }
return true;
} }
}; };
...@@ -157,13 +244,11 @@ struct CSInterpreter : Interpreter<ENV> ...@@ -157,13 +244,11 @@ struct CSInterpreter : Interpreter<ENV>
for (;;) { for (;;) {
OpCode op; OpCode op;
if (unlikely (!super.fetch_op (op) || if (unlikely (!super.env.fetch_op (op) ||
!OPSET::process_op (op, super.env, param))) !OPSET::process_op (op, super.env, param)))
return false; return false;
if (super.env.is_endchar ()) if (super.env.is_endchar ())
break; break;
if (!super.env.substr.avail ())
return false;
} }
return true; return true;
......
...@@ -170,7 +170,8 @@ struct DictInterpreter : Interpreter<InterpEnv> ...@@ -170,7 +170,8 @@ struct DictInterpreter : Interpreter<InterpEnv>
do do
{ {
OpCode op; 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; return false;
} while (super.env.substr.avail ()); } while (super.env.substr.avail ());
......
...@@ -38,11 +38,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs> ...@@ -38,11 +38,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs) inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
{ {
CSInterpEnv<CFF1Subrs>::init (str, globalSubrs, localSubrs); CSInterpEnv<CFF1Subrs>::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++) for (unsigned int i = 0; i < kTransientArraySize; i++)
transient_array[i].set_int (0); transient_array[i].set_int (0);
} }
...@@ -50,34 +45,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs> ...@@ -50,34 +45,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
bool check_transient_array_index (unsigned int i) const bool check_transient_array_index (unsigned int i) const
{ return i < kTransientArraySize; } { 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) inline void process_width (void)
{ {
if (!seen_width && (argStack.size > 0)) if (!seen_width && (argStack.size > 0))
...@@ -90,11 +57,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs> ...@@ -90,11 +57,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
bool seen_width; bool seen_width;
Number 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; static const unsigned int kTransientArraySize = 32;
Number transient_array[kTransientArraySize]; Number transient_array[kTransientArraySize];
...@@ -109,11 +71,6 @@ struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM> ...@@ -109,11 +71,6 @@ struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM>
switch (op) { switch (op) {
case OpCode_return:
return env.returnFromSubr ();
case OpCode_endchar:
env.set_endchar (true);
return true;
case OpCode_and: case OpCode_and:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false; 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)); env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f));
...@@ -223,45 +180,6 @@ struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM> ...@@ -223,45 +180,6 @@ struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM>
} }
} }
break; 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: default:
typedef CSOpSet<CFF1Subrs, PARAM> SUPER; typedef CSOpSet<CFF1Subrs, PARAM> SUPER;
if (unlikely (!SUPER::process_op (op, env, param))) if (unlikely (!SUPER::process_op (op, env, param)))
......
/*
* 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<CFF2Subrs>
{
inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_)
{
CSInterpEnv<CFF2Subrs>::init (str, globalSubrs_, localSubrs_);
ivs = 0;
}
inline bool fetch_op (OpCode &op)
{
if (unlikely (substr.avail ()))
return CSInterpEnv<CFF2Subrs>::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 <typename PARAM>
struct CFF2CSOpSet : CSOpSet<CFF2Subrs, PARAM>
{
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<CFF2Subrs, PARAM> SUPER;
if (unlikely (!SUPER::process_op (op, env, param)))
return false;
break;
}
return true;
}
};
template <typename OPSET, typename PARAM>
struct CFF2CSInterpreter : CSInterpreter<CFF2CSInterpEnv, OPSET, PARAM> {};
} /* namespace CFF */
#endif /* HB_CFF2_INTERP_CS_HH */
...@@ -557,6 +557,8 @@ struct Subrs : CFFIndex<COUNT> ...@@ -557,6 +557,8 @@ struct Subrs : CFFIndex<COUNT>
inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr()) inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr())
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
if (&subrs == &Null(Subrs<COUNT>))
return_trace (true);
if ((subrs.count == 0) || (hb_set_get_population (set) == 0)) if ((subrs.count == 0) || (hb_set_get_population (set) == 0))
{ {
if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size))) if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
...@@ -580,6 +582,8 @@ struct Subrs : CFFIndex<COUNT> ...@@ -580,6 +582,8 @@ struct Subrs : CFFIndex<COUNT>
/* in parallel to above */ /* in parallel to above */
inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const
{ {
if (this == &Null(Subrs<COUNT>))
return 0;
unsigned int count_ = CFFIndex<COUNT>::count; unsigned int count_ = CFFIndex<COUNT>::count;
offSize = 0; offSize = 0;
if ((count_ == 0) || (hb_set_get_population (set) == 0)) if ((count_ == 0) || (hb_set_get_population (set) == 0))
......
...@@ -318,6 +318,7 @@ struct CFF2PrivateDictOpSet : DictOpSet ...@@ -318,6 +318,7 @@ struct CFF2PrivateDictOpSet : DictOpSet
return false; return false;
env.argStack.clear (); env.argStack.clear ();
break; break;
case OpCode_vsindexdict:
case OpCode_blenddict: case OpCode_blenddict:
// XXX: TODO // XXX: TODO
return true; return true;
...@@ -442,10 +443,11 @@ struct cff2 ...@@ -442,10 +443,11 @@ struct cff2
if (num_glyphs != sc.get_num_glyphs ()) if (num_glyphs != sc.get_num_glyphs ())
{ fini (); return; } { fini (); return; }
privateDicts.resize (fdArray->count); fdCount = fdArray->count;
privateDicts.resize (fdCount);
/* parse font dicts and gather private dicts */ /* 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]; const ByteStr fontDictStr = (*fdArray)[i];
if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
...@@ -500,6 +502,7 @@ struct cff2 ...@@ -500,6 +502,7 @@ struct cff2
const CFF2CharStrings *charStrings; const CFF2CharStrings *charStrings;
const CFF2FDArray *fdArray; const CFF2FDArray *fdArray;
const CFF2FDSelect *fdSelect; const CFF2FDSelect *fdSelect;
unsigned int fdCount;
hb_vector_t<CFF2FontDictValues> fontDicts; hb_vector_t<CFF2FontDictValues> fontDicts;
hb_vector_t<PrivDictVal> privateDicts; hb_vector_t<PrivDictVal> privateDicts;
......
...@@ -555,6 +555,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, ...@@ -555,6 +555,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
} }
} }
assert (c.head == c.end);
c.end_serialize (); c.end_serialize ();
return true; return true;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "hb-subset-cff2.hh" #include "hb-subset-cff2.hh"
#include "hb-subset-plan.hh" #include "hb-subset-plan.hh"
#include "hb-subset-cff-common-private.hh" #include "hb-subset-cff-common-private.hh"
#include "hb-cff2-interp-cs.hh"
using namespace CFF; using namespace CFF;
...@@ -37,6 +38,12 @@ struct CFF2SubTableOffsets { ...@@ -37,6 +38,12 @@ struct CFF2SubTableOffsets {
inline CFF2SubTableOffsets (void) inline CFF2SubTableOffsets (void)
{ {
memset (this, 0, sizeof(*this)); memset (this, 0, sizeof(*this));
localSubrsInfos.init ();
}
inline ~CFF2SubTableOffsets (void)
{
localSubrsInfos.fini ();
} }
unsigned int topDictSize; unsigned int topDictSize;
...@@ -45,6 +52,8 @@ struct CFF2SubTableOffsets { ...@@ -45,6 +52,8 @@ struct CFF2SubTableOffsets {
TableInfo FDArrayInfo; TableInfo FDArrayInfo;
TableInfo charStringsInfo; TableInfo charStringsInfo;
unsigned int privateDictsOffset; unsigned int privateDictsOffset;
TableInfo globalSubrsInfo;
hb_vector_t<TableInfo> localSubrsInfos;
}; };
struct CFF2TopDict_OpSerializer : OpSerializer struct CFF2TopDict_OpSerializer : OpSerializer
...@@ -157,6 +166,31 @@ struct CFF2PrivateDict_OpSerializer : OpSerializer ...@@ -157,6 +166,31 @@ struct CFF2PrivateDict_OpSerializer : OpSerializer
} }
}; };
struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<SubrRefMapPair>
{
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<SubrRefMapPair>::process_op (op, env, refMapPair);
}
};
struct cff2_subset_plan { struct cff2_subset_plan {
inline cff2_subset_plan (void) inline cff2_subset_plan (void)
: final_size (0), : final_size (0),
...@@ -176,6 +210,7 @@ struct cff2_subset_plan { ...@@ -176,6 +210,7 @@ struct cff2_subset_plan {
fdmap.fini (); fdmap.fini ();
subset_charstrings.fini (); subset_charstrings.fini ();
privateDictInfos.fini (); privateDictInfos.fini ();
subrRefMaps.fini ();
} }
inline bool create (const OT::cff2::accelerator_subset_t &acc, inline bool create (const OT::cff2::accelerator_subset_t &acc,
...@@ -194,8 +229,22 @@ struct cff2_subset_plan { ...@@ -194,8 +229,22 @@ struct cff2_subset_plan {
final_size += offsets.topDictSize; final_size += offsets.topDictSize;
} }
/* Subset global & local subrs */
{
SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubrSubset> 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 */ /* global subrs */
final_size += acc.globalSubrs->get_size (); offsets.globalSubrsInfo.offset = final_size;
final_size += offsets.globalSubrsInfo.size;
/* variation store */ /* variation store */
if (acc.varStore != &Null(CFF2VariationStore)) if (acc.varStore != &Null(CFF2VariationStore))
...@@ -253,7 +302,7 @@ struct cff2_subset_plan { ...@@ -253,7 +302,7 @@ struct cff2_subset_plan {
CFF2PrivateDict_OpSerializer privSzr; CFF2PrivateDict_OpSerializer privSzr;
TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr), 0 }; TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr), 0 };
privateDictInfos.push (privInfo); 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 { ...@@ -275,6 +324,8 @@ struct cff2_subset_plan {
hb_vector_t<ByteStr> subset_charstrings; hb_vector_t<ByteStr> subset_charstrings;
hb_vector_t<TableInfo> privateDictInfos; hb_vector_t<TableInfo> privateDictInfos;
SubrRefMaps subrRefMaps;
}; };
static inline bool _write_cff2 (const cff2_subset_plan &plan, static inline bool _write_cff2 (const cff2_subset_plan &plan,
...@@ -312,8 +363,7 @@ 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); assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
CFF2Subrs *dest = c.start_embed<CFF2Subrs> (); CFF2Subrs *dest = c.start_embed<CFF2Subrs> ();
if (unlikely (dest == nullptr)) return false; if (unlikely (dest == nullptr)) return false;
CFFIndex<HBUINT32> *super = dest; if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map)))
if (unlikely (!super->serialize (&c, *acc.globalSubrs)))
{ {
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs"); DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs");
return false; return false;
...@@ -409,8 +459,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, ...@@ -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); DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
return false; return false;
} }
CFFIndex<HBUINT32> *super = subrs; if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i])))
if (unlikely (!super->serialize (&c, *acc.privateDicts[i].localSubrs)))
{ {
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i); DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i);
return false; return false;
...@@ -419,6 +468,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan, ...@@ -419,6 +468,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
} }
} }
assert (c.head == c.end);
c.end_serialize (); c.end_serialize ();
return true; return true;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册