Subr-flattened charstrings are temporarily re-encoded in ByteStrBuff during "plan" phase, then copied to hb_serialize_context_t during "write" phase
CSOpSet may callback opcode processing "virtual" functions via CRTP
Numer struct may store a value as fixed optionally in addition to int and float
};
inline OpCode Make_OpCode_ESC (unsigned char byte2) { return (OpCode)(OpCode_ESC_Base + byte2); }
-inline unsigned int OpCode_Size (OpCode op) { return (op >= OpCode_ESC_Base)? 2: 1; }
+inline OpCode Unmake_OpCode_ESC (OpCode op) { return (OpCode)(op - OpCode_ESC_Base); }
+inline bool Is_OpCode_ESC (OpCode op) { return op >= OpCode_ESC_Base; }
+inline unsigned int OpCode_Size (OpCode op) { return Is_OpCode_ESC (op)? 2: 1; }
struct Number
{
inline Number (void) { set_int (0); }
- inline void set_int (int v) { is_real = false; u.int_val = v; };
- inline int to_int (void) const { return is_real? (int)u.real_val: u.int_val; }
- inline void set_real (float v) { is_real = true; u.real_val = v; };
- inline float to_real (void) const { return is_real? u.real_val: (float)u.int_val; }
+ inline void set_int (int v) { format = NumInt; u.int_val = v; };
+ inline int to_int (void) const { return is_int ()? u.int_val: (int)to_real (); }
+ inline void set_fixed (int32_t v) { format = NumFixed; u.fixed_val = v; };
+ inline int32_t to_fixed (void) const
+ {
+ if (is_fixed ())
+ return u.fixed_val;
+ else if (is_real ())
+ return (int32_t)(u.real_val * 65536.0);
+ else
+ return (int32_t)(u.int_val << 16);
+ }
+ inline void set_real (float v) { format = NumReal; u.real_val = v; };
+ inline float to_real (void) const
+ {
+ if (is_real ())
+ return u.real_val;
+ if (is_fixed ())
+ return u.fixed_val / 65536.0;
+ else
+ return (float)u.int_val;
+ }
+ inline bool in_int_range (void) const
+ {
+ if (is_int ())
+ return true;
+ if (is_fixed () && ((u.fixed_val & 0xFFFF) == 0))
+ return true;
+ else
+ return ((float)(int16_t)to_int () == u.real_val);
+ }
protected:
- bool is_real;
+ enum NumFormat {
+ NumInt,
+ NumFixed,
+ NumReal
+ };
+ NumFormat format;
union {
int int_val;
+ int32_t fixed_val;
float real_val;
} u;
+
+ inline bool is_int (void) const { return format == NumInt; }
+ inline bool is_fixed (void) const { return format == NumFixed; }
+ inline bool is_real (void) const { return format == NumReal; }
};
/* byte string */
offset = offset_;
}
- inline const HBUINT8& operator [] (unsigned int i) const {
+ inline const HBUINT8& operator [] (int i) const {
return str[offset + i];
}
hintmask_size = (hstem_count + vstem_count + 7) >> 3;
seen_hintmask = true;
}
- clear_stack ();
- }
-
- inline void process_moveto (void)
- {
- clear_stack ();
-
- if (!seen_moveto)
- {
- determine_hintmask_size ();
- seen_moveto = true;
- }
}
inline void clear_stack (void)
inline bool is_endchar (void) const { return endchar_flag; }
inline bool is_stack_cleared (void) const { return stack_cleared; }
- protected:
+ public:
bool endchar_flag;
bool stack_cleared;
bool seen_moveto;
bool seen_hintmask;
- public:
unsigned int hstem_count;
unsigned int vstem_count;
unsigned int hintmask_size;
BiasedSubrs<SUBRS> localSubrs;
};
-template <typename SUBRS, typename PARAM>
+template <typename OPSET, typename ENV, typename PARAM>
struct CSOpSet : OpSet
{
- static inline bool process_op (OpCode op, CSInterpEnv<SUBRS> &env, PARAM& param)
- {
+ static inline bool process_op (OpCode op, ENV &env, PARAM& param)
+ {
switch (op) {
case OpCode_return:
case OpCode_hstem:
case OpCode_hstemhm:
- env.hstem_count += env.argStack.size / 2;
- env.clear_stack ();
+ OPSET::process_hstem (env, param);
break;
case OpCode_vstem:
case OpCode_vstemhm:
- env.vstem_count += env.argStack.size / 2;
- env.clear_stack ();
+ OPSET::process_vstem (env, param);
break;
case OpCode_hintmask:
case OpCode_cntrmask:
env.determine_hintmask_size ();
+ OPSET::flush_stack (env, param);
if (unlikely (!env.substr.avail (env.hintmask_size)))
return false;
env.substr.inc (env.hintmask_size);
case OpCode_vlineto:
case OpCode_rmoveto:
case OpCode_hmoveto:
- env.process_moveto ();
+ OPSET::process_moveto (env, param);
break;
case OpCode_rrcurveto:
case OpCode_rcurveline:
case OpCode_flex:
case OpCode_hflex1:
case OpCode_flex1:
- env.clear_stack ();
+ OPSET::flush_stack (env, param);
break;
default:
}
return true;
}
+
+ static inline void process_hstem (ENV &env, PARAM& param)
+ {
+ env.hstem_count += env.argStack.size / 2;
+ OPSET::flush_stack (env, param);
+ }
+
+ static inline void process_vstem (ENV &env, PARAM& param)
+ {
+ env.vstem_count += env.argStack.size / 2;
+ OPSET::flush_stack (env, param);
+ }
+
+ static inline void process_moveto (ENV &env, PARAM& param)
+ {
+ if (!env.seen_moveto)
+ {
+ env.determine_hintmask_size ();
+ env.seen_moveto = true;
+ }
+ OPSET::flush_stack (env, param);
+ }
+
+ static inline void flush_stack (ENV &env, PARAM& param)
+ {
+ env.clear_stack ();
+ }
+
+ /* numeric / logical / arithmetic operators */
+ static inline bool is_arg_op (OpCode op)
+ {
+ switch (op)
+ {
+ case OpCode_shortint:
+ case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
+ case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
+ case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
+ case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
+ case OpCode_fixedcs:
+ case OpCode_and:
+ case OpCode_or:
+ case OpCode_not:
+ case OpCode_abs:
+ case OpCode_add:
+ case OpCode_sub:
+ case OpCode_div:
+ case OpCode_neg:
+ case OpCode_eq:
+ case OpCode_drop:
+ case OpCode_put:
+ case OpCode_get:
+ case OpCode_ifelse:
+ case OpCode_random:
+ case OpCode_mul:
+ case OpCode_sqrt:
+ case OpCode_dup:
+ case OpCode_exch:
+ case OpCode_index:
+ case OpCode_roll:
+ return true;
+ default:
+ return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
+ }
+ }
+
+ static inline bool is_subr_op (OpCode op)
+ {
+ switch (op)
+ {
+ case OpCode_callsubr:
+ case OpCode_callgsubr:
+ case OpCode_return:
+ return true;
+ default:
+ return false;
+ }
+ }
};
template <typename ENV, typename OPSET, typename PARAM>
inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
{
CSInterpEnv<CFF1Subrs>::init (str, globalSubrs, localSubrs);
+ processed_width = false;
+ has_width = false;
for (unsigned int i = 0; i < kTransientArraySize; i++)
transient_array[i].set_int (0);
}
bool check_transient_array_index (unsigned int i) const
{ return i < kTransientArraySize; }
- inline void process_width (void)
+ inline void check_width (void)
{
- if (!seen_width && (argStack.size > 0))
+ if (!processed_width)
{
- assert (argStack.size == 1);
- width = argStack.pop ();
- seen_width = true;
+ if ((this->argStack.size & 1) != 0)
+ {
+ width = this->argStack.elements[0];
+ has_width = true;
+ }
+ processed_width = true;
}
}
- bool seen_width;
+ bool processed_width;
+ bool has_width;
Number width;
static const unsigned int kTransientArraySize = 32;
Number transient_array[kTransientArraySize];
};
-template <typename PARAM>
-struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM>
+template <typename OPSET, typename PARAM>
+struct CFF1CSOpSet : CSOpSet<OPSET, CFF1CSInterpEnv, PARAM>
{
static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, PARAM& param)
{
break;
case OpCode_random:
if (unlikely (!env.argStack.check_overflow (1))) return false;
- env.argStack.push_real (((float)rand() + 1) / ((float)RAND_MAX + 1));
+ env.argStack.push_int (1); /* we can't deal with random behavior; make it constant */
case OpCode_mul:
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
env.argStack.push_real (n1.to_real() * n2.to_real());
}
break;
default:
- typedef CSOpSet<CFF1Subrs, PARAM> SUPER;
if (unlikely (!SUPER::process_op (op, env, param)))
return false;
- env.process_width ();
break;
}
return true;
}
+
+ static inline void flush_stack (CFF1CSInterpEnv &env, PARAM& param)
+ {
+ env.check_width ();
+ SUPER::flush_stack (env, param);
+ }
+
+ private:
+ typedef CSOpSet<OPSET, CFF1CSInterpEnv, PARAM> SUPER;
};
template <typename OPSET, typename PARAM>
inline bool fetch_op (OpCode &op)
{
- if (unlikely (substr.avail ()))
+ if (unlikely (this->substr.avail ()))
return CSInterpEnv<CFF2Subrs>::fetch_op (op);
/* make up return or endchar op */
- if (callStack.check_underflow ())
+ if (this->callStack.check_underflow ())
op = OpCode_return;
else
op = OpCode_endchar;
unsigned int ivs;
};
-template <typename PARAM>
-struct CFF2CSOpSet : CSOpSet<CFF2Subrs, PARAM>
+template <typename OPSET, typename PARAM>
+struct CFF2CSOpSet : CSOpSet<OPSET, CFF2CSInterpEnv, PARAM>
{
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
{
switch (op) {
case OpCode_blendcs:
- env.clear_stack (); // XXX: TODO
+ //env.flush_stack (); // XXX: TODO
break;
case OpCode_vsindexcs:
{
unsigned int ivs;
if (unlikely (!env.argStack.check_pop_uint (ivs))) return false;
env.set_ivs (ivs);
- env.clear_stack ();
+ //env.flush_stack ();
}
break;
default:
- typedef CSOpSet<CFF2Subrs, PARAM> SUPER;
+ typedef CSOpSet<OPSET, CFF2CSInterpEnv, PARAM> SUPER;
if (unlikely (!SUPER::process_op (op, env, param)))
return false;
break;
TRACE_SERIALIZE (this);
/* serialize the opcode */
- HBUINT8 *p = c->allocate_size<HBUINT8> ((op >= OpCode_ESC_Base)? 2: 1);
+ HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
if (unlikely (p == nullptr)) return_trace (false);
- if (op >= OpCode_ESC_Base)
+ if (Is_OpCode_ESC (op))
{
p->set (OpCode_escape);
- op = (OpCode)(op - OpCode_ESC_Base);
+ op = Unmake_OpCode_ESC (op);
p++;
}
p->set (op);
inline bool fullset (void) const
{
for (unsigned int i = 0; i < len; i++)
- if ((*this)[i] == HB_SET_VALUE_INVALID)
+ if (hb_vector_t<hb_codepoint_t>::operator[] (i) == HB_SET_VALUE_INVALID)
return false;
return true;
}
TRACE_SERIALIZE (this);
if (&subrs == &Null(Subrs<COUNT>))
return_trace (true);
- if ((subrs.count == 0) || (hb_set_get_population (set) == 0))
+ if ((subrs.count == 0) || (set == nullptr) || (hb_set_is_empty (set)))
{
if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
return_trace (false);
namespace CFF {
+/* Used for writing a temporary charstring */
+struct ByteStrBuff : hb_vector_t<char, 1>
+{
+ inline bool encode_byte (unsigned char b)
+ {
+ return (push ((const char)b) != &Crap(char));
+ }
+
+ inline bool encode_num (const Number& n)
+ {
+ if (n.in_int_range ())
+ {
+ int v = n.to_int ();
+ if ((-1131 <= v) && (v <= 1131))
+ {
+ if ((-107 <= v) && (v <= 107))
+ return encode_byte (v + 139);
+ else if (v > 0)
+ {
+ v -= 108;
+ return encode_byte ((v >> 8) + OpCode_TwoBytePosInt0) && encode_byte (v & 0xFF);
+ }
+ else
+ {
+ v = -v - 108;
+ return encode_byte ((v >> 8) + OpCode_TwoByteNegInt0) && encode_byte (v & 0xFF);
+ }
+ }
+ assert ((v & ~0xFFFF) == 0);
+ return encode_byte (OpCode_shortint) &&
+ encode_byte ((v >> 8) & 0xFF) &&
+ encode_byte (v & 0xFF);
+ }
+ 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);
+ }
+ }
+
+ inline bool encode_op (OpCode op)
+ {
+ if (Is_OpCode_ESC (op))
+ return encode_byte (OpCode_escape) &&
+ encode_byte (Unmake_OpCode_ESC (op));
+ else
+ return encode_byte (op);
+ }
+};
+
+struct ByteStrBuffArray : hb_vector_t<ByteStrBuff, 1>
+{
+ inline void fini (void)
+ {
+ for (unsigned int i = 0; i < len; i++)
+ hb_vector_t<ByteStrBuff, 1>::operator[] (i).fini ();
+ hb_vector_t<ByteStrBuff, 1>::fini ();
+ }
+};
+
+
+template <typename ACCESSOR, typename ENV, typename OPSET>
+struct SubrFlattener
+{
+ inline SubrFlattener (const ACCESSOR &acc_, const hb_vector_t<hb_codepoint_t> &glyphs_)
+ : acc (acc_),
+ glyphs (glyphs_)
+ {}
+
+ inline bool flatten (ByteStrBuffArray &flat_charstrings)
+ {
+ if (!flat_charstrings.resize (glyphs.len))
+ return false;
+ for (unsigned int i = 0; i < glyphs.len; i++)
+ flat_charstrings[i].init ();
+ 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, ByteStrBuff> interp;
+ interp.env.init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
+ if (unlikely (!interp.interpret (flat_charstrings[i])))
+ return false;
+ }
+ return true;
+ }
+
+ const ACCESSOR &acc;
+ const hb_vector_t<hb_codepoint_t> &glyphs;
+};
+
struct SubrRefMaps
{
- inline SubrRefMaps (void)
- : valid (false),
- global_map (nullptr)
+ inline void init (void)
{
+ valid = false;
+ global_map = nullptr;
local_maps.init ();
}
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)
- return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
+ {
+ 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)
- return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (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 CFF1PrivateDict_OpSerializer_DropHints : CFF1PrivateDict_OpSerializer
+struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff>
{
- inline bool serialize (hb_serialize_context_t *c,
- const OpStr &opstr,
- const unsigned int subrsOffset) const
+ static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
{
- if (DictOpSet::is_hint_op (opstr.op))
- return true;
- else
- return CFF1PrivateDict_OpSerializer::serialize (c, opstr, subrsOffset);
+ if (unlikely (!SUPER::process_op (op, env, flatStr)))
+ return false;
+ switch (op)
+ {
+ case OpCode_hintmask:
+ case OpCode_cntrmask:
+ if (unlikely (!flatStr.encode_op (op)))
+ return false;
+ for (int i = -env.hintmask_size; i < 0; i++)
+ if (unlikely (!flatStr.encode_byte (env.substr[i])))
+ return false;
+ break;
+ default:
+ if (!CSOpSet::is_subr_op (op) &&
+ !CSOpSet::is_arg_op (op))
+ return flatStr.encode_op (op);
+ }
+ return true;
}
- inline unsigned int calculate_serialized_size (const OpStr &opstr) const
+ static inline void flush_stack (CFF1CSInterpEnv &env, ByteStrBuff& flatStr)
{
- if (DictOpSet::is_hint_op (opstr.op))
- return 0;
- else
- return CFF1PrivateDict_OpSerializer::calculate_serialized_size (opstr);
+ for (unsigned int i = 0; i < env.argStack.size; i++)
+ flatStr.encode_num (env.argStack.elements[i]);
+ SUPER::flush_stack (env, flatStr);
}
+
+ private:
+ typedef CFF1CSOpSet<CFF1CSOpSet_Flatten, ByteStrBuff> SUPER;
};
-struct CFF1CSOpSet_SubrSubset : CFF1CSOpSet<SubrRefMapPair>
+struct CFF1CSOpSet_SubsetSubrs : CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>
{
static inline bool process_op (OpCode op, CFF1CSInterpEnv &env, SubrRefMapPair& refMapPair)
{
default:
break;
}
- return CFF1CSOpSet<SubrRefMapPair>::process_op (op, env, refMapPair);
+ return CFF1CSOpSet<CFF1CSOpSet_SubsetSubrs, SubrRefMapPair>::process_op (op, env, refMapPair);
}
};
inline cff_subset_plan (void)
: final_size (0),
orig_fdcount (0),
- subst_fdcount(1),
+ subst_fdcount (1),
subst_fdselect_format (0),
- offsets()
+ offsets (),
+ flatten_subrs (true),
+ drop_hints (false)
{
topdict_sizes.init ();
topdict_sizes.resize (1);
subst_fdselect_first_glyphs.init ();
fdmap.init ();
subset_charstrings.init ();
+ flat_charstrings.init ();
privateDictInfos.init ();
+ subrRefMaps.init ();
}
inline ~cff_subset_plan (void)
subst_fdselect_first_glyphs.fini ();
fdmap.fini ();
subset_charstrings.fini ();
+ flat_charstrings.fini ();
privateDictInfos.fini ();
subrRefMaps.fini ();
}
offsets.stringIndexOffset = final_size;
final_size += acc.stringIndex->get_size ();
- /* Subset global & local subrs */
+ if (flatten_subrs)
+ {
+ /* Flatten global & local subrs */
+ SubrFlattener<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_Flatten> flattener(acc, plan->glyphs);
+ if (!flattener.flatten (flat_charstrings))
+ return false;
+
+ /* no global/local subroutines */
+ offsets.globalSubrsInfo.size = HBUINT16::static_size; /* count 0 only */
+ }
+ else
{
- SubrSubsetter<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubrSubset> subsetter(acc, plan->glyphs);
+ /* Subset global & local subrs */
+ SubrSubsetter<const OT::cff1::accelerator_subset_t, CFF1CSInterpEnv, CFF1CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
if (!subsetter.collect_refs (subrRefMaps))
return false;
for (unsigned int i = 0; i < orig_fdcount; i++)
offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i], 1);
}
-
/* global subrs */
offsets.globalSubrsInfo.offset = final_size;
final_size += offsets.globalSubrsInfo.size;
unsigned int dataSize = 0;
for (unsigned int i = 0; i < plan->glyphs.len; i++)
{
- const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
- subset_charstrings.push (str);
- dataSize += str.len;
+ if (flatten_subrs)
+ {
+ 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);
final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.len, dataSize);
if (!fdmap.excludes (i))
{
unsigned int priv_size;
- if (plan->drop_hints)
- {
- CFF1PrivateDict_OpSerializer_DropHints privSzr_drop;
- priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr_drop);
- }
- else
- {
- CFF1PrivateDict_OpSerializer privSzr;
- priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
- }
+ CFF1PrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
+ priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
TableInfo privInfo = { final_size, priv_size, 0 };
privateDictInfos.push (privInfo);
- final_size += privInfo.size + offsets.localSubrsInfos[i].size;
+ final_size += privInfo.size;
+ if (!flatten_subrs)
+ final_size += offsets.localSubrsInfos[i].size;
}
}
if (!acc.is_CID ())
offsets.privateDictInfo = privateDictInfos[0];
- return true;
+ return ((subset_charstrings.len == plan->glyphs.len) &&
+ (privateDictInfos.len == subst_fdcount));
}
inline unsigned int get_final_size (void) const { return final_size; }
* set to HB_SET_VALUE_INVALID if excluded from subset */
FDMap fdmap;
- hb_vector_t<ByteStr> subset_charstrings;
- hb_vector_t<TableInfo> privateDictInfos;
+ hb_vector_t<ByteStr> subset_charstrings;
+ ByteStrBuffArray flat_charstrings;
+ hb_vector_t<TableInfo> privateDictInfos;
SubrRefMaps subrRefMaps;
+ bool flatten_subrs;
bool drop_hints;
};
/* global subrs */
{
+ assert (plan.offsets.globalSubrsInfo.offset != 0);
assert (plan.offsets.globalSubrsInfo.offset == c.head - c.start);
CFF1Subrs *dest = c.start_embed<CFF1Subrs> ();
if (unlikely (dest == nullptr)) return false;
{
PrivateDict *pd = c.start_embed<PrivateDict> ();
if (unlikely (pd == nullptr)) return false;
- unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
+ unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size;
bool result;
+ CFF1PrivateDict_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 */
- if (plan.drop_hints)
- {
- CFF1PrivateDict_OpSerializer_DropHints privSzr_drop;
- result = pd->serialize (&c, acc.privateDicts[i], privSzr_drop, priv_size);
- }
- else
- {
- CFF1PrivateDict_OpSerializer privSzr;
- result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
- }
+ result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size);
if (unlikely (!result))
{
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
return false;
}
- if (acc.privateDicts[i].subrsOffset != 0)
+ if (!plan.flatten_subrs && (acc.privateDicts[i].subrsOffset != 0))
{
CFF1Subrs *subrs = c.start_embed<CFF1Subrs> ();
if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF1Subrs))
}
};
-struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<SubrRefMapPair>
+struct CFF2CSOpSet_SubsetSubrs : CFF2CSOpSet<CFF2CSOpSet_SubsetSubrs, SubrRefMapPair>
{
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, SubrRefMapPair& refMapPair)
{
default:
break;
}
- return CFF2CSOpSet<SubrRefMapPair>::process_op (op, env, refMapPair);
+ return CFF2CSOpSet<CFF2CSOpSet_SubsetSubrs, SubrRefMapPair>::process_op (op, env, refMapPair);
}
};
fdmap.init ();
subset_charstrings.init ();
privateDictInfos.init ();
+ subrRefMaps.init ();
}
inline ~cff2_subset_plan (void)
/* Subset global & local subrs */
{
- SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubrSubset> subsetter(acc, plan->glyphs);
+ SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubsetSubrs> subsetter(acc, plan->glyphs);
if (!subsetter.collect_refs (subrRefMaps))
return false;