CFF2 subroutine flattner
Factored out CFF1 & CFF2 common subsetting code in hb-subset-cff-common.hh
This commit is contained in:
parent
b95bf075d7
commit
9fd08cc238
|
@ -54,6 +54,15 @@ struct CFF2CSInterpEnv : CSInterpEnv<CFF2Subrs>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool process_vsindex (void)
|
||||||
|
{
|
||||||
|
unsigned int index;
|
||||||
|
if (unlikely (!argStack.check_pop_uint (index)))
|
||||||
|
return false;
|
||||||
|
set_ivs (index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
inline unsigned int get_ivs (void) const { return ivs; }
|
inline unsigned int get_ivs (void) const { return ivs; }
|
||||||
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
|
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
|
||||||
|
|
||||||
|
@ -69,16 +78,11 @@ struct CFF2CSOpSet : CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|
||||||
case OpCode_blendcs:
|
case OpCode_blendcs:
|
||||||
//env.flush_stack (); // XXX: TODO
|
return OPSET::process_blend (env, param);
|
||||||
break;
|
|
||||||
case OpCode_vsindexcs:
|
case OpCode_vsindexcs:
|
||||||
{
|
return OPSET::process_vsindex (env, param);
|
||||||
unsigned int ivs;
|
|
||||||
if (unlikely (!env.argStack.check_pop_uint (ivs))) return false;
|
|
||||||
env.set_ivs (ivs);
|
|
||||||
//env.flush_stack ();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
typedef CSOpSet<OPSET, CFF2CSInterpEnv, PARAM> SUPER;
|
typedef CSOpSet<OPSET, CFF2CSInterpEnv, PARAM> SUPER;
|
||||||
if (unlikely (!SUPER::process_op (op, env, param)))
|
if (unlikely (!SUPER::process_op (op, env, param)))
|
||||||
|
@ -87,6 +91,18 @@ struct CFF2CSOpSet : CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool process_blend (CFF2CSInterpEnv &env, PARAM& param)
|
||||||
|
{
|
||||||
|
// XXX: TODO leave default values?
|
||||||
|
OPSET::flush_stack (env, param);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool process_vsindex (CFF2CSInterpEnv &env, PARAM& param)
|
||||||
|
{
|
||||||
|
return env.process_vsindex ();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename OPSET, typename PARAM>
|
template <typename OPSET, typename PARAM>
|
||||||
|
|
|
@ -98,6 +98,160 @@ struct ByteStrBuffArray : hb_vector_t<ByteStrBuff, 1>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CFFSubTableOffsets {
|
||||||
|
inline CFFSubTableOffsets (void)
|
||||||
|
: privateDictsOffset (0)
|
||||||
|
|
||||||
|
{
|
||||||
|
topDictInfo.init ();
|
||||||
|
FDSelectInfo.init ();
|
||||||
|
FDArrayInfo.init ();
|
||||||
|
charStringsInfo.init ();
|
||||||
|
globalSubrsInfo.init ();
|
||||||
|
localSubrsInfos.init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~CFFSubTableOffsets (void)
|
||||||
|
{
|
||||||
|
localSubrsInfos.fini ();
|
||||||
|
}
|
||||||
|
|
||||||
|
TableInfo topDictInfo;
|
||||||
|
TableInfo FDSelectInfo;
|
||||||
|
TableInfo FDArrayInfo;
|
||||||
|
TableInfo charStringsInfo;
|
||||||
|
unsigned int privateDictsOffset;
|
||||||
|
TableInfo globalSubrsInfo;
|
||||||
|
hb_vector_t<TableInfo> localSubrsInfos;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CFFTopDict_OpSerializer : OpSerializer
|
||||||
|
{
|
||||||
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
|
const OpStr &opstr,
|
||||||
|
const CFFSubTableOffsets &offsets) const
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
|
||||||
|
switch (opstr.op)
|
||||||
|
{
|
||||||
|
case OpCode_CharStrings:
|
||||||
|
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
|
||||||
|
|
||||||
|
case OpCode_FDArray:
|
||||||
|
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
|
||||||
|
|
||||||
|
case OpCode_FDSelect:
|
||||||
|
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
|
||||||
|
|
||||||
|
default:
|
||||||
|
return_trace (copy_opstr (c, opstr));
|
||||||
|
}
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||||
|
{
|
||||||
|
switch (opstr.op)
|
||||||
|
{
|
||||||
|
case OpCode_CharStrings:
|
||||||
|
case OpCode_FDArray:
|
||||||
|
case OpCode_FDSelect:
|
||||||
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return opstr.str.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CFFFontDict_OpSerializer : OpSerializer
|
||||||
|
{
|
||||||
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
|
const OpStr &opstr,
|
||||||
|
const TableInfo &privateDictInfo) const
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
|
||||||
|
if (opstr.op == OpCode_Private)
|
||||||
|
{
|
||||||
|
/* serialize the private dict size as a 2-byte integer */
|
||||||
|
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size)))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
/* serialize the private dict offset as a 4-byte integer */
|
||||||
|
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
/* serialize the opcode */
|
||||||
|
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
||||||
|
if (unlikely (p == nullptr)) return_trace (false);
|
||||||
|
p->set (OpCode_Private);
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
|
||||||
|
if (unlikely (d == nullptr)) return_trace (false);
|
||||||
|
memcpy (d, &opstr.str.str[0], opstr.str.len);
|
||||||
|
}
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||||
|
{
|
||||||
|
if (opstr.op == OpCode_Private)
|
||||||
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
||||||
|
else
|
||||||
|
return opstr.str.len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CFFPrivateDict_OpSerializer : OpSerializer
|
||||||
|
{
|
||||||
|
inline CFFPrivateDict_OpSerializer (bool drop_hints_=false, bool flatten_subrs_=false)
|
||||||
|
: drop_hints (drop_hints_), flatten_subrs (flatten_subrs_) {}
|
||||||
|
|
||||||
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
|
const OpStr &opstr,
|
||||||
|
const unsigned int subrsOffset) const
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
|
||||||
|
if (drop_hints && DictOpSet::is_hint_op (opstr.op))
|
||||||
|
return true;
|
||||||
|
if (opstr.op == OpCode_Subrs)
|
||||||
|
{
|
||||||
|
if (flatten_subrs)
|
||||||
|
return_trace (true);
|
||||||
|
else
|
||||||
|
return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return_trace (copy_opstr (c, opstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||||
|
{
|
||||||
|
if (drop_hints && DictOpSet::is_hint_op (opstr.op))
|
||||||
|
return 0;
|
||||||
|
if (opstr.op == OpCode_Subrs)
|
||||||
|
{
|
||||||
|
if (flatten_subrs)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return opstr.str.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const bool drop_hints;
|
||||||
|
const bool flatten_subrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename ACCESSOR, typename ENV, typename OPSET>
|
template <typename ACCESSOR, typename ENV, typename OPSET>
|
||||||
struct SubrFlattener
|
struct SubrFlattener
|
||||||
|
|
|
@ -34,32 +34,26 @@
|
||||||
|
|
||||||
using namespace CFF;
|
using namespace CFF;
|
||||||
|
|
||||||
struct CFF1SubTableOffsets {
|
struct CFF1SubTableOffsets : CFFSubTableOffsets
|
||||||
|
{
|
||||||
inline CFF1SubTableOffsets (void)
|
inline CFF1SubTableOffsets (void)
|
||||||
|
: CFFSubTableOffsets (),
|
||||||
|
nameIndexOffset (0),
|
||||||
|
stringIndexOffset (0),
|
||||||
|
encodingOffset (0),
|
||||||
|
charsetOffset (0)
|
||||||
{
|
{
|
||||||
memset (this, 0, sizeof(*this));
|
privateDictInfo.init ();
|
||||||
localSubrsInfos.init ();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~CFF1SubTableOffsets (void)
|
|
||||||
{
|
|
||||||
localSubrsInfos.fini ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int nameIndexOffset;
|
unsigned int nameIndexOffset;
|
||||||
TableInfo topDictInfo;
|
|
||||||
unsigned int stringIndexOffset;
|
unsigned int stringIndexOffset;
|
||||||
TableInfo globalSubrsInfo;
|
|
||||||
unsigned int encodingOffset;
|
unsigned int encodingOffset;
|
||||||
unsigned int charsetOffset;
|
unsigned int charsetOffset;
|
||||||
TableInfo FDSelectInfo;
|
|
||||||
TableInfo FDArrayInfo;
|
|
||||||
TableInfo charStringsInfo;
|
|
||||||
TableInfo privateDictInfo;
|
TableInfo privateDictInfo;
|
||||||
hb_vector_t<TableInfo> localSubrsInfos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF1TopDict_OpSerializer : OpSerializer
|
struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer
|
||||||
{
|
{
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
const OpStr &opstr,
|
const OpStr &opstr,
|
||||||
|
@ -75,15 +69,6 @@ struct CFF1TopDict_OpSerializer : OpSerializer
|
||||||
case OpCode_Encoding:
|
case OpCode_Encoding:
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset));
|
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset));
|
||||||
|
|
||||||
case OpCode_CharStrings:
|
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
|
|
||||||
|
|
||||||
case OpCode_FDArray:
|
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
|
|
||||||
|
|
||||||
case OpCode_FDSelect:
|
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
|
|
||||||
|
|
||||||
case OpCode_Private:
|
case OpCode_Private:
|
||||||
{
|
{
|
||||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size)))
|
if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size)))
|
||||||
|
@ -97,7 +82,7 @@ struct CFF1TopDict_OpSerializer : OpSerializer
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return_trace (copy_opstr (c, opstr));
|
return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets));
|
||||||
}
|
}
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
@ -108,107 +93,17 @@ struct CFF1TopDict_OpSerializer : OpSerializer
|
||||||
{
|
{
|
||||||
case OpCode_charset:
|
case OpCode_charset:
|
||||||
case OpCode_Encoding:
|
case OpCode_Encoding:
|
||||||
case OpCode_CharStrings:
|
|
||||||
case OpCode_FDArray:
|
|
||||||
case OpCode_FDSelect:
|
|
||||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
||||||
|
|
||||||
case OpCode_Private:
|
case OpCode_Private:
|
||||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return opstr.str.len;
|
return CFFTopDict_OpSerializer::calculate_serialized_size (opstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF1FontDict_OpSerializer : OpSerializer
|
|
||||||
{
|
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
|
||||||
const OpStr &opstr,
|
|
||||||
const TableInfo &privateDictInfo) const
|
|
||||||
{
|
|
||||||
TRACE_SERIALIZE (this);
|
|
||||||
|
|
||||||
if (opstr.op == OpCode_Private)
|
|
||||||
{
|
|
||||||
/* serialize the private dict size as a 2-byte integer */
|
|
||||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size)))
|
|
||||||
return_trace (false);
|
|
||||||
|
|
||||||
/* serialize the private dict offset as a 4-byte integer */
|
|
||||||
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
|
|
||||||
return_trace (false);
|
|
||||||
|
|
||||||
/* serialize the opcode */
|
|
||||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
|
||||||
if (unlikely (p == nullptr)) return_trace (false);
|
|
||||||
p->set (OpCode_Private);
|
|
||||||
|
|
||||||
return_trace (true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
|
|
||||||
if (unlikely (d == nullptr)) return_trace (false);
|
|
||||||
memcpy (d, &opstr.str.str[0], opstr.str.len);
|
|
||||||
}
|
|
||||||
return_trace (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
|
||||||
{
|
|
||||||
if (opstr.op == OpCode_Private)
|
|
||||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
|
||||||
else
|
|
||||||
return opstr.str.len;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CFF1PrivateDict_OpSerializer : OpSerializer
|
|
||||||
{
|
|
||||||
inline CFF1PrivateDict_OpSerializer (bool drop_hints_=false, bool flatten_subrs_=false)
|
|
||||||
: drop_hints (drop_hints_), flatten_subrs (flatten_subrs_) {}
|
|
||||||
|
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
|
||||||
const OpStr &opstr,
|
|
||||||
const unsigned int subrsOffset) const
|
|
||||||
{
|
|
||||||
TRACE_SERIALIZE (this);
|
|
||||||
|
|
||||||
if (drop_hints && DictOpSet::is_hint_op (opstr.op))
|
|
||||||
return true;
|
|
||||||
if (opstr.op == OpCode_Subrs)
|
|
||||||
{
|
|
||||||
if (flatten_subrs)
|
|
||||||
return_trace (true);
|
|
||||||
else
|
|
||||||
return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return_trace (copy_opstr (c, opstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
|
||||||
{
|
|
||||||
if (drop_hints && DictOpSet::is_hint_op (opstr.op))
|
|
||||||
return 0;
|
|
||||||
if (opstr.op == OpCode_Subrs)
|
|
||||||
{
|
|
||||||
if (flatten_subrs)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return opstr.str.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const bool drop_hints;
|
|
||||||
const bool flatten_subrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff>
|
struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff>
|
||||||
{
|
{
|
||||||
static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
|
static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
|
||||||
|
@ -387,7 +282,7 @@ struct cff_subset_plan {
|
||||||
/* FDArray (FDIndex) */
|
/* FDArray (FDIndex) */
|
||||||
if (acc.fdArray != &Null(CFF1FDArray)) {
|
if (acc.fdArray != &Null(CFF1FDArray)) {
|
||||||
offsets.FDArrayInfo.offset = final_size;
|
offsets.FDArrayInfo.offset = final_size;
|
||||||
CFF1FontDict_OpSerializer fontSzr;
|
CFFFontDict_OpSerializer fontSzr;
|
||||||
final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +317,7 @@ struct cff_subset_plan {
|
||||||
if (!fdmap.excludes (i))
|
if (!fdmap.excludes (i))
|
||||||
{
|
{
|
||||||
unsigned int priv_size;
|
unsigned int priv_size;
|
||||||
CFF1PrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
|
CFFPrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
|
||||||
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
||||||
TableInfo privInfo = { final_size, priv_size, 0 };
|
TableInfo privInfo = { final_size, priv_size, 0 };
|
||||||
privateDictInfos.push (privInfo);
|
privateDictInfos.push (privInfo);
|
||||||
|
@ -594,7 +489,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||||
assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
|
assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
|
||||||
CFF1FDArray *fda = c.start_embed<CFF1FDArray> ();
|
CFF1FDArray *fda = c.start_embed<CFF1FDArray> ();
|
||||||
if (unlikely (fda == nullptr)) return false;
|
if (unlikely (fda == nullptr)) return false;
|
||||||
CFF1FontDict_OpSerializer fontSzr;
|
CFFFontDict_OpSerializer fontSzr;
|
||||||
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
|
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
|
||||||
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
||||||
fontSzr, plan.privateDictInfos)))
|
fontSzr, plan.privateDictInfos)))
|
||||||
|
@ -626,7 +521,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||||
if (unlikely (pd == nullptr)) return false;
|
if (unlikely (pd == nullptr)) return false;
|
||||||
unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size;
|
unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size;
|
||||||
bool result;
|
bool result;
|
||||||
CFF1PrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
|
CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
|
||||||
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
|
/* 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);
|
result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
|
||||||
if (unlikely (!result))
|
if (unlikely (!result))
|
||||||
|
|
|
@ -34,29 +34,17 @@
|
||||||
|
|
||||||
using namespace CFF;
|
using namespace CFF;
|
||||||
|
|
||||||
struct CFF2SubTableOffsets {
|
struct CFF2SubTableOffsets : CFFSubTableOffsets
|
||||||
|
{
|
||||||
inline CFF2SubTableOffsets (void)
|
inline CFF2SubTableOffsets (void)
|
||||||
{
|
: CFFSubTableOffsets (),
|
||||||
memset (this, 0, sizeof(*this));
|
varStoreOffset (0)
|
||||||
localSubrsInfos.init ();
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
inline ~CFF2SubTableOffsets (void)
|
|
||||||
{
|
|
||||||
localSubrsInfos.fini ();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int topDictSize;
|
|
||||||
unsigned int varStoreOffset;
|
unsigned int varStoreOffset;
|
||||||
TableInfo FDSelectInfo;
|
|
||||||
TableInfo FDArrayInfo;
|
|
||||||
TableInfo charStringsInfo;
|
|
||||||
unsigned int privateDictsOffset;
|
|
||||||
TableInfo globalSubrsInfo;
|
|
||||||
hb_vector_t<TableInfo> localSubrsInfos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF2TopDict_OpSerializer : OpSerializer
|
struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer
|
||||||
{
|
{
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
const OpStr &opstr,
|
const OpStr &opstr,
|
||||||
|
@ -69,19 +57,9 @@ struct CFF2TopDict_OpSerializer : OpSerializer
|
||||||
case OpCode_vstore:
|
case OpCode_vstore:
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
|
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
|
||||||
|
|
||||||
case OpCode_CharStrings:
|
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset));
|
|
||||||
|
|
||||||
case OpCode_FDArray:
|
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset));
|
|
||||||
|
|
||||||
case OpCode_FDSelect:
|
|
||||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return_trace (copy_opstr (c, opstr));
|
return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets));
|
||||||
}
|
}
|
||||||
return_trace (true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||||
|
@ -89,102 +67,64 @@ struct CFF2TopDict_OpSerializer : OpSerializer
|
||||||
switch (opstr.op)
|
switch (opstr.op)
|
||||||
{
|
{
|
||||||
case OpCode_vstore:
|
case OpCode_vstore:
|
||||||
case OpCode_CharStrings:
|
|
||||||
case OpCode_FDArray:
|
|
||||||
case OpCode_FDSelect:
|
|
||||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return opstr.str.len;
|
return CFFTopDict_OpSerializer::calculate_serialized_size (opstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF2FontDict_OpSerializer : OpSerializer
|
struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, ByteStrBuff>
|
||||||
{
|
{
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, ByteStrBuff& flatStr)
|
||||||
const OpStr &opstr,
|
|
||||||
const TableInfo& privDictInfo) const
|
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
if (unlikely (!SUPER::process_op (op, env, flatStr)))
|
||||||
|
return false;
|
||||||
if (opstr.op == OpCode_Private)
|
switch (op)
|
||||||
{
|
{
|
||||||
/* serialize the private dict size as a 2-byte integer */
|
case OpCode_hintmask:
|
||||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privDictInfo.size)))
|
case OpCode_cntrmask:
|
||||||
return_trace (false);
|
if (unlikely (!flatStr.encode_op (op)))
|
||||||
|
return false;
|
||||||
/* serialize the private dict offset as a 4-byte integer */
|
for (int i = -env.hintmask_size; i < 0; i++)
|
||||||
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privDictInfo.offset)))
|
if (unlikely (!flatStr.encode_byte (env.substr[i])))
|
||||||
return_trace (false);
|
return false;
|
||||||
|
break;
|
||||||
/* serialize the opcode */
|
case OpCode_return:
|
||||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
case OpCode_endchar:
|
||||||
if (unlikely (p == nullptr)) return_trace (false);
|
/* dummy opcodes in CFF2. ignore */
|
||||||
p->set (OpCode_Private);
|
break;
|
||||||
|
default:
|
||||||
return_trace (true);
|
if (!CSOPSET::is_subr_op (op) &&
|
||||||
|
!CSOPSET::is_arg_op (op))
|
||||||
|
return flatStr.encode_op (op);
|
||||||
}
|
}
|
||||||
else
|
return true;
|
||||||
{
|
|
||||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
|
|
||||||
if (unlikely (d == nullptr)) return_trace (false);
|
|
||||||
memcpy (d, &opstr.str.str[0], opstr.str.len);
|
|
||||||
}
|
|
||||||
return_trace (true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
static inline bool process_blend (CFF2CSInterpEnv &env, ByteStrBuff& flatStr)
|
||||||
{
|
{
|
||||||
if (opstr.op == OpCode_Private)
|
flush_stack (env, flatStr);
|
||||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
return true;
|
||||||
else
|
|
||||||
return opstr.str.len;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct CFF2PrivateDict_OpSerializer : OpSerializer
|
static inline bool process_vsindex (CFF2CSInterpEnv &env, ByteStrBuff& flatStr)
|
||||||
{
|
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
|
||||||
const OpStr &opstr,
|
|
||||||
const unsigned int subrsOffset) const
|
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
flush_stack (env, flatStr);
|
||||||
|
return true;
|
||||||
if (opstr.op == OpCode_Subrs)
|
|
||||||
return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
|
|
||||||
else
|
|
||||||
return_trace (copy_opstr (c, opstr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
static inline void flush_stack (CFF2CSInterpEnv &env, ByteStrBuff& flatStr)
|
||||||
{
|
{
|
||||||
if (opstr.op == OpCode_Subrs)
|
for (unsigned int i = 0; i < env.argStack.size; i++)
|
||||||
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
flatStr.encode_num (env.argStack.elements[i]);
|
||||||
else
|
SUPER::flush_stack (env, flatStr);
|
||||||
return opstr.str.len;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CFF2PrivateDict_OpSerializer_DropHints : CFF2PrivateDict_OpSerializer
|
|
||||||
{
|
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
|
||||||
const OpStr &opstr,
|
|
||||||
const unsigned int subrsOffset) const
|
|
||||||
{
|
|
||||||
if (DictOpSet::is_hint_op (opstr.op))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return CFF2PrivateDict_OpSerializer::serialize (c, opstr, subrsOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
private:
|
||||||
{
|
typedef CFF2CSOpSet<CFF2CSOpSet_Flatten, ByteStrBuff> SUPER;
|
||||||
if (DictOpSet::is_hint_op (opstr.op))
|
typedef CSOpSet<CFF2CSOpSet_Flatten, CFF2CSInterpEnv, ByteStrBuff> CSOPSET;
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return CFF2PrivateDict_OpSerializer::calculate_serialized_size (opstr);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF2CSOpSet_SubsetSubrs : CFF2CSOpSet<CFF2CSOpSet_SubsetSubrs, SubrRefMapPair>
|
struct CFF2CSOpSet_SubsetSubrs : CFF2CSOpSet<CFF2CSOpSet_SubsetSubrs, SubrRefMapPair>
|
||||||
|
@ -217,11 +157,14 @@ struct cff2_subset_plan {
|
||||||
: final_size (0),
|
: final_size (0),
|
||||||
orig_fdcount (0),
|
orig_fdcount (0),
|
||||||
subst_fdcount(1),
|
subst_fdcount(1),
|
||||||
subst_fdselect_format (0)
|
subst_fdselect_format (0),
|
||||||
|
flatten_subrs (true),
|
||||||
|
drop_hints (false)
|
||||||
{
|
{
|
||||||
subst_fdselect_first_glyphs.init ();
|
subst_fdselect_first_glyphs.init ();
|
||||||
fdmap.init ();
|
fdmap.init ();
|
||||||
subset_charstrings.init ();
|
subset_charstrings.init ();
|
||||||
|
flat_charstrings.init ();
|
||||||
privateDictInfos.init ();
|
privateDictInfos.init ();
|
||||||
subrRefMaps.init ();
|
subrRefMaps.init ();
|
||||||
}
|
}
|
||||||
|
@ -231,6 +174,7 @@ struct cff2_subset_plan {
|
||||||
subst_fdselect_first_glyphs.fini ();
|
subst_fdselect_first_glyphs.fini ();
|
||||||
fdmap.fini ();
|
fdmap.fini ();
|
||||||
subset_charstrings.fini ();
|
subset_charstrings.fini ();
|
||||||
|
flat_charstrings.fini ();
|
||||||
privateDictInfos.fini ();
|
privateDictInfos.fini ();
|
||||||
subrRefMaps.fini ();
|
subrRefMaps.fini ();
|
||||||
}
|
}
|
||||||
|
@ -249,12 +193,23 @@ struct cff2_subset_plan {
|
||||||
/* top dict */
|
/* top dict */
|
||||||
{
|
{
|
||||||
CFF2TopDict_OpSerializer topSzr;
|
CFF2TopDict_OpSerializer topSzr;
|
||||||
offsets.topDictSize = TopDict::calculate_serialized_size (acc.topDict, topSzr);
|
offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr);
|
||||||
final_size += offsets.topDictSize;
|
final_size += offsets.topDictInfo.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Subset global & local subrs */
|
if (flatten_subrs)
|
||||||
{
|
{
|
||||||
|
/* Flatten global & local subrs */
|
||||||
|
SubrFlattener<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_Flatten> flattener(acc, plan->glyphs);
|
||||||
|
if (!flattener.flatten (flat_charstrings))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* no global/local subroutines */
|
||||||
|
offsets.globalSubrsInfo.size = HBUINT32::static_size; /* count 0 only */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Subset global & local subrs */
|
||||||
SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
|
SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
|
||||||
if (!subsetter.collect_refs (subrRefMaps))
|
if (!subsetter.collect_refs (subrRefMaps))
|
||||||
return false;
|
return false;
|
||||||
|
@ -299,7 +254,7 @@ struct cff2_subset_plan {
|
||||||
/* FDArray (FDIndex) */
|
/* FDArray (FDIndex) */
|
||||||
{
|
{
|
||||||
offsets.FDArrayInfo.offset = final_size;
|
offsets.FDArrayInfo.offset = final_size;
|
||||||
CFF2FontDict_OpSerializer fontSzr;
|
CFFFontDict_OpSerializer fontSzr;
|
||||||
final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,9 +264,19 @@ struct cff2_subset_plan {
|
||||||
unsigned int dataSize = 0;
|
unsigned int dataSize = 0;
|
||||||
for (unsigned int i = 0; i < plan->glyphs.len; i++)
|
for (unsigned int i = 0; i < plan->glyphs.len; i++)
|
||||||
{
|
{
|
||||||
const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
|
if (flatten_subrs)
|
||||||
subset_charstrings.push (str);
|
{
|
||||||
dataSize += str.len;
|
ByteStrBuff &flatstr = flat_charstrings[i];
|
||||||
|
ByteStr str (&flatstr[0], flatstr.len);
|
||||||
|
subset_charstrings.push (str);
|
||||||
|
dataSize += flatstr.len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
|
||||||
|
subset_charstrings.push (str);
|
||||||
|
dataSize += str.len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offsets.charStringsInfo.offSize = calcOffSize (dataSize + 1);
|
offsets.charStringsInfo.offSize = calcOffSize (dataSize + 1);
|
||||||
final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
|
final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
|
||||||
|
@ -324,19 +289,13 @@ struct cff2_subset_plan {
|
||||||
if (!fdmap.excludes (i))
|
if (!fdmap.excludes (i))
|
||||||
{
|
{
|
||||||
unsigned int priv_size;
|
unsigned int priv_size;
|
||||||
if (plan->drop_hints)
|
CFFPrivateDict_OpSerializer privSzr (drop_hints, flatten_subrs);
|
||||||
{
|
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
||||||
CFF2PrivateDict_OpSerializer_DropHints privSzr_drop;
|
|
||||||
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr_drop);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CFF2PrivateDict_OpSerializer privSzr;
|
|
||||||
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
|
||||||
}
|
|
||||||
TableInfo privInfo = { final_size, priv_size, 0 };
|
TableInfo privInfo = { final_size, priv_size, 0 };
|
||||||
privateDictInfos.push (privInfo);
|
privateDictInfos.push (privInfo);
|
||||||
final_size += privInfo.size + offsets.localSubrsInfos[i].size;
|
final_size += privInfo.size;
|
||||||
|
if (!flatten_subrs)
|
||||||
|
final_size += offsets.localSubrsInfos[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,11 +315,13 @@ struct cff2_subset_plan {
|
||||||
|
|
||||||
FDMap fdmap;
|
FDMap fdmap;
|
||||||
|
|
||||||
hb_vector_t<ByteStr> subset_charstrings;
|
hb_vector_t<ByteStr> subset_charstrings;
|
||||||
hb_vector_t<TableInfo> privateDictInfos;
|
ByteStrBuffArray flat_charstrings;
|
||||||
|
hb_vector_t<TableInfo> privateDictInfos;
|
||||||
|
|
||||||
SubrRefMaps subrRefMaps;
|
SubrRefMaps subrRefMaps;
|
||||||
|
|
||||||
|
bool flatten_subrs;
|
||||||
bool drop_hints;
|
bool drop_hints;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -384,7 +345,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
/* top dict */
|
/* top dict */
|
||||||
{
|
{
|
||||||
assert (cff2->topDict == c.head - c.start);
|
assert (cff2->topDict == c.head - c.start);
|
||||||
cff2->topDictSize.set (plan.offsets.topDictSize);
|
cff2->topDictSize.set (plan.offsets.topDictInfo.size);
|
||||||
TopDict &dict = cff2 + cff2->topDict;
|
TopDict &dict = cff2 + cff2->topDict;
|
||||||
CFF2TopDict_OpSerializer topSzr;
|
CFF2TopDict_OpSerializer topSzr;
|
||||||
if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
|
if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
|
||||||
|
@ -396,7 +357,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
|
|
||||||
/* global subrs */
|
/* global subrs */
|
||||||
{
|
{
|
||||||
assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
|
assert (cff2->topDict + plan.offsets.topDictInfo.size == 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;
|
||||||
if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map)))
|
if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map)))
|
||||||
|
@ -450,7 +411,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
|
assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
|
||||||
CFF2FDArray *fda = c.start_embed<CFF2FDArray> ();
|
CFF2FDArray *fda = c.start_embed<CFF2FDArray> ();
|
||||||
if (unlikely (fda == nullptr)) return false;
|
if (unlikely (fda == nullptr)) return false;
|
||||||
CFF2FontDict_OpSerializer fontSzr;
|
CFFFontDict_OpSerializer fontSzr;
|
||||||
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
|
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
|
||||||
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
||||||
fontSzr, plan.privateDictInfos)))
|
fontSzr, plan.privateDictInfos)))
|
||||||
|
@ -482,22 +443,14 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
if (unlikely (pd == nullptr)) return false;
|
if (unlikely (pd == nullptr)) return false;
|
||||||
unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
|
unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
|
||||||
bool result;
|
bool result;
|
||||||
if (plan.drop_hints)
|
CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
|
||||||
{
|
result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
|
||||||
CFF2PrivateDict_OpSerializer_DropHints privSzr_drop;
|
|
||||||
result = pd->serialize (&c, acc.privateDicts[i], privSzr_drop, priv_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CFF2PrivateDict_OpSerializer privSzr;
|
|
||||||
result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
|
|
||||||
}
|
|
||||||
if (unlikely (!result))
|
if (unlikely (!result))
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Private Dict[%d]", i);
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Private Dict[%d]", i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (acc.privateDicts[i].subrsOffset != 0)
|
if (!plan.flatten_subrs && (acc.privateDicts[i].subrsOffset != 0))
|
||||||
{
|
{
|
||||||
CFF2Subrs *subrs = c.start_embed<CFF2Subrs> ();
|
CFF2Subrs *subrs = c.start_embed<CFF2Subrs> ();
|
||||||
if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF2Subrs))
|
if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF2Subrs))
|
||||||
|
|
Loading…
Reference in New Issue