CFF1 no-desubroutinize + no-hinting
no-desubroutinize option is disabled for now code cleanup (esp. CFF1 width handling) bug fixes & renaming
This commit is contained in:
parent
be746009e9
commit
d56e338a90
@ -448,6 +448,8 @@ struct SubByteStr
|
||||
bool error;
|
||||
};
|
||||
|
||||
typedef hb_vector_t<ByteStr> ByteStrArray;
|
||||
|
||||
/* stack */
|
||||
template <typename ELEM, int LIMIT>
|
||||
struct Stack
|
||||
@ -652,6 +654,53 @@ struct OpSerializer
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VAL>
|
||||
struct ParsedValues
|
||||
{
|
||||
inline void init (void)
|
||||
{
|
||||
opStart = 0;
|
||||
values.init ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
values.fini_deep ();
|
||||
}
|
||||
|
||||
inline void add_op (OpCode op, const SubByteStr& substr = SubByteStr ())
|
||||
{
|
||||
VAL *val = values.push ();
|
||||
val->op = op;
|
||||
assert (substr.offset >= opStart);
|
||||
val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
|
||||
opStart = substr.offset;
|
||||
}
|
||||
|
||||
inline void add_op (OpCode op, const SubByteStr& substr, const VAL &v)
|
||||
{
|
||||
VAL *val = values.push (v);
|
||||
val->op = op;
|
||||
assert (substr.offset >= opStart);
|
||||
val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
|
||||
opStart = substr.offset;
|
||||
}
|
||||
|
||||
inline bool has_op (OpCode op) const
|
||||
{
|
||||
for (unsigned int i = 0; i < get_count (); i++)
|
||||
if (get_value (i).op == op) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline unsigned get_count (void) const { return values.len; }
|
||||
inline const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
inline const VAL &operator [] (unsigned int i) const { return get_value (i); }
|
||||
|
||||
unsigned int opStart;
|
||||
hb_vector_t<VAL> values;
|
||||
};
|
||||
|
||||
template <typename ARG=Number>
|
||||
struct InterpEnv
|
||||
{
|
||||
|
@ -33,8 +33,31 @@ namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
enum CSType {
|
||||
CSType_CharString,
|
||||
CSType_GlobalSubr,
|
||||
CSType_LocalSubr
|
||||
};
|
||||
|
||||
struct CallContext
|
||||
{
|
||||
inline void init (const SubByteStr substr_=SubByteStr (), CSType type_=CSType_CharString, unsigned int subr_num_=0)
|
||||
{
|
||||
substr = substr_;
|
||||
type = type_;
|
||||
subr_num = subr_num_;
|
||||
}
|
||||
|
||||
inline void fini (void) {}
|
||||
|
||||
SubByteStr substr;
|
||||
CSType type;
|
||||
unsigned int subr_num;
|
||||
};
|
||||
|
||||
/* call stack */
|
||||
struct CallStack : Stack<SubByteStr, 10> {};
|
||||
const unsigned int kMaxCallLimit = 10;
|
||||
struct CallStack : Stack<CallContext, kMaxCallLimit> {};
|
||||
|
||||
template <typename SUBRS>
|
||||
struct BiasedSubrs
|
||||
@ -80,6 +103,7 @@ struct CSInterpEnv : InterpEnv<ARG>
|
||||
{
|
||||
InterpEnv<ARG>::init (str);
|
||||
|
||||
context.init (str, CSType_CharString);
|
||||
seen_moveto = true;
|
||||
seen_hintmask = false;
|
||||
hstem_count = 0;
|
||||
@ -114,23 +138,29 @@ struct CSInterpEnv : InterpEnv<ARG>
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool callSubr (const BiasedSubrs<SUBRS>& biasedSubrs)
|
||||
inline void callSubr (const BiasedSubrs<SUBRS>& biasedSubrs, CSType type)
|
||||
{
|
||||
unsigned int subr_num;
|
||||
|
||||
if (unlikely (!popSubrNum (biasedSubrs, subr_num)))
|
||||
return false;
|
||||
callStack.push (SUPER::substr);
|
||||
SUPER::substr = (*biasedSubrs.subrs)[subr_num];
|
||||
if (unlikely (!popSubrNum (biasedSubrs, subr_num)
|
||||
|| callStack.get_count () >= kMaxCallLimit))
|
||||
{
|
||||
SUPER::set_error ();
|
||||
return;
|
||||
}
|
||||
context.substr = SUPER::substr;
|
||||
callStack.push (context);
|
||||
|
||||
return true;
|
||||
context.init ( (*biasedSubrs.subrs)[subr_num], type, subr_num);
|
||||
SUPER::substr = context.substr;
|
||||
}
|
||||
|
||||
inline void returnFromSubr (void)
|
||||
{
|
||||
if (unlikely (SUPER::substr.in_error ()))
|
||||
SUPER::set_error ();
|
||||
SUPER::substr = callStack.pop ();
|
||||
context = callStack.pop ();
|
||||
SUPER::substr = context.substr;
|
||||
}
|
||||
|
||||
inline void determine_hintmask_size (void)
|
||||
@ -153,6 +183,7 @@ struct CSInterpEnv : InterpEnv<ARG>
|
||||
inline void moveto (const Point &pt_ ) { pt = pt_; }
|
||||
|
||||
public:
|
||||
CallContext context;
|
||||
bool endchar_flag;
|
||||
bool seen_moveto;
|
||||
bool seen_hintmask;
|
||||
@ -206,6 +237,7 @@ struct CSOpSet : OpSet<ARG>
|
||||
env.returnFromSubr ();
|
||||
break;
|
||||
case OpCode_endchar:
|
||||
OPSET::check_width (op, env, param);
|
||||
env.set_endchar (true);
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
break;
|
||||
@ -215,36 +247,42 @@ struct CSOpSet : OpSet<ARG>
|
||||
break;
|
||||
|
||||
case OpCode_callsubr:
|
||||
env.callSubr (env.localSubrs);
|
||||
env.callSubr (env.localSubrs, CSType_LocalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
env.callSubr (env.globalSubrs);
|
||||
env.callSubr (env.globalSubrs, CSType_GlobalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_hstem:
|
||||
case OpCode_hstemhm:
|
||||
OPSET::check_width (op, env, param);
|
||||
OPSET::process_hstem (op, env, param);
|
||||
break;
|
||||
case OpCode_vstem:
|
||||
case OpCode_vstemhm:
|
||||
OPSET::check_width (op, env, param);
|
||||
OPSET::process_vstem (op, env, param);
|
||||
break;
|
||||
case OpCode_hintmask:
|
||||
case OpCode_cntrmask:
|
||||
OPSET::check_width (op, env, param);
|
||||
OPSET::process_hintmask (op, env, param);
|
||||
break;
|
||||
case OpCode_rmoveto:
|
||||
OPSET::check_width (op, env, param);
|
||||
PATH::rmoveto (env, param);
|
||||
process_post_move (op, env, param);
|
||||
OPSET::process_post_move (op, env, param);
|
||||
break;
|
||||
case OpCode_hmoveto:
|
||||
OPSET::check_width (op, env, param);
|
||||
PATH::hmoveto (env, param);
|
||||
process_post_move (op, env, param);
|
||||
OPSET::process_post_move (op, env, param);
|
||||
break;
|
||||
case OpCode_vmoveto:
|
||||
OPSET::check_width (op, env, param);
|
||||
PATH::vmoveto (env, param);
|
||||
process_post_move (op, env, param);
|
||||
OPSET::process_post_move (op, env, param);
|
||||
break;
|
||||
case OpCode_rlineto:
|
||||
PATH::rlineto (env, param);
|
||||
@ -340,6 +378,9 @@ struct CSOpSet : OpSet<ARG>
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static inline void check_width (OpCode op, ENV &env, PARAM& param)
|
||||
{}
|
||||
|
||||
static inline void process_post_move (OpCode op, ENV &env, PARAM& param)
|
||||
{
|
||||
if (!env.seen_moveto)
|
||||
@ -355,15 +396,15 @@ struct CSOpSet : OpSet<ARG>
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static inline void flush_args_and_op (OpCode op, ENV &env, PARAM& param, unsigned int start_arg = 0)
|
||||
static inline void flush_args_and_op (OpCode op, ENV &env, PARAM& param)
|
||||
{
|
||||
OPSET::flush_args (env, param, start_arg);
|
||||
OPSET::flush_args (env, param);
|
||||
OPSET::flush_op (op, env, param);
|
||||
}
|
||||
|
||||
static inline void flush_args (ENV &env, PARAM& param, unsigned int start_arg = 0)
|
||||
static inline void flush_args (ENV &env, PARAM& param)
|
||||
{
|
||||
env.pop_n_args (env.argStack.get_count () - start_arg);
|
||||
env.pop_n_args (env.argStack.get_count ());
|
||||
}
|
||||
|
||||
static inline void flush_op (OpCode op, ENV &env, PARAM& param)
|
||||
@ -375,6 +416,24 @@ struct CSOpSet : OpSet<ARG>
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static inline bool is_number_op (OpCode op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_shortint:
|
||||
case OpCode_fixedcs:
|
||||
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
|
||||
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
|
||||
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
|
||||
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* 1-byte integer */
|
||||
return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef OpSet<ARG> SUPER;
|
||||
};
|
||||
|
@ -50,50 +50,7 @@ struct DictVal : OpStr
|
||||
|
||||
typedef DictVal NumDictVal;
|
||||
|
||||
template <typename VAL>
|
||||
struct DictValues
|
||||
{
|
||||
inline void init (void)
|
||||
{
|
||||
opStart = 0;
|
||||
values.init ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
values.fini_deep ();
|
||||
}
|
||||
|
||||
inline void addOp (OpCode op, const SubByteStr& substr = SubByteStr ())
|
||||
{
|
||||
VAL *val = values.push ();
|
||||
val->op = op;
|
||||
val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
|
||||
opStart = substr.offset;
|
||||
}
|
||||
|
||||
inline void addOp (OpCode op, const SubByteStr& substr, const VAL &v)
|
||||
{
|
||||
VAL *val = values.push (v);
|
||||
val->op = op;
|
||||
val->str = ByteStr (substr.str, opStart, substr.offset - opStart);
|
||||
opStart = substr.offset;
|
||||
}
|
||||
|
||||
inline bool hasOp (OpCode op) const
|
||||
{
|
||||
for (unsigned int i = 0; i < getNumValues (); i++)
|
||||
if (getValue (i).op == op) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline unsigned getNumValues (void) const { return values.len; }
|
||||
inline const VAL &getValue (unsigned int i) const { return values[i]; }
|
||||
inline const VAL &operator [] (unsigned int i) const { return getValue (i); }
|
||||
|
||||
unsigned int opStart;
|
||||
hb_vector_t<VAL> values;
|
||||
};
|
||||
template <typename VAL> struct DictValues : ParsedValues<VAL> {};
|
||||
|
||||
template <typename OPSTR=OpStr>
|
||||
struct TopDictValues : DictValues<OPSTR>
|
||||
|
@ -33,6 +33,8 @@ namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
typedef BiasedSubrs<CFF1Subrs> CFF1BiasedSubrs;
|
||||
|
||||
struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
|
||||
{
|
||||
template <typename ACC>
|
||||
@ -41,6 +43,7 @@ struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
|
||||
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
|
||||
processed_width = false;
|
||||
has_width = false;
|
||||
arg_start = 0;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
@ -48,24 +51,26 @@ struct CFF1CSInterpEnv : CSInterpEnv<Number, CFF1Subrs>
|
||||
SUPER::fini ();
|
||||
}
|
||||
|
||||
inline unsigned int check_width (void)
|
||||
inline void set_width (void)
|
||||
{
|
||||
unsigned int arg_start = 0;
|
||||
if (!processed_width)
|
||||
if (likely (!processed_width && (SUPER::argStack.get_count () > 0)))
|
||||
{
|
||||
if ((SUPER::argStack.get_count () & 1) != 0)
|
||||
{
|
||||
width = SUPER::argStack[0];
|
||||
has_width = true;
|
||||
arg_start = 1;
|
||||
}
|
||||
width = SUPER::argStack[0];
|
||||
has_width = true;
|
||||
processed_width = true;
|
||||
arg_start = 1;
|
||||
}
|
||||
return arg_start;
|
||||
}
|
||||
|
||||
inline void clear_args (void)
|
||||
{
|
||||
arg_start = 0;
|
||||
SUPER::clear_args ();
|
||||
}
|
||||
|
||||
bool processed_width;
|
||||
bool has_width;
|
||||
unsigned int arg_start;
|
||||
Number width;
|
||||
|
||||
private:
|
||||
@ -77,10 +82,45 @@ struct CFF1CSOpSet : CSOpSet<Number, OPSET, CFF1CSInterpEnv, PARAM, PATH>
|
||||
{
|
||||
/* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
|
||||
|
||||
static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param, unsigned int start_arg = 0)
|
||||
static inline void check_width (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
|
||||
{
|
||||
start_arg = env.check_width ();
|
||||
SUPER::flush_args (env, param, start_arg);
|
||||
if (!env.processed_width)
|
||||
{
|
||||
bool has_width = false;
|
||||
switch (op)
|
||||
{
|
||||
default:
|
||||
case OpCode_endchar:
|
||||
has_width = (env.argStack.get_count () > 0);
|
||||
break;
|
||||
case OpCode_hstem:
|
||||
case OpCode_hstemhm:
|
||||
case OpCode_hintmask:
|
||||
case OpCode_cntrmask:
|
||||
has_width = ((env.argStack.get_count () & 1) != 0);
|
||||
break;
|
||||
case OpCode_hmoveto:
|
||||
case OpCode_vmoveto:
|
||||
has_width = (env.argStack.get_count () > 1);
|
||||
break;
|
||||
case OpCode_rmoveto:
|
||||
has_width = (env.argStack.get_count () > 2);
|
||||
break;
|
||||
}
|
||||
if (has_width)
|
||||
{
|
||||
env.set_width ();
|
||||
OPSET::process_width (env, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void process_width (CFF1CSInterpEnv &env, PARAM& param)
|
||||
{}
|
||||
|
||||
static inline void flush_args (CFF1CSInterpEnv &env, PARAM& param)
|
||||
{
|
||||
SUPER::flush_args (env, param);
|
||||
env.clear_args (); /* pop off width */
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ struct BlendArg : Number
|
||||
};
|
||||
|
||||
typedef InterpEnv<BlendArg> BlendInterpEnv;
|
||||
typedef BiasedSubrs<CFF2Subrs> CFF2BiasedSubrs;
|
||||
|
||||
struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
|
||||
{
|
||||
|
@ -61,6 +61,18 @@ struct code_pair
|
||||
hb_codepoint_t glyph;
|
||||
};
|
||||
|
||||
typedef hb_vector_t<char, 1> StrBuff;
|
||||
struct StrBuffArray : hb_vector_t<StrBuff>
|
||||
{
|
||||
inline unsigned int total_size (void) const
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
size += (*this)[i].len;
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
/* CFF INDEX */
|
||||
template <typename COUNT>
|
||||
struct CFFIndex
|
||||
@ -95,7 +107,7 @@ struct CFFIndex
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize_,
|
||||
const hb_vector_t<ByteStr> &byteArray)
|
||||
const ByteStrArray &byteArray)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
/* serialize CFFIndex header */
|
||||
@ -126,6 +138,22 @@ struct CFFIndex
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize_,
|
||||
const StrBuffArray &buffArray)
|
||||
{
|
||||
ByteStrArray byteArray;
|
||||
byteArray.init ();
|
||||
byteArray.resize (buffArray.len);
|
||||
for (unsigned int i = 0; i < byteArray.len; i++)
|
||||
{
|
||||
byteArray[i] = ByteStr (buffArray[i].arrayZ (), buffArray[i].len);
|
||||
}
|
||||
bool result = this->serialize (c, offSize_, byteArray);
|
||||
byteArray.fini ();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void set_offset_at (unsigned int index, unsigned int offset)
|
||||
{
|
||||
HBUINT8 *p = offsets + offSize * index + offSize;
|
||||
@ -280,7 +308,7 @@ struct Dict : UnsizedByteStr
|
||||
PARAM& param)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
for (unsigned int i = 0; i < dictval.getNumValues (); i++)
|
||||
for (unsigned int i = 0; i < dictval.get_count (); i++)
|
||||
{
|
||||
if (unlikely (!opszr.serialize (c, dictval[i], param)))
|
||||
return_trace (false);
|
||||
@ -294,7 +322,7 @@ struct Dict : UnsizedByteStr
|
||||
OP_SERIALIZER& opszr)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < dictval.getNumValues (); i++)
|
||||
for (unsigned int i = 0; i < dictval.get_count (); i++)
|
||||
size += opszr.calculate_serialized_size (dictval[i]);
|
||||
return size;
|
||||
}
|
||||
@ -383,6 +411,9 @@ struct Remap : hb_vector_t<hb_codepoint_t>
|
||||
inline bool excludes (hb_codepoint_t id) const
|
||||
{ return (id < len) && ((*this)[id] == CFF_UNDEF_CODE); }
|
||||
|
||||
inline bool includes (hb_codepoint_t id) const
|
||||
{ return !excludes (id); }
|
||||
|
||||
inline hb_codepoint_t operator[] (hb_codepoint_t i) const
|
||||
{
|
||||
if (fullset ())
|
||||
@ -649,52 +680,8 @@ struct FDSelect {
|
||||
template <typename COUNT>
|
||||
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())
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (&subrs == &Null(Subrs<COUNT>))
|
||||
return_trace (true);
|
||||
if ((subrs.count == 0) || (set == nullptr) || (hb_set_is_empty (set)))
|
||||
{
|
||||
if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
|
||||
return_trace (false);
|
||||
CFFIndex<COUNT>::count.set (0);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
hb_vector_t<ByteStr> bytesArray;
|
||||
bytesArray.init ();
|
||||
if (!bytesArray.resize (subrs.count))
|
||||
return_trace (false);
|
||||
for (hb_codepoint_t i = 0; i < subrs.count; i++)
|
||||
bytesArray[i] = (hb_set_has (set, i))? subrs[i]: nullStr;
|
||||
|
||||
bool result = CFFIndex<COUNT>::serialize (c, offSize, bytesArray);
|
||||
bytesArray.fini ();
|
||||
return_trace (result);
|
||||
}
|
||||
|
||||
/* 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<COUNT>))
|
||||
return 0;
|
||||
unsigned int count_ = CFFIndex<COUNT>::count;
|
||||
offSize = 0;
|
||||
if ((count_ == 0) || (hb_set_get_population (set) == 0))
|
||||
return COUNT::static_size;
|
||||
|
||||
unsigned int dataSize = 0;
|
||||
for (hb_codepoint_t i = 0; i < count_; i++)
|
||||
{
|
||||
if (hb_set_has (set, i))
|
||||
dataSize += (*this)[i].len;
|
||||
else
|
||||
dataSize += nullStrSize;
|
||||
}
|
||||
offSize = calcOffSize(dataSize);
|
||||
return CFFIndex<COUNT>::calculate_serialized_size (offSize, count_, dataSize);
|
||||
}
|
||||
typedef COUNT count_type;
|
||||
typedef CFFIndex<COUNT> SUPER;
|
||||
};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
@ -537,7 +537,7 @@ struct CFF1StringIndex : CFF1Index
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
hb_vector_t<ByteStr> bytesArray;
|
||||
ByteStrArray bytesArray;
|
||||
bytesArray.init ();
|
||||
if (!bytesArray.resize (sidmap.get_count ()))
|
||||
return_trace (false);
|
||||
@ -757,7 +757,7 @@ struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal>
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr, val);
|
||||
dictval.add_op (op, env.substr, val);
|
||||
}
|
||||
};
|
||||
|
||||
@ -806,7 +806,7 @@ struct CFF1FontDictOpSet : DictOpSet
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr);
|
||||
dictval.add_op (op, env.substr);
|
||||
}
|
||||
};
|
||||
|
||||
@ -828,11 +828,11 @@ struct CFF1PrivateDictValues_Base : DictValues<VAL>
|
||||
inline unsigned int calculate_serialized_size (void) const
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < DictValues<VAL>::getNumValues; i++)
|
||||
if (DictValues<VAL>::getValue (i).op == OpCode_Subrs)
|
||||
for (unsigned int i = 0; i < DictValues<VAL>::get_count; i++)
|
||||
if (DictValues<VAL>::get_value (i).op == OpCode_Subrs)
|
||||
size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
||||
else
|
||||
size += DictValues<VAL>::getValue (i).str.len;
|
||||
size += DictValues<VAL>::get_value (i).str.len;
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -886,7 +886,7 @@ struct CFF1PrivateDictOpSet : DictOpSet
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr, val);
|
||||
dictval.add_op (op, env.substr, val);
|
||||
}
|
||||
};
|
||||
|
||||
@ -928,7 +928,7 @@ struct CFF1PrivateDictOpSet_Subset : DictOpSet
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr);
|
||||
dictval.add_op (op, env.substr);
|
||||
}
|
||||
};
|
||||
|
||||
@ -989,6 +989,7 @@ struct cff1
|
||||
if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
|
||||
CFF1TopDict_Interpreter top_interp;
|
||||
top_interp.env.init (topDictStr);
|
||||
topDict.init ();
|
||||
if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
|
||||
}
|
||||
|
||||
@ -1041,12 +1042,14 @@ struct cff1
|
||||
CFF1FontDict_Interpreter font_interp;
|
||||
font_interp.env.init (fontDictStr);
|
||||
font = fontDicts.push ();
|
||||
font->init ();
|
||||
if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
|
||||
PRIVDICTVAL *priv = &privateDicts[i];
|
||||
const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
|
||||
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
|
||||
DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp;
|
||||
priv_interp.env.init (privDictStr);
|
||||
priv->init ();
|
||||
if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
|
||||
|
||||
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
|
||||
@ -1064,6 +1067,7 @@ struct cff1
|
||||
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
|
||||
DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp;
|
||||
priv_interp.env.init (privDictStr);
|
||||
priv->init ();
|
||||
if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
|
||||
|
||||
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
|
||||
|
@ -153,9 +153,9 @@ struct CFF2TopDictValues : TopDictValues<>
|
||||
inline unsigned int calculate_serialized_size (void) const
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < getNumValues (); i++)
|
||||
for (unsigned int i = 0; i < get_count (); i++)
|
||||
{
|
||||
OpCode op = getValue (i).op;
|
||||
OpCode op = get_value (i).op;
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_vstore:
|
||||
@ -163,7 +163,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 (get_value (i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -183,7 +183,7 @@ struct CFF2TopDictOpSet : TopDictOpSet<>
|
||||
{
|
||||
DictVal val;
|
||||
val.init ();
|
||||
dictval.addOp (op, env.substr);
|
||||
dictval.add_op (op, env.substr);
|
||||
env.clear_args ();
|
||||
}
|
||||
break;
|
||||
@ -205,7 +205,7 @@ struct CFF2TopDictOpSet : TopDictOpSet<>
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr);
|
||||
dictval.add_op (op, env.substr);
|
||||
}
|
||||
|
||||
typedef TopDictOpSet<> SUPER;
|
||||
@ -246,7 +246,7 @@ struct CFF2FontDictOpSet : DictOpSet
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr);
|
||||
dictval.add_op (op, env.substr);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -272,11 +272,11 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
|
||||
inline unsigned int calculate_serialized_size (void) const
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < DictValues<VAL>::getNumValues; i++)
|
||||
if (DictValues<VAL>::getValue (i).op == OpCode_Subrs)
|
||||
for (unsigned int i = 0; i < DictValues<VAL>::get_count; i++)
|
||||
if (DictValues<VAL>::get_value (i).op == OpCode_Subrs)
|
||||
size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
||||
else
|
||||
size += DictValues<VAL>::getValue (i).str.len;
|
||||
size += DictValues<VAL>::get_value (i).str.len;
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -359,7 +359,7 @@ struct CFF2PrivateDictOpSet : DictOpSet
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr, val);
|
||||
dictval.add_op (op, env.substr, val);
|
||||
}
|
||||
};
|
||||
|
||||
@ -401,7 +401,7 @@ struct CFF2PrivateDictOpSet_Subset : DictOpSet
|
||||
|
||||
if (unlikely (env.in_error ())) return;
|
||||
|
||||
dictval.addOp (op, env.substr);
|
||||
dictval.add_op (op, env.substr);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -453,6 +453,7 @@ struct cff2
|
||||
if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
|
||||
CFF2TopDict_Interpreter top_interp;
|
||||
top_interp.env.init (topDictStr);
|
||||
topDict.init ();
|
||||
if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
|
||||
}
|
||||
|
||||
@ -484,12 +485,14 @@ struct cff2
|
||||
CFF2FontDict_Interpreter font_interp;
|
||||
font_interp.env.init (fontDictStr);
|
||||
font = fontDicts.push ();
|
||||
font->init ();
|
||||
if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
|
||||
|
||||
const ByteStr privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
|
||||
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
|
||||
DictInterpreter<PRIVOPSET, PRIVDICTVAL, CFF2PrivDictInterpEnv> priv_interp;
|
||||
priv_interp.env.init(privDictStr);
|
||||
privateDicts[i].init ();
|
||||
if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
|
||||
|
||||
privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (privDictStr.str, privateDicts[i].subrsOffset);
|
||||
|
@ -35,74 +35,101 @@
|
||||
namespace CFF {
|
||||
|
||||
/* Used for writing a temporary charstring */
|
||||
struct ByteStrBuff : hb_vector_t<char, 1>
|
||||
struct StrEncoder
|
||||
{
|
||||
inline bool encode_byte (unsigned char b)
|
||||
inline StrEncoder (StrBuff &buff_)
|
||||
: buff (buff_), error (false)
|
||||
{}
|
||||
|
||||
inline void reset (void)
|
||||
{
|
||||
return (push ((const char)b) != &Crap(char));
|
||||
buff.resize (0);
|
||||
}
|
||||
|
||||
inline bool encode_int (int v)
|
||||
inline void encode_byte (unsigned char b)
|
||||
{
|
||||
if (unlikely (buff.push ((const char)b) == &Crap(char)))
|
||||
set_error ();
|
||||
}
|
||||
|
||||
inline void encode_int (int v)
|
||||
{
|
||||
if ((-1131 <= v) && (v <= 1131))
|
||||
{
|
||||
if ((-107 <= v) && (v <= 107))
|
||||
return encode_byte (v + 139);
|
||||
encode_byte (v + 139);
|
||||
else if (v > 0)
|
||||
{
|
||||
v -= 108;
|
||||
return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF);
|
||||
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);
|
||||
encode_byte ((v >> 8) + OpCode_TwoByteNegInt0);
|
||||
encode_byte (v & 0xFF);
|
||||
}
|
||||
}
|
||||
if (unlikely (v < -32768))
|
||||
v = -32768;
|
||||
else if (unlikely (v > 32767))
|
||||
v = 32767;
|
||||
return encode_byte (OpCode_shortint) &&
|
||||
encode_byte ((v >> 8) & 0xFF) &&
|
||||
encode_byte (v & 0xFF);
|
||||
else
|
||||
{
|
||||
if (unlikely (v < -32768))
|
||||
v = -32768;
|
||||
else if (unlikely (v > 32767))
|
||||
v = 32767;
|
||||
encode_byte (OpCode_shortint);
|
||||
encode_byte ((v >> 8) & 0xFF);
|
||||
encode_byte (v & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool encode_num (const Number& n)
|
||||
inline void encode_num (const Number& n)
|
||||
{
|
||||
if (n.in_int_range ())
|
||||
{
|
||||
return encode_int (n.to_int ());
|
||||
encode_int (n.to_int ());
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t v = n.to_fixed ();
|
||||
return encode_byte (OpCode_fixedcs) &&
|
||||
encode_byte ((v >> 24) & 0xFF) &&
|
||||
encode_byte ((v >> 16) & 0xFF) &&
|
||||
encode_byte ((v >> 8) & 0xFF) &&
|
||||
encode_byte (v & 0xFF);
|
||||
encode_byte (OpCode_fixedcs);
|
||||
encode_byte ((v >> 24) & 0xFF);
|
||||
encode_byte ((v >> 16) & 0xFF);
|
||||
encode_byte ((v >> 8) & 0xFF);
|
||||
encode_byte (v & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool encode_op (OpCode op)
|
||||
inline void encode_op (OpCode op)
|
||||
{
|
||||
if (Is_OpCode_ESC (op))
|
||||
return encode_byte (OpCode_escape) &&
|
||||
encode_byte (Unmake_OpCode_ESC (op));
|
||||
{
|
||||
encode_byte (OpCode_escape);
|
||||
encode_byte (Unmake_OpCode_ESC (op));
|
||||
}
|
||||
else
|
||||
return encode_byte (op);
|
||||
encode_byte (op);
|
||||
}
|
||||
};
|
||||
|
||||
struct ByteStrBuffArray : hb_vector_t<ByteStrBuff, 1>
|
||||
{
|
||||
inline void fini (void)
|
||||
inline void copy_str (const ByteStr &str)
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
hb_vector_t<ByteStrBuff, 1>::operator[] (i).fini ();
|
||||
hb_vector_t<ByteStrBuff, 1>::fini ();
|
||||
unsigned int offset = buff.len;
|
||||
buff.resize (offset + str.len);
|
||||
if (unlikely (buff.len < offset + str.len))
|
||||
{
|
||||
set_error ();
|
||||
return;
|
||||
}
|
||||
memcpy (&buff[offset], &str.str[0], str.len);
|
||||
}
|
||||
|
||||
inline bool is_error (void) const { return error; }
|
||||
|
||||
protected:
|
||||
inline void set_error (void) { error = true; }
|
||||
|
||||
StrBuff &buff;
|
||||
bool error;
|
||||
};
|
||||
|
||||
struct CFFSubTableOffsets {
|
||||
@ -215,8 +242,8 @@ struct CFFFontDict_OpSerializer : OpSerializer
|
||||
|
||||
struct CFFPrivateDict_OpSerializer : OpSerializer
|
||||
{
|
||||
inline CFFPrivateDict_OpSerializer (bool drop_hints_=false)
|
||||
: drop_hints (drop_hints_) {}
|
||||
inline CFFPrivateDict_OpSerializer (bool desubroutinize_, bool drop_hints_)
|
||||
: desubroutinize (desubroutinize_), drop_hints (drop_hints_) {}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
const OpStr &opstr,
|
||||
@ -227,7 +254,12 @@ struct CFFPrivateDict_OpSerializer : OpSerializer
|
||||
if (drop_hints && DictOpSet::is_hint_op (opstr.op))
|
||||
return true;
|
||||
if (opstr.op == OpCode_Subrs)
|
||||
return_trace (true);
|
||||
{
|
||||
if (desubroutinize)
|
||||
return_trace (true);
|
||||
else
|
||||
return_trace (FontDict::serialize_offset4_op (c, opstr.op, subrsOffset));
|
||||
}
|
||||
else
|
||||
return_trace (copy_opstr (c, opstr));
|
||||
}
|
||||
@ -237,18 +269,24 @@ struct CFFPrivateDict_OpSerializer : OpSerializer
|
||||
if (drop_hints && DictOpSet::is_hint_op (opstr.op))
|
||||
return 0;
|
||||
if (opstr.op == OpCode_Subrs)
|
||||
return 0;
|
||||
{
|
||||
if (desubroutinize)
|
||||
return 0;
|
||||
else
|
||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
||||
}
|
||||
else
|
||||
return opstr.str.len;
|
||||
}
|
||||
|
||||
protected:
|
||||
const bool desubroutinize;
|
||||
const bool drop_hints;
|
||||
};
|
||||
|
||||
struct FlattenParam
|
||||
{
|
||||
ByteStrBuff &flatStr;
|
||||
StrBuff &flatStr;
|
||||
bool drop_hints;
|
||||
};
|
||||
|
||||
@ -263,7 +301,7 @@ struct SubrFlattener
|
||||
drop_hints (drop_hints_)
|
||||
{}
|
||||
|
||||
inline bool flatten (ByteStrBuffArray &flat_charstrings)
|
||||
inline bool flatten (StrBuffArray &flat_charstrings)
|
||||
{
|
||||
if (!flat_charstrings.resize (glyphs.len))
|
||||
return false;
|
||||
@ -287,6 +325,594 @@ struct SubrFlattener
|
||||
const hb_vector_t<hb_codepoint_t> &glyphs;
|
||||
bool drop_hints;
|
||||
};
|
||||
|
||||
struct SubrClosures
|
||||
{
|
||||
inline SubrClosures (void)
|
||||
: valid (false),
|
||||
global_closure (nullptr)
|
||||
{
|
||||
local_closures.init ();
|
||||
}
|
||||
|
||||
inline void init (unsigned int fd_count)
|
||||
{
|
||||
valid = true;
|
||||
global_closure = hb_set_create ();
|
||||
if (global_closure == hb_set_get_empty ())
|
||||
valid = false;
|
||||
if (!local_closures.resize (fd_count))
|
||||
valid = false;
|
||||
|
||||
for (unsigned int i = 0; i < local_closures.len; i++)
|
||||
{
|
||||
local_closures[i] = hb_set_create ();
|
||||
if (local_closures[i] == hb_set_get_empty ())
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
hb_set_destroy (global_closure);
|
||||
for (unsigned int i = 0; i < local_closures.len; i++)
|
||||
hb_set_destroy (local_closures[i]);
|
||||
local_closures.fini ();
|
||||
}
|
||||
|
||||
inline void reset (void)
|
||||
{
|
||||
hb_set_clear (global_closure);
|
||||
for (unsigned int i = 0; i < local_closures.len; i++)
|
||||
hb_set_clear (local_closures[i]);
|
||||
}
|
||||
|
||||
bool is_valid (void) const { return valid; }
|
||||
bool valid;
|
||||
hb_set_t *global_closure;
|
||||
hb_vector_t<hb_set_t *> local_closures;
|
||||
};
|
||||
|
||||
struct ParsedCSOp : OpStr
|
||||
{
|
||||
inline void init (unsigned int subr_num_ = 0)
|
||||
{
|
||||
OpStr::init ();
|
||||
flags = kDropFlag_None;
|
||||
subr_num = subr_num_;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
OpStr::fini ();
|
||||
}
|
||||
|
||||
inline bool for_keep (void) const { return (flags & kDropFlag_Keep) != 0; }
|
||||
inline bool for_drop (void) const { return (flags & kDropFlag_Drop) != 0; }
|
||||
inline void set_drop (void) { if (!for_keep ()) flags |= kDropFlag_Drop; }
|
||||
inline void set_keep (void) { flags |= kDropFlag_Keep; }
|
||||
|
||||
enum DropFlag
|
||||
{
|
||||
kDropFlag_None = 0,
|
||||
kDropFlag_Drop = 1,
|
||||
kDropFlag_Keep = 2
|
||||
};
|
||||
|
||||
unsigned int flags;
|
||||
unsigned int subr_num;
|
||||
};
|
||||
|
||||
struct ParsedCStr : ParsedValues<ParsedCSOp>
|
||||
{
|
||||
inline void init (void)
|
||||
{
|
||||
SUPER::init ();
|
||||
parsed = false;
|
||||
hint_removed = false;
|
||||
has_prefix_ = false;
|
||||
}
|
||||
|
||||
inline void add_op (OpCode op, const SubByteStr& substr)
|
||||
{
|
||||
if (!is_parsed ())
|
||||
SUPER::add_op (op, substr);
|
||||
}
|
||||
|
||||
inline void addCallOp (OpCode op, const SubByteStr& substr, unsigned int subr_num)
|
||||
{
|
||||
if (!is_parsed ())
|
||||
{
|
||||
unsigned int parsed_len = get_count ();
|
||||
if (likely (parsed_len > 0))
|
||||
values[parsed_len-1].set_drop ();
|
||||
|
||||
ParsedCSOp val;
|
||||
val.init (subr_num);
|
||||
SUPER::add_op (op, substr, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_prefix (const Number &num, OpCode op = OpCode_Invalid)
|
||||
{
|
||||
has_prefix_ = true;
|
||||
prefix_op_ = op;
|
||||
prefix_num_ = num;
|
||||
}
|
||||
|
||||
inline bool is_parsed (void) const { return parsed; }
|
||||
inline void set_parsed (void) { parsed = true; }
|
||||
inline bool is_hint_removed (void) const { return hint_removed; }
|
||||
inline void set_hint_removed (void) { hint_removed = true; }
|
||||
inline bool has_prefix (void) const { return has_prefix_; }
|
||||
inline OpCode prefix_op (void) const { return prefix_op_; }
|
||||
inline const Number &prefix_num (void) const { return prefix_num_; }
|
||||
|
||||
protected:
|
||||
bool parsed;
|
||||
bool hint_removed;
|
||||
bool has_prefix_;
|
||||
OpCode prefix_op_;
|
||||
Number prefix_num_;
|
||||
|
||||
private:
|
||||
typedef ParsedValues<ParsedCSOp> SUPER;
|
||||
};
|
||||
|
||||
struct ParsedCStrs : hb_vector_t<ParsedCStr>
|
||||
{
|
||||
inline void init (unsigned int len_ = 0)
|
||||
{
|
||||
hb_vector_t<ParsedCStr>::init ();
|
||||
resize (len_);
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
(*this)[i].init ();
|
||||
}
|
||||
};
|
||||
|
||||
struct SubrSubsetParam
|
||||
{
|
||||
inline void init (ParsedCStr *parsed_charstring_,
|
||||
ParsedCStrs *parsed_global_subrs_, ParsedCStrs *parsed_local_subrs_,
|
||||
hb_set_t *global_closure_, hb_set_t *local_closure_,
|
||||
bool drop_hints_)
|
||||
{
|
||||
parsed_charstring = parsed_charstring_;
|
||||
current_parsed_str = parsed_charstring;
|
||||
parsed_global_subrs = parsed_global_subrs_;
|
||||
parsed_local_subrs = parsed_local_subrs_;
|
||||
global_closure = global_closure_;
|
||||
local_closure = local_closure_;
|
||||
drop_hints = drop_hints_;
|
||||
}
|
||||
|
||||
template <typename ENV>
|
||||
inline void set_current_str (ENV &env)
|
||||
{
|
||||
const CallContext &context = env.context;
|
||||
|
||||
switch (context.type)
|
||||
{
|
||||
case CSType_CharString:
|
||||
current_parsed_str = parsed_charstring;
|
||||
break;
|
||||
|
||||
case CSType_LocalSubr:
|
||||
if (likely (context.subr_num < parsed_local_subrs->len))
|
||||
current_parsed_str = &(*parsed_local_subrs)[context.subr_num];
|
||||
else
|
||||
env.set_error ();
|
||||
break;
|
||||
|
||||
case CSType_GlobalSubr:
|
||||
if (likely (context.subr_num < parsed_global_subrs->len))
|
||||
current_parsed_str = &(*parsed_global_subrs)[context.subr_num];
|
||||
else
|
||||
env.set_error ();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (0);
|
||||
}
|
||||
}
|
||||
|
||||
ParsedCStr *current_parsed_str;
|
||||
|
||||
ParsedCStr *parsed_charstring;
|
||||
ParsedCStrs *parsed_global_subrs;
|
||||
ParsedCStrs *parsed_local_subrs;
|
||||
hb_set_t *global_closure;
|
||||
hb_set_t *local_closure;
|
||||
bool drop_hints;
|
||||
};
|
||||
|
||||
struct SubrRemap : Remap
|
||||
{
|
||||
inline void create (hb_set_t *closure)
|
||||
{
|
||||
/* create a remapping of subroutine numbers from old to new.
|
||||
* no optimization based on usage counts. fonttools doesn't appear doing that either.
|
||||
*/
|
||||
reset (closure->get_max () + 1);
|
||||
for (hb_codepoint_t old_num = 0; old_num < len; old_num++)
|
||||
{
|
||||
if (hb_set_has (closure, old_num))
|
||||
add (old_num);
|
||||
}
|
||||
|
||||
if (get_count () < 1240)
|
||||
bias = 107;
|
||||
else if (get_count () < 33900)
|
||||
bias = 1131;
|
||||
else
|
||||
bias = 32768;
|
||||
}
|
||||
|
||||
inline hb_codepoint_t operator[] (unsigned int old_num) const
|
||||
{
|
||||
if (old_num >= len)
|
||||
return CFF_UNDEF_CODE;
|
||||
else
|
||||
return Remap::operator[] (old_num);
|
||||
}
|
||||
|
||||
inline int biased_num (unsigned int old_num) const
|
||||
{
|
||||
return (int)(*this)[old_num] - bias;
|
||||
}
|
||||
|
||||
protected:
|
||||
int bias;
|
||||
};
|
||||
|
||||
struct SubrRemaps
|
||||
{
|
||||
inline SubrRemaps (void)
|
||||
{
|
||||
global_remap.init ();
|
||||
local_remaps.init ();
|
||||
}
|
||||
|
||||
inline ~SubrRemaps (void)
|
||||
{
|
||||
fini ();
|
||||
}
|
||||
|
||||
inline void init (unsigned int fdCount)
|
||||
{
|
||||
local_remaps.resize (fdCount);
|
||||
for (unsigned int i = 0; i < fdCount; i++)
|
||||
local_remaps[i].init ();
|
||||
}
|
||||
|
||||
inline void create (SubrClosures& closures)
|
||||
{
|
||||
global_remap.create (closures.global_closure);
|
||||
for (unsigned int i = 0; i < local_remaps.len; i++)
|
||||
local_remaps[i].create (closures.local_closures[i]);
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
global_remap.fini ();
|
||||
local_remaps.fini_deep ();
|
||||
}
|
||||
|
||||
SubrRemap global_remap;
|
||||
hb_vector_t<SubrRemap> local_remaps;
|
||||
};
|
||||
|
||||
template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET>
|
||||
struct SubrSubsetter
|
||||
{
|
||||
inline SubrSubsetter (void)
|
||||
{
|
||||
parsed_charstrings.init ();
|
||||
parsed_global_subrs.init ();
|
||||
parsed_local_subrs.init ();
|
||||
}
|
||||
|
||||
inline ~SubrSubsetter (void)
|
||||
{
|
||||
closures.fini ();
|
||||
remaps.fini ();
|
||||
parsed_charstrings.fini_deep ();
|
||||
parsed_global_subrs.fini_deep ();
|
||||
parsed_local_subrs.fini_deep ();
|
||||
}
|
||||
|
||||
/* Subroutine subsetting with --no-desubroutinize runs in phases:
|
||||
*
|
||||
* 1. execute charstrings/subroutines to determine subroutine closures
|
||||
* 2. parse out all operators and numbers
|
||||
* 3. mark hint operators and operands for removal if --no-hinting
|
||||
* 4. re-encode all charstrings and subroutines with new subroutine numbers
|
||||
*
|
||||
* Phases #1 and #2 are done at the same time in collect_subrs ().
|
||||
* Phase #3 requires walking charstrings/subroutines forward then backward (hence parsing), because
|
||||
* we can't tell if a number belongs to a hint op until we see the first moveto.
|
||||
*
|
||||
* Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
|
||||
* within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
|
||||
*/
|
||||
inline bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints)
|
||||
{
|
||||
closures.init (acc.fdCount);
|
||||
remaps.init (acc.fdCount);
|
||||
|
||||
parsed_charstrings.init (glyphs.len);
|
||||
parsed_global_subrs.init (acc.globalSubrs->count);
|
||||
parsed_local_subrs.resize (acc.fdCount);
|
||||
for (unsigned int i = 0; i < acc.fdCount; i++)
|
||||
{
|
||||
parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count);
|
||||
}
|
||||
if (unlikely (!closures.valid))
|
||||
return false;
|
||||
|
||||
/* phase 1 & 2 */
|
||||
for (unsigned int i = 0; i < glyphs.len; i++)
|
||||
{
|
||||
hb_codepoint_t glyph = glyphs[i];
|
||||
const ByteStr str = (*acc.charStrings)[glyph];
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||
|
||||
CSInterpreter<ENV, OPSET, SubrSubsetParam> interp;
|
||||
interp.env.init (str, acc, fd);
|
||||
|
||||
SubrSubsetParam param;
|
||||
param.init (&parsed_charstrings[i],
|
||||
&parsed_global_subrs, &parsed_local_subrs[fd],
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
|
||||
if (unlikely (!interp.interpret (param)))
|
||||
return false;
|
||||
|
||||
/* copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
|
||||
SUBSETTER::set_parsed_prefix (interp.env, parsed_charstrings[i]);
|
||||
}
|
||||
|
||||
if (drop_hints)
|
||||
{
|
||||
/* mark hint ops and arguments for drop */
|
||||
for (unsigned int i = 0; i < glyphs.len; i++)
|
||||
{
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
|
||||
SubrSubsetParam param;
|
||||
param.init (&parsed_charstrings[i],
|
||||
&parsed_global_subrs, &parsed_local_subrs[fd],
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
|
||||
bool seen_moveto = false;
|
||||
if (drop_hints_in_str (parsed_charstrings[i], param, seen_moveto))
|
||||
parsed_charstrings[i].set_hint_removed ();
|
||||
}
|
||||
|
||||
/* after dropping hints recreate closures from subrs actually used */
|
||||
closures.reset ();
|
||||
for (unsigned int i = 0; i < glyphs.len; i++)
|
||||
{
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
|
||||
SubrSubsetParam param;
|
||||
param.init (&parsed_charstrings[i],
|
||||
&parsed_global_subrs, &parsed_local_subrs[fd],
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
collect_subr_refs_in_str (parsed_charstrings[i], param);
|
||||
}
|
||||
}
|
||||
|
||||
remaps.create (closures);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, StrBuffArray &buffArray) const
|
||||
{
|
||||
if (unlikely (!buffArray.resize (glyphs.len)))
|
||||
return false;
|
||||
for (unsigned int i = 0; i < glyphs.len; i++)
|
||||
{
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
|
||||
if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool encode_subrs (const ParsedCStrs &subrs, const SubrRemap& remap, StrBuffArray &buffArray) const
|
||||
{
|
||||
unsigned int count = remap.get_count ();
|
||||
|
||||
if (unlikely (!buffArray.resize (count)))
|
||||
return false;
|
||||
for (unsigned int old_num = 0; old_num < subrs.len; old_num++)
|
||||
{
|
||||
hb_codepoint_t new_num = remap[old_num];
|
||||
if (new_num != CFF_UNDEF_CODE)
|
||||
{
|
||||
if (unlikely (!encode_str (subrs[old_num], 0, buffArray[new_num])))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool encode_globalsubrs (StrBuffArray &buffArray)
|
||||
{
|
||||
return encode_subrs (parsed_global_subrs, remaps.global_remap, buffArray);
|
||||
}
|
||||
|
||||
inline bool encode_localsubrs (unsigned int fd, StrBuffArray &buffArray) const
|
||||
{
|
||||
return encode_subrs (parsed_local_subrs[fd], remaps.local_remaps[fd], buffArray);
|
||||
}
|
||||
|
||||
protected:
|
||||
inline bool drop_hints_in_subr (ParsedCStr &str, unsigned int pos,
|
||||
ParsedCStrs &subrs, unsigned int subr_num,
|
||||
const SubrSubsetParam ¶m, bool &seen_moveto)
|
||||
{
|
||||
if (drop_hints_in_str (subrs[subr_num], param, seen_moveto))
|
||||
{
|
||||
/* if the first op in the subr is a hint op, then all args/ops (especially including other subr calls)
|
||||
* preceding this subr no and call op are hints */
|
||||
/* TODO CFF2 vsindex */
|
||||
for (unsigned int i = 0; i + 1 < pos; i++)
|
||||
str.values[i].set_drop ();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* returns true if it sees a hint op before moveto */
|
||||
inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam ¶m, bool &seen_moveto)
|
||||
{
|
||||
bool seen_hint = false;
|
||||
unsigned int next_check_pos = 0;
|
||||
|
||||
for (unsigned int pos = 0; pos < str.values.len; pos++)
|
||||
{
|
||||
switch (str.values[pos].op)
|
||||
{
|
||||
case OpCode_callsubr:
|
||||
seen_hint |= drop_hints_in_subr (str, pos,
|
||||
*param.parsed_local_subrs, str.values[pos].subr_num,
|
||||
param, seen_moveto);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
seen_hint |= drop_hints_in_subr (str, pos,
|
||||
*param.parsed_global_subrs, str.values[pos].subr_num,
|
||||
param, seen_moveto);
|
||||
break;
|
||||
|
||||
case OpCode_rmoveto:
|
||||
case OpCode_hmoveto:
|
||||
case OpCode_vmoveto:
|
||||
seen_moveto = true;
|
||||
break;
|
||||
|
||||
case OpCode_hintmask:
|
||||
case OpCode_cntrmask:
|
||||
if (seen_moveto)
|
||||
{
|
||||
str.values[pos].set_drop ();
|
||||
break;
|
||||
}
|
||||
HB_FALLTHROUGH;
|
||||
|
||||
case OpCode_hstemhm:
|
||||
case OpCode_vstemhm:
|
||||
case OpCode_hstem:
|
||||
case OpCode_vstem:
|
||||
seen_hint = true;
|
||||
for (unsigned int i = next_check_pos; i <= pos; i++)
|
||||
{
|
||||
/* TODO: CFF2 vsindex */
|
||||
str.values[i].set_drop ();
|
||||
}
|
||||
next_check_pos = pos + 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* NONE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return seen_hint;
|
||||
}
|
||||
|
||||
inline void collect_subr_refs_in_subr (ParsedCStr &str, unsigned int pos,
|
||||
unsigned int subr_num, ParsedCStrs &subrs,
|
||||
hb_set_t *closure,
|
||||
const SubrSubsetParam ¶m)
|
||||
{
|
||||
hb_set_add (closure, subr_num);
|
||||
collect_subr_refs_in_str (subrs[subr_num], param);
|
||||
}
|
||||
|
||||
inline void collect_subr_refs_in_str (ParsedCStr &str, const SubrSubsetParam ¶m)
|
||||
{
|
||||
for (unsigned int pos = 0; pos < str.values.len; pos++)
|
||||
{
|
||||
if (!str.values[pos].for_drop ())
|
||||
{
|
||||
switch (str.values[pos].op)
|
||||
{
|
||||
case OpCode_callsubr:
|
||||
collect_subr_refs_in_subr (str, pos,
|
||||
str.values[pos].subr_num, *param.parsed_local_subrs,
|
||||
param.local_closure, param);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
collect_subr_refs_in_subr (str, pos,
|
||||
str.values[pos].subr_num, *param.parsed_global_subrs,
|
||||
param.global_closure, param);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool encode_str (const ParsedCStr &str, const unsigned int fd, StrBuff &buff) const
|
||||
{
|
||||
buff.init ();
|
||||
StrEncoder encoder (buff);
|
||||
encoder.reset ();
|
||||
/* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
|
||||
* re-insert it at the beginning of charstreing */
|
||||
if (str.has_prefix () && str.is_hint_removed ())
|
||||
{
|
||||
encoder.encode_num (str.prefix_num ());
|
||||
if (str.prefix_op () != OpCode_Invalid)
|
||||
encoder.encode_op (str.prefix_op ());
|
||||
}
|
||||
for (unsigned int i = 0; i < str.get_count(); i++)
|
||||
{
|
||||
const ParsedCSOp &opstr = str.values[i];
|
||||
if (!opstr.for_drop ())
|
||||
{
|
||||
switch (opstr.op)
|
||||
{
|
||||
case OpCode_callsubr:
|
||||
encoder.encode_int (remaps.local_remaps[fd].biased_num (opstr.subr_num));
|
||||
encoder.encode_op (OpCode_callsubr);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
encoder.encode_int (remaps.global_remap.biased_num (opstr.subr_num));
|
||||
encoder.encode_op (OpCode_callgsubr);
|
||||
break;
|
||||
|
||||
default:
|
||||
encoder.copy_str (opstr.str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !encoder.is_error ();
|
||||
}
|
||||
|
||||
protected:
|
||||
SubrClosures closures;
|
||||
|
||||
ParsedCStrs parsed_charstrings;
|
||||
ParsedCStrs parsed_global_subrs;
|
||||
hb_vector_t<ParsedCStrs> parsed_local_subrs;
|
||||
|
||||
SubrRemaps remaps;
|
||||
|
||||
private:
|
||||
typedef typename SUBRS::count_type subr_count_type;
|
||||
};
|
||||
}; /* namespace CFF */
|
||||
|
||||
HB_INTERNAL bool
|
||||
|
@ -92,18 +92,18 @@ struct CFF1TopDictValuesMod : CFF1TopDictValues
|
||||
SUPER::fini ();
|
||||
}
|
||||
|
||||
inline unsigned getNumValues (void) const
|
||||
inline unsigned get_count (void) const
|
||||
{
|
||||
return base->getNumValues () + SUPER::getNumValues ();
|
||||
return base->get_count () + SUPER::get_count ();
|
||||
}
|
||||
inline const CFF1TopDictVal &getValue (unsigned int i) const
|
||||
inline const CFF1TopDictVal &get_value (unsigned int i) const
|
||||
{
|
||||
if (i < base->getNumValues ())
|
||||
if (i < base->get_count ())
|
||||
return (*base)[i];
|
||||
else
|
||||
return SUPER::values[i - base->getNumValues ()];
|
||||
return SUPER::values[i - base->get_count ()];
|
||||
}
|
||||
inline const CFF1TopDictVal &operator [] (unsigned int i) const { return getValue (i); }
|
||||
inline const CFF1TopDictVal &operator [] (unsigned int i) const { return get_value (i); }
|
||||
|
||||
inline void reassignSIDs (const RemapSID& sidmap)
|
||||
{
|
||||
@ -230,9 +230,9 @@ struct FontDictValuesMod
|
||||
privateDictInfo = privateDictInfo_;
|
||||
}
|
||||
|
||||
inline unsigned getNumValues (void) const
|
||||
inline unsigned get_count (void) const
|
||||
{
|
||||
return base->getNumValues ();
|
||||
return base->get_count ();
|
||||
}
|
||||
|
||||
inline const OpStr &operator [] (unsigned int i) const { return (*base)[i]; }
|
||||
@ -270,10 +270,9 @@ struct CFF1FontDict_OpSerializer : CFFFontDict_OpSerializer
|
||||
|
||||
struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
|
||||
{
|
||||
static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
|
||||
static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
start_arg = env.check_width ();
|
||||
if ((start_arg > 0) && likely (param.flatStr.len == 0))
|
||||
if (env.arg_start > 0)
|
||||
flush_width (env, param);
|
||||
|
||||
switch (op)
|
||||
@ -292,35 +291,40 @@ struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
|
||||
HB_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
SUPER::flush_args_and_op (op, env, param, start_arg);
|
||||
SUPER::flush_args_and_op (op, env, param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void flush_args (CFF1CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
|
||||
static inline void flush_args (CFF1CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
for (unsigned int i = start_arg; i < env.argStack.get_count (); i++)
|
||||
param.flatStr.encode_num (env.eval_arg (i));
|
||||
SUPER::flush_args (env, param, start_arg);
|
||||
StrEncoder encoder (param.flatStr);
|
||||
for (unsigned int i = env.arg_start; i < env.argStack.get_count (); i++)
|
||||
encoder.encode_num (env.eval_arg (i));
|
||||
SUPER::flush_args (env, param);
|
||||
}
|
||||
|
||||
static inline void flush_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
param.flatStr.encode_op (op);
|
||||
StrEncoder encoder (param.flatStr);
|
||||
encoder.encode_op (op);
|
||||
}
|
||||
|
||||
static inline void flush_width (CFF1CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
assert (env.has_width);
|
||||
param.flatStr.encode_num (env.width);
|
||||
StrEncoder encoder (param.flatStr);
|
||||
encoder.encode_num (env.width);
|
||||
}
|
||||
|
||||
static inline void flush_hintmask (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
SUPER::flush_hintmask (op, env, param);
|
||||
if (!param.drop_hints)
|
||||
{
|
||||
StrEncoder encoder (param.flatStr);
|
||||
for (unsigned int i = 0; i < env.hintmask_size; i++)
|
||||
param.flatStr.encode_byte (env.substr[i]);
|
||||
encoder.encode_byte (env.substr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -342,6 +346,70 @@ struct RangeList : hb_vector_t<code_pair>
|
||||
}
|
||||
};
|
||||
|
||||
struct CFF1CSOpSet_SubrSubset : CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetParam>
|
||||
{
|
||||
static inline void process_op (OpCode op, CFF1CSInterpEnv &env, SubrSubsetParam& param)
|
||||
{
|
||||
switch (op) {
|
||||
|
||||
case OpCode_return:
|
||||
param.current_parsed_str->add_op (op, env.substr);
|
||||
param.current_parsed_str->set_parsed ();
|
||||
env.returnFromSubr ();
|
||||
param.set_current_str (env);
|
||||
break;
|
||||
|
||||
case OpCode_endchar:
|
||||
param.current_parsed_str->add_op (op, env.substr);
|
||||
param.current_parsed_str->set_parsed ();
|
||||
SUPER::process_op (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_callsubr:
|
||||
process_call_subr (op, CSType_LocalSubr, env, param, env.localSubrs, param.local_closure);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
process_call_subr (op, CSType_GlobalSubr, env, param, env.globalSubrs, param.global_closure);
|
||||
break;
|
||||
|
||||
default:
|
||||
SUPER::process_op (op, env, param);
|
||||
param.current_parsed_str->add_op (op, env.substr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void process_width (CFF1CSInterpEnv &env, SubrSubsetParam& param)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
static inline void process_call_subr (OpCode op, CSType type,
|
||||
CFF1CSInterpEnv &env, SubrSubsetParam& param,
|
||||
CFF1BiasedSubrs& subrs, hb_set_t *closure)
|
||||
{
|
||||
SubByteStr substr = env.substr;
|
||||
env.callSubr (subrs, type);
|
||||
param.current_parsed_str->addCallOp (op, substr, env.context.subr_num);
|
||||
hb_set_add (closure, env.context.subr_num);
|
||||
param.set_current_str (env);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef CFF1CSOpSet<CFF1CSOpSet_SubrSubset, SubrSubsetParam> SUPER;
|
||||
};
|
||||
|
||||
struct CFF1SubrSubsetter : SubrSubsetter<CFF1SubrSubsetter, CFF1Subrs, const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubrSubset>
|
||||
{
|
||||
static inline void set_parsed_prefix (const CFF1CSInterpEnv &env, ParsedCStr &charstring)
|
||||
{
|
||||
if (env.processed_width)
|
||||
charstring.set_prefix (env.width);
|
||||
}
|
||||
};
|
||||
|
||||
struct cff_subset_plan {
|
||||
inline cff_subset_plan (void)
|
||||
: final_size (0),
|
||||
@ -349,7 +417,8 @@ struct cff_subset_plan {
|
||||
orig_fdcount (0),
|
||||
subset_fdcount (1),
|
||||
subset_fdselect_format (0),
|
||||
drop_hints (false)
|
||||
drop_hints (false),
|
||||
desubroutinize(false)
|
||||
{
|
||||
topdict_sizes.init ();
|
||||
topdict_sizes.resize (1);
|
||||
@ -357,7 +426,8 @@ struct cff_subset_plan {
|
||||
subset_fdselect_ranges.init ();
|
||||
fdmap.init ();
|
||||
subset_charstrings.init ();
|
||||
flat_charstrings.init ();
|
||||
subset_globalsubrs.init ();
|
||||
subset_localsubrs.init ();
|
||||
fontdicts_mod.init ();
|
||||
subset_enc_code_ranges.init ();
|
||||
subset_enc_supp_codes.init ();
|
||||
@ -374,7 +444,8 @@ struct cff_subset_plan {
|
||||
subset_fdselect_ranges.fini ();
|
||||
fdmap.fini ();
|
||||
subset_charstrings.fini ();
|
||||
flat_charstrings.fini ();
|
||||
subset_globalsubrs.fini ();
|
||||
subset_localsubrs.fini_deep ();
|
||||
fontdicts_mod.fini ();
|
||||
subset_enc_code_ranges.fini ();
|
||||
subset_enc_supp_codes.init ();
|
||||
@ -504,9 +575,9 @@ struct cff_subset_plan {
|
||||
}
|
||||
|
||||
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);
|
||||
for (unsigned int i = 0; i < orig_fdcount; i++)
|
||||
if (fdmap.includes (i))
|
||||
(void)sidmap.add (acc.fontDicts[i].fontName);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -521,6 +592,7 @@ struct cff_subset_plan {
|
||||
num_glyphs = plan->glyphs.len;
|
||||
orig_fdcount = acc.fdCount;
|
||||
drop_hints = plan->drop_hints;
|
||||
desubroutinize = true; // plan->desubroutinize;
|
||||
|
||||
/* check whether the subset renumbers any glyph IDs */
|
||||
gid_renum = false;
|
||||
@ -546,14 +618,14 @@ struct cff_subset_plan {
|
||||
{
|
||||
/* Add encoding/charset to a (copy of) top dict as necessary */
|
||||
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));
|
||||
bool need_to_add_enc = (subset_encoding && !acc.topDict.has_op (OpCode_Encoding));
|
||||
bool need_to_add_set = (subset_charset && !acc.topDict.has_op (OpCode_charset));
|
||||
if (need_to_add_enc || need_to_add_set)
|
||||
{
|
||||
if (need_to_add_enc)
|
||||
topdict_mod.addOp (OpCode_Encoding);
|
||||
topdict_mod.add_op (OpCode_Encoding);
|
||||
if (need_to_add_set)
|
||||
topdict_mod.addOp (OpCode_charset);
|
||||
topdict_mod.add_op (OpCode_charset);
|
||||
}
|
||||
offsets.topDictInfo.offset = final_size;
|
||||
CFF1TopDict_OpSerializer topSzr;
|
||||
@ -595,16 +667,54 @@ struct cff_subset_plan {
|
||||
final_size += offsets.stringIndexInfo.size;
|
||||
}
|
||||
|
||||
if (desubroutinize)
|
||||
{
|
||||
/* Flatten global & local subrs */
|
||||
SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten>
|
||||
flattener(acc, plan->glyphs, plan->drop_hints);
|
||||
if (!flattener.flatten (flat_charstrings))
|
||||
if (!flattener.flatten (subset_charstrings))
|
||||
return false;
|
||||
|
||||
/* no global/local subroutines */
|
||||
offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
|
||||
if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints))
|
||||
return false;
|
||||
|
||||
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
|
||||
if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings))
|
||||
return false;
|
||||
|
||||
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
||||
return false;
|
||||
|
||||
/* global subrs */
|
||||
unsigned int dataSize = subset_globalsubrs.total_size ();
|
||||
offsets.globalSubrsInfo.offSize = calcOffSize (dataSize);
|
||||
offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.len, dataSize);
|
||||
|
||||
/* local subrs */
|
||||
if (!offsets.localSubrsInfos.resize (orig_fdcount))
|
||||
return false;
|
||||
if (!subset_localsubrs.resize (orig_fdcount))
|
||||
return false;
|
||||
for (unsigned int fd = 0; fd < orig_fdcount; fd++)
|
||||
{
|
||||
subset_localsubrs[fd].init ();
|
||||
if (fdmap.includes (fd))
|
||||
{
|
||||
if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd]))
|
||||
return false;
|
||||
|
||||
unsigned int dataSize = subset_localsubrs[fd].total_size ();
|
||||
offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
|
||||
offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* global subrs */
|
||||
offsets.globalSubrsInfo.offset = final_size;
|
||||
@ -640,7 +750,7 @@ struct cff_subset_plan {
|
||||
CFF1FontDict_OpSerializer fontSzr;
|
||||
unsigned int dictsSize = 0;
|
||||
for (unsigned int i = 0; i < acc.fontDicts.len; i++)
|
||||
if (!fdmap.excludes (i))
|
||||
if (fdmap.includes (i))
|
||||
dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
|
||||
|
||||
offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
|
||||
@ -650,14 +760,7 @@ struct cff_subset_plan {
|
||||
/* CharStrings */
|
||||
{
|
||||
offsets.charStringsInfo.offset = final_size;
|
||||
unsigned int dataSize = 0;
|
||||
for (unsigned int i = 0; i < plan->glyphs.len; i++)
|
||||
{
|
||||
ByteStrBuff &flatstr = flat_charstrings[i];
|
||||
ByteStr str (&flatstr[0], flatstr.len);
|
||||
subset_charstrings.push (str);
|
||||
dataSize += flatstr.len;
|
||||
}
|
||||
unsigned int dataSize = subset_charstrings.total_size ();
|
||||
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
|
||||
final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
|
||||
}
|
||||
@ -666,23 +769,26 @@ struct cff_subset_plan {
|
||||
offsets.privateDictInfo.offset = final_size;
|
||||
for (unsigned int i = 0; i < orig_fdcount; i++)
|
||||
{
|
||||
if (!fdmap.excludes (i))
|
||||
if (fdmap.includes (i))
|
||||
{
|
||||
CFFPrivateDict_OpSerializer privSzr (plan->drop_hints);
|
||||
CFFPrivateDict_OpSerializer privSzr (desubroutinize, plan->drop_hints);
|
||||
unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
||||
TableInfo privInfo = { final_size, priv_size, 0 };
|
||||
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 (!plan->desubroutinize)
|
||||
final_size += offsets.localSubrsInfos[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!acc.is_CID ())
|
||||
offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
|
||||
|
||||
return ((subset_charstrings.len == plan->glyphs.len) &&
|
||||
(fontdicts_mod.len == subset_fdcount));
|
||||
return ((subset_charstrings.len == plan->glyphs.len)
|
||||
&& (fontdicts_mod.len == subset_fdcount));
|
||||
}
|
||||
|
||||
inline unsigned int get_final_size (void) const { return final_size; }
|
||||
@ -703,11 +809,11 @@ struct cff_subset_plan {
|
||||
* set to CFF_UNDEF_CODE if excluded from subset */
|
||||
Remap fdmap;
|
||||
|
||||
hb_vector_t<ByteStr> subset_charstrings;
|
||||
ByteStrBuffArray flat_charstrings;
|
||||
StrBuffArray subset_charstrings;
|
||||
StrBuffArray subset_globalsubrs;
|
||||
hb_vector_t<StrBuffArray> subset_localsubrs;
|
||||
hb_vector_t<FontDictValuesMod> fontdicts_mod;
|
||||
|
||||
bool flatten_subrs;
|
||||
bool drop_hints;
|
||||
|
||||
bool gid_renum;
|
||||
@ -723,6 +829,9 @@ struct cff_subset_plan {
|
||||
|
||||
RemapSID sidmap;
|
||||
unsigned int topDictModSIDs[NameDictValues::ValCount];
|
||||
|
||||
bool desubroutinize;
|
||||
CFF1SubrSubsetter subr_subsetter;
|
||||
};
|
||||
|
||||
static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||
@ -790,9 +899,23 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||
{
|
||||
assert (plan.offsets.globalSubrsInfo.offset != 0);
|
||||
assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
|
||||
CFF1Subrs *dest = c.allocate_size <CFF1Subrs> (HBUINT16::static_size);
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
dest->count.set (0);
|
||||
|
||||
if (plan.desubroutinize)
|
||||
{
|
||||
CFF1Subrs *dest = c.allocate_size <CFF1Subrs> (HBUINT16::static_size);
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
dest->count.set (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Encoding */
|
||||
@ -893,7 +1016,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||
if (unlikely (pd == nullptr)) return false;
|
||||
unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
|
||||
bool result;
|
||||
CFFPrivateDict_OpSerializer privSzr (plan.drop_hints);
|
||||
CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints);
|
||||
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
|
||||
result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
|
||||
if (unlikely (!result))
|
||||
@ -904,6 +1027,23 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||
}
|
||||
}
|
||||
|
||||
if (!plan.desubroutinize)
|
||||
{
|
||||
for (unsigned int i = 0; i < acc.privateDicts.len; i++)
|
||||
{
|
||||
if (!plan.fdmap.excludes (i))
|
||||
{
|
||||
CFF1Subrs *dest = c.start_embed <CFF1Subrs> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i])))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert (c.head == c.end);
|
||||
c.end_serialize ();
|
||||
|
||||
|
@ -77,7 +77,7 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer<>
|
||||
|
||||
struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
|
||||
{
|
||||
static inline void flush_args_and_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
|
||||
static inline void flush_args_and_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
@ -100,29 +100,30 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
|
||||
HB_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
SUPER::flush_args_and_op (op, env, param, start_arg);
|
||||
SUPER::flush_args_and_op (op, env, param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void flush_args (CFF2CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
|
||||
static inline void flush_args (CFF2CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
for (unsigned int i = start_arg; i < env.argStack.get_count ();)
|
||||
for (unsigned int i = 0; i < env.argStack.get_count ();)
|
||||
{
|
||||
const BlendArg &arg = env.argStack[i];
|
||||
if (arg.blending ())
|
||||
{
|
||||
assert ((arg.numValues > 0) && (env.argStack.get_count () - start_arg >= arg.numValues));
|
||||
assert ((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues));
|
||||
flatten_blends (arg, i, env, param);
|
||||
i += arg.numValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
param.flatStr.encode_num (arg);
|
||||
StrEncoder encoder (param.flatStr);
|
||||
encoder.encode_num (arg);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
SUPER::flush_args (env, param, start_arg);
|
||||
SUPER::flush_args (env, param);
|
||||
}
|
||||
|
||||
static inline void flatten_blends (const BlendArg &arg, unsigned int i, CFF2CSInterpEnv &env, FlattenParam& param)
|
||||
@ -133,20 +134,22 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
|
||||
const BlendArg &arg1 = env.argStack[i + j];
|
||||
assert (arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
|
||||
(arg1.deltas.len == env.get_region_count ()));
|
||||
param.flatStr.encode_num (arg1);
|
||||
StrEncoder encoder (param.flatStr);
|
||||
encoder.encode_num (arg1);
|
||||
}
|
||||
/* flatten deltas for each value */
|
||||
StrEncoder encoder (param.flatStr);
|
||||
for (unsigned int j = 0; j < arg.numValues; j++)
|
||||
{
|
||||
const BlendArg &arg1 = env.argStack[i + j];
|
||||
for (unsigned int k = 0; k < arg1.deltas.len; k++)
|
||||
param.flatStr.encode_num (arg1.deltas[k]);
|
||||
encoder.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);
|
||||
encoder.encode_int (arg.numValues);
|
||||
encoder.encode_op (OpCode_blendcs);
|
||||
}
|
||||
|
||||
|
||||
static inline void flush_op (OpCode op, CFF2CSInterpEnv &env, FlattenParam& param)
|
||||
{
|
||||
switch (op)
|
||||
@ -155,7 +158,8 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
|
||||
case OpCode_endchar:
|
||||
return;
|
||||
default:
|
||||
param.flatStr.encode_op (op);
|
||||
StrEncoder encoder (param.flatStr);
|
||||
encoder.encode_op (op);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,7 +174,8 @@ struct cff2_subset_plan {
|
||||
orig_fdcount (0),
|
||||
subset_fdcount(1),
|
||||
subset_fdselect_format (0),
|
||||
drop_hints (false)
|
||||
drop_hints (false),
|
||||
desubroutinize (false)
|
||||
{
|
||||
subset_fdselect_ranges.init ();
|
||||
fdmap.init ();
|
||||
@ -195,6 +200,7 @@ struct cff2_subset_plan {
|
||||
orig_fdcount = acc.fdArray->count;
|
||||
|
||||
drop_hints = plan->drop_hints;
|
||||
desubroutinize = plan->desubroutinize;
|
||||
|
||||
/* CFF2 header */
|
||||
final_size += OT::cff2::static_size;
|
||||
@ -260,7 +266,7 @@ struct cff2_subset_plan {
|
||||
unsigned int dataSize = 0;
|
||||
for (unsigned int i = 0; i < plan->glyphs.len; i++)
|
||||
{
|
||||
ByteStrBuff &flatstr = flat_charstrings[i];
|
||||
StrBuff &flatstr = flat_charstrings[i];
|
||||
ByteStr str (&flatstr[0], flatstr.len);
|
||||
subset_charstrings.push (str);
|
||||
dataSize += flatstr.len;
|
||||
@ -276,7 +282,7 @@ struct cff2_subset_plan {
|
||||
if (!fdmap.excludes (i))
|
||||
{
|
||||
unsigned int priv_size;
|
||||
CFFPrivateDict_OpSerializer privSzr (drop_hints);
|
||||
CFFPrivateDict_OpSerializer privSzr (desubroutinize, drop_hints);
|
||||
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
||||
TableInfo privInfo = { final_size, priv_size, 0 };
|
||||
privateDictInfos.push (privInfo);
|
||||
@ -300,11 +306,12 @@ struct cff2_subset_plan {
|
||||
|
||||
Remap fdmap;
|
||||
|
||||
hb_vector_t<ByteStr> subset_charstrings;
|
||||
ByteStrBuffArray flat_charstrings;
|
||||
ByteStrArray subset_charstrings;
|
||||
StrBuffArray flat_charstrings;
|
||||
hb_vector_t<TableInfo> privateDictInfos;
|
||||
|
||||
bool drop_hints;
|
||||
bool desubroutinize;
|
||||
};
|
||||
|
||||
static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||
@ -421,7 +428,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||
if (unlikely (pd == nullptr)) return false;
|
||||
unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
|
||||
bool result;
|
||||
CFFPrivateDict_OpSerializer privSzr (plan.drop_hints);
|
||||
CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints);
|
||||
result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
|
||||
if (unlikely (!result))
|
||||
{
|
||||
|
@ -44,6 +44,7 @@ struct hb_subset_input_t
|
||||
|
||||
bool drop_hints : 1;
|
||||
bool drop_layout : 1;
|
||||
bool desubroutinize : 1;
|
||||
/* TODO
|
||||
*
|
||||
* features
|
||||
|
@ -150,6 +150,7 @@ hb_subset_plan_create (hb_face_t *face,
|
||||
|
||||
plan->drop_hints = input->drop_hints;
|
||||
plan->drop_layout = input->drop_layout;
|
||||
plan->desubroutinize = input->desubroutinize;
|
||||
plan->unicodes = hb_set_create();
|
||||
plan->glyphs.init();
|
||||
plan->source = hb_face_reference (face);
|
||||
|
@ -41,6 +41,7 @@ struct hb_subset_plan_t
|
||||
|
||||
bool drop_hints : 1;
|
||||
bool drop_layout : 1;
|
||||
bool desubroutinize : 1;
|
||||
|
||||
// For each cp that we'd like to retain maps to the corresponding gid.
|
||||
hb_set_t *unicodes;
|
||||
|
@ -970,6 +970,8 @@ subset_options_t::add_options (option_parser_t *parser)
|
||||
GOptionEntry entries[] =
|
||||
{
|
||||
{"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->drop_hints, "Whether to drop hints", nullptr},
|
||||
{"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->desubroutinize, "Remove CFF/CFF2 use of subroutinizes", nullptr},
|
||||
|
||||
{nullptr}
|
||||
};
|
||||
parser->add_group (entries,
|
||||
|
@ -669,6 +669,7 @@ struct subset_options_t : option_group_t
|
||||
subset_options_t (option_parser_t *parser)
|
||||
{
|
||||
drop_hints = false;
|
||||
desubroutinize = false;
|
||||
|
||||
add_options (parser);
|
||||
}
|
||||
@ -676,6 +677,7 @@ struct subset_options_t : option_group_t
|
||||
void add_options (option_parser_t *parser);
|
||||
|
||||
hb_bool_t drop_hints;
|
||||
hb_bool_t desubroutinize;
|
||||
};
|
||||
|
||||
/* fallback implementation for scalbn()/scalbnf() for pre-2013 MSVC */
|
||||
|
Loading…
Reference in New Issue
Block a user