implented no-desubroutinize with CFF2 along with API test

replaced AdobeVFPrototype.abc.otf with a hinted (maually) & subroutinized copy
replaced expected results as well
This commit is contained in:
Michiharu Ariza 2018-11-07 14:48:37 -08:00
parent 43ee0e4d00
commit 0996c0ff62
12 changed files with 271 additions and 66 deletions

View File

@ -262,12 +262,12 @@ struct DictInterpreter : Interpreter<ENV>
inline bool interpret (PARAM& param) inline bool interpret (PARAM& param)
{ {
param.init (); param.init ();
do while (SUPER::env.substr.avail ())
{ {
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
if (unlikely (SUPER::env.in_error ())) if (unlikely (SUPER::env.in_error ()))
return false; return false;
} while (SUPER::env.substr.avail ()); }
return true; return true;
} }

View File

@ -88,7 +88,7 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
num_coords = num_coords_; num_coords = num_coords_;
varStore = acc.varStore; varStore = acc.varStore;
seen_blend = false; seen_blend = false;
seen_vsindex = false; seen_vsindex_ = false;
scalars.init (); scalars.init ();
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore)); do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
set_ivs (acc.privateDicts[fd].ivs); set_ivs (acc.privateDicts[fd].ivs);
@ -145,18 +145,22 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
inline void process_vsindex (void) inline void process_vsindex (void)
{ {
unsigned int index = argStack.pop_uint (); unsigned int index = argStack.pop_uint ();
if (do_blend) if (unlikely (seen_vsindex () || seen_blend))
{ {
if (likely (!seen_vsindex && !seen_blend)) set_error ();
set_ivs (index);
} }
seen_vsindex = true; else
{
set_ivs (index);
}
seen_vsindex_ = true;
} }
inline unsigned int get_region_count (void) const { return region_count; } inline unsigned int get_region_count (void) const { return region_count; }
inline void set_region_count (unsigned int region_count_) { region_count = region_count_; } inline void set_region_count (unsigned int region_count_) { region_count = region_count_; }
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_; }
inline bool seen_vsindex (void) const { return seen_vsindex_; }
protected: protected:
inline void blend_arg (BlendArg &arg) inline void blend_arg (BlendArg &arg)
@ -184,7 +188,7 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
unsigned int ivs; unsigned int ivs;
hb_vector_t<float> scalars; hb_vector_t<float> scalars;
bool do_blend; bool do_blend;
bool seen_vsindex; bool seen_vsindex_;
bool seen_blend; bool seen_blend;
typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER; typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER;

View File

@ -418,14 +418,14 @@ struct TableInfo
struct Remap : hb_vector_t<hb_codepoint_t> struct Remap : hb_vector_t<hb_codepoint_t>
{ {
inline void init (void) inline void init (void)
{ hb_vector_t<hb_codepoint_t>::init (); } { SUPER::init (); }
inline void fini (void) inline void fini (void)
{ hb_vector_t<hb_codepoint_t>::fini (); } { SUPER::fini (); }
inline bool reset (unsigned int size) inline bool reset (unsigned int size)
{ {
if (unlikely (!hb_vector_t<hb_codepoint_t>::resize (size))) if (unlikely (!SUPER::resize (size)))
return false; return false;
for (unsigned int i = 0; i < len; i++) for (unsigned int i = 0; i < len; i++)
(*this)[i] = CFF_UNDEF_CODE; (*this)[i] = CFF_UNDEF_CODE;
@ -436,7 +436,7 @@ struct Remap : hb_vector_t<hb_codepoint_t>
inline bool fullset (void) const inline bool fullset (void) const
{ {
for (unsigned int i = 0; i < len; i++) for (unsigned int i = 0; i < len; i++)
if (hb_vector_t<hb_codepoint_t>::operator[] (i) == CFF_UNDEF_CODE) if (SUPER::operator[] (i) == CFF_UNDEF_CODE)
return false; return false;
return true; return true;
} }
@ -452,13 +452,13 @@ struct Remap : hb_vector_t<hb_codepoint_t>
if (fullset ()) if (fullset ())
return i; return i;
else else
return hb_vector_t<hb_codepoint_t>::operator[] (i); return SUPER::operator[] (i);
} }
inline hb_codepoint_t &operator[] (hb_codepoint_t i) inline hb_codepoint_t &operator[] (hb_codepoint_t i)
{ {
assert (i < len); assert (i < len);
return hb_vector_t<hb_codepoint_t>::operator[] (i); return SUPER::operator[] (i);
} }
inline unsigned int add (unsigned int i) inline unsigned int add (unsigned int i)
@ -473,6 +473,9 @@ struct Remap : hb_vector_t<hb_codepoint_t>
protected: protected:
hb_codepoint_t count; hb_codepoint_t count;
private:
typedef hb_vector_t<hb_codepoint_t> SUPER;
}; };
template <typename COUNT> template <typename COUNT>
@ -533,7 +536,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
unsigned int offset = 1; unsigned int offset = 1;
unsigned int fid = 0; unsigned int fid = 0;
for (unsigned i = 0; i < fontDicts.len; i++) for (unsigned i = 0; i < fontDicts.len; i++)
if (!fdmap.excludes (i)) if (fdmap.includes (i))
{ {
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset); CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
@ -542,7 +545,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
/* serialize font dicts */ /* serialize font dicts */
for (unsigned int i = 0; i < fontDicts.len; i++) for (unsigned int i = 0; i < fontDicts.len; i++)
if (!fdmap.excludes (i)) if (fdmap.includes (i))
{ {
FontDict *dict = c->start_embed<FontDict> (); FontDict *dict = c->start_embed<FontDict> ();
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
@ -561,7 +564,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
{ {
unsigned int dictsSize = 0; unsigned int dictsSize = 0;
for (unsigned int i = 0; i < fontDicts.len; i++) for (unsigned int i = 0; i < fontDicts.len; i++)
if (!fdmap.excludes (i)) if (fdmap.includes (i))
dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
offSize_ = calcOffSize (dictsSize); offSize_ = calcOffSize (dictsSize);
@ -720,4 +723,3 @@ struct Subrs : CFFIndex<COUNT>
} /* namespace CFF */ } /* namespace CFF */
#endif /* HB_OT_CFF_COMMON_HH */ #endif /* HB_OT_CFF_COMMON_HH */

View File

@ -411,7 +411,7 @@ struct ParsedCStr : ParsedValues<ParsedCSOp>
{ {
SUPER::init (); SUPER::init ();
parsed = false; parsed = false;
hint_removed = false; hint_dropped = false;
has_prefix_ = false; has_prefix_ = false;
} }
@ -444,15 +444,18 @@ struct ParsedCStr : ParsedValues<ParsedCSOp>
inline bool is_parsed (void) const { return parsed; } inline bool is_parsed (void) const { return parsed; }
inline void set_parsed (void) { parsed = true; } inline void set_parsed (void) { parsed = true; }
inline bool is_hint_removed (void) const { return hint_removed; } inline bool is_hint_dropped (void) const { return hint_dropped; }
inline void set_hint_removed (void) { hint_removed = true; } inline void set_hint_dropped (void) { hint_dropped = true; }
inline bool is_vsindex_dropped (void) const { return vsindex_dropped; }
inline void set_vsindex_dropped (void) { vsindex_dropped = true; }
inline bool has_prefix (void) const { return has_prefix_; } inline bool has_prefix (void) const { return has_prefix_; }
inline OpCode prefix_op (void) const { return prefix_op_; } inline OpCode prefix_op (void) const { return prefix_op_; }
inline const Number &prefix_num (void) const { return prefix_num_; } inline const Number &prefix_num (void) const { return prefix_num_; }
protected: protected:
bool parsed; bool parsed;
bool hint_removed; bool hint_dropped;
bool vsindex_dropped;
bool has_prefix_; bool has_prefix_;
OpCode prefix_op_; OpCode prefix_op_;
Number prefix_num_; Number prefix_num_;
@ -697,10 +700,13 @@ struct SubrSubsetter
closures.global_closure, closures.local_closures[fd], closures.global_closure, closures.local_closures[fd],
drop_hints); drop_hints);
bool seen_moveto = false; DropHintsParam drop;
bool ends_in_hint = false; if (drop_hints_in_str (parsed_charstrings[i], param, drop))
if (drop_hints_in_str (parsed_charstrings[i], param, seen_moveto, ends_in_hint)) {
parsed_charstrings[i].set_hint_removed (); parsed_charstrings[i].set_hint_dropped ();
if (drop.vsindex_dropped)
parsed_charstrings[i].set_vsindex_dropped ();
}
} }
/* after dropping hints recreate closures of actually used subrs */ /* after dropping hints recreate closures of actually used subrs */
@ -764,24 +770,35 @@ struct SubrSubsetter
} }
protected: protected:
struct DropHintsParam
{
inline DropHintsParam (void)
: seen_moveto (false),
ends_in_hint (false),
vsindex_dropped (false) {}
bool seen_moveto;
bool ends_in_hint;
bool vsindex_dropped;
};
inline bool drop_hints_in_subr (ParsedCStr &str, unsigned int pos, inline bool drop_hints_in_subr (ParsedCStr &str, unsigned int pos,
ParsedCStrs &subrs, unsigned int subr_num, ParsedCStrs &subrs, unsigned int subr_num,
const SubrSubsetParam &param, bool &seen_moveto) const SubrSubsetParam &param, DropHintsParam &drop)
{ {
bool ends_in_hint = false; drop.ends_in_hint = false;
bool has_hint = drop_hints_in_str (subrs[subr_num], param, seen_moveto, ends_in_hint); bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop);
/* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto), /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto),
* then this entire subroutine must be a hint. drop its call. */ * then this entire subroutine must be a hint. drop its call. */
if (ends_in_hint) if (drop.ends_in_hint)
str.values[pos].set_drop (); str.values[pos].set_drop ();
return has_hint; return has_hint;
} }
/* returns true if it sees a hint op before the first moveto */ /* returns true if it sees a hint op before the first moveto */
inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam &param, inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam &param, DropHintsParam &drop)
bool &seen_moveto, bool &ends_in_hint)
{ {
bool seen_hint = false; bool seen_hint = false;
@ -793,25 +810,25 @@ struct SubrSubsetter
case OpCode_callsubr: case OpCode_callsubr:
has_hint = drop_hints_in_subr (str, pos, has_hint = drop_hints_in_subr (str, pos,
*param.parsed_local_subrs, str.values[pos].subr_num, *param.parsed_local_subrs, str.values[pos].subr_num,
param, seen_moveto); param, drop);
break; break;
case OpCode_callgsubr: case OpCode_callgsubr:
has_hint = drop_hints_in_subr (str, pos, has_hint = drop_hints_in_subr (str, pos,
*param.parsed_global_subrs, str.values[pos].subr_num, *param.parsed_global_subrs, str.values[pos].subr_num,
param, seen_moveto); param, drop);
break; break;
case OpCode_rmoveto: case OpCode_rmoveto:
case OpCode_hmoveto: case OpCode_hmoveto:
case OpCode_vmoveto: case OpCode_vmoveto:
seen_moveto = true; drop.seen_moveto = true;
break; break;
case OpCode_hintmask: case OpCode_hintmask:
case OpCode_cntrmask: case OpCode_cntrmask:
if (seen_moveto) if (drop.seen_moveto)
{ {
str.values[pos].set_drop (); str.values[pos].set_drop ();
break; break;
@ -826,7 +843,7 @@ struct SubrSubsetter
str.values[pos].set_drop (); str.values[pos].set_drop ();
if ((pos + 1 >= str.values.len) /* CFF2 */ if ((pos + 1 >= str.values.len) /* CFF2 */
|| (str.values[pos + 1].op == OpCode_return)) || (str.values[pos + 1].op == OpCode_return))
ends_in_hint = true; drop.ends_in_hint = true;
break; break;
default: default:
@ -837,9 +854,12 @@ struct SubrSubsetter
{ {
for (int i = pos - 1; i >= 0; i--) for (int i = pos - 1; i >= 0; i--)
{ {
if (str.values[i].for_drop ()) ParsedCSOp &csop = str.values[i];
if (csop.for_drop ())
break; break;
str.values[i].set_drop (); csop.set_drop ();
if (csop.op == OpCode_vsindexcs)
drop.vsindex_dropped = true;
} }
seen_hint |= has_hint; seen_hint |= has_hint;
} }
@ -890,7 +910,7 @@ struct SubrSubsetter
encoder.reset (); encoder.reset ();
/* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints,
* re-insert it at the beginning of charstreing */ * re-insert it at the beginning of charstreing */
if (str.has_prefix () && str.is_hint_removed ()) if (str.has_prefix () && str.is_hint_dropped ())
{ {
encoder.encode_num (str.prefix_num ()); encoder.encode_num (str.prefix_num ());
if (str.prefix_op () != OpCode_Invalid) if (str.prefix_op () != OpCode_Invalid)

View File

@ -167,6 +167,68 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
typedef CSOpSet<BlendArg, CFF2CSOpSet_Flatten, CFF2CSOpSet_Flatten, CFF2CSInterpEnv, FlattenParam> CSOPSET; typedef CSOpSet<BlendArg, CFF2CSOpSet_Flatten, CFF2CSOpSet_Flatten, CFF2CSInterpEnv, FlattenParam> CSOPSET;
}; };
struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<CFF2CSOpSet_SubrSubset, SubrSubsetParam>
{
static inline void process_op (OpCode op, CFF2CSInterpEnv &env, SubrSubsetParam& param)
{
switch (op) {
case OpCode_return:
param.current_parsed_str->set_parsed ();
env.returnFromSubr ();
param.set_current_str (env);
break;
case OpCode_endchar:
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;
}
}
protected:
static inline void process_call_subr (OpCode op, CSType type,
CFF2CSInterpEnv &env, SubrSubsetParam& param,
CFF2BiasedSubrs& subrs, hb_set_t *closure)
{
SubByteStr substr = env.substr;
env.callSubr (subrs, type);
param.current_parsed_str->add_call_op (op, substr, env.context.subr_num);
hb_set_add (closure, env.context.subr_num);
param.set_current_str (env);
}
private:
typedef CFF2CSOpSet<CFF2CSOpSet_SubrSubset, SubrSubsetParam> SUPER;
};
struct CFF2SubrSubsetter : SubrSubsetter<CFF2SubrSubsetter, CFF2Subrs, const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubrSubset>
{
static inline void finalize_parsed_str (CFF2CSInterpEnv &env, SubrSubsetParam& param, ParsedCStr &charstring)
{
/* vsindex is inserted at the beginning of the charstring as necessary */
if (env.seen_vsindex ())
{
Number ivs;
ivs.set_int ((int)env.get_ivs ());
charstring.set_prefix (ivs, OpCode_vsindexcs);
}
}
};
struct cff2_subset_plan { struct cff2_subset_plan {
inline cff2_subset_plan (void) inline cff2_subset_plan (void)
: final_size (0), : final_size (0),
@ -179,7 +241,8 @@ struct cff2_subset_plan {
subset_fdselect_ranges.init (); subset_fdselect_ranges.init ();
fdmap.init (); fdmap.init ();
subset_charstrings.init (); subset_charstrings.init ();
flat_charstrings.init (); subset_globalsubrs.init ();
subset_localsubrs.init ();
privateDictInfos.init (); privateDictInfos.init ();
} }
@ -187,8 +250,9 @@ struct cff2_subset_plan {
{ {
subset_fdselect_ranges.fini (); subset_fdselect_ranges.fini ();
fdmap.fini (); fdmap.fini ();
subset_charstrings.fini (); subset_charstrings.fini_deep ();
flat_charstrings.fini_deep (); subset_globalsubrs.fini_deep ();
subset_localsubrs.fini_deep ();
privateDictInfos.fini (); privateDictInfos.fini ();
} }
@ -211,17 +275,60 @@ struct cff2_subset_plan {
final_size += offsets.topDictInfo.size; final_size += offsets.topDictInfo.size;
} }
if (desubroutinize)
{ {
/* Flatten global & local subrs */ /* Flatten global & local subrs */
SubrFlattener<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_Flatten> SubrFlattener<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_Flatten>
flattener(acc, plan->glyphs, plan->drop_hints); flattener(acc, plan->glyphs, plan->drop_hints);
if (!flattener.flatten (flat_charstrings)) if (!flattener.flatten (subset_charstrings))
return false; return false;
/* no global/local subroutines */ /* no global/local subroutines */
offsets.globalSubrsInfo.size = HBUINT32::static_size; /* count 0 only */ offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0);
} }
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 = CFF2Subrs::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 ();
offsets.localSubrsInfos[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 ();
if (dataSize > 0)
{
offsets.localSubrsInfos[fd].offset = final_size;
offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize);
offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].len, dataSize);
}
}
}
}
/* global subrs */ /* global subrs */
offsets.globalSubrsInfo.offset = final_size; offsets.globalSubrsInfo.offset = final_size;
final_size += offsets.globalSubrsInfo.size; final_size += offsets.globalSubrsInfo.size;
@ -256,20 +363,19 @@ struct cff2_subset_plan {
{ {
offsets.FDArrayInfo.offset = final_size; offsets.FDArrayInfo.offset = final_size;
CFFFontDict_OpSerializer fontSzr; CFFFontDict_OpSerializer fontSzr;
final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subset_fdcount, fdmap, fontSzr); unsigned int dictsSize = 0;
for (unsigned int i = 0; i < acc.fontDicts.len; i++)
if (fdmap.includes (i))
dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
offsets.FDArrayInfo.offSize = calcOffSize (dictsSize);
final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
} }
/* CharStrings */ /* CharStrings */
{ {
offsets.charStringsInfo.offset = final_size; offsets.charStringsInfo.offset = final_size;
unsigned int dataSize = 0; unsigned int dataSize = subset_charstrings.total_size ();
for (unsigned int i = 0; i < plan->glyphs.len; i++)
{
StrBuff &flatstr = flat_charstrings[i];
ByteStr str (&flatstr[0], flatstr.len);
subset_charstrings.push (str);
dataSize += flatstr.len;
}
offsets.charStringsInfo.offSize = calcOffSize (dataSize); offsets.charStringsInfo.offSize = calcOffSize (dataSize);
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);
} }
@ -278,14 +384,20 @@ struct cff2_subset_plan {
offsets.privateDictsOffset = final_size; offsets.privateDictsOffset = final_size;
for (unsigned int i = 0; i < orig_fdcount; i++) for (unsigned int i = 0; i < orig_fdcount; i++)
{ {
if (!fdmap.excludes (i)) if (fdmap.includes (i))
{ {
unsigned int priv_size; bool has_localsubrs = offsets.localSubrsInfos[i].size > 0;
CFFPrivateDict_OpSerializer privSzr (desubroutinize, drop_hints); CFFPrivateDict_OpSerializer privSzr (desubroutinize, drop_hints);
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr); unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs);
TableInfo privInfo = { final_size, priv_size, 0 }; TableInfo privInfo = { final_size, priv_size, 0 };
privateDictInfos.push (privInfo); privateDictInfos.push (privInfo);
final_size += privInfo.size; final_size += privInfo.size;
if (!plan->desubroutinize && has_localsubrs)
{
offsets.localSubrsInfos[i].offset = final_size;
final_size += offsets.localSubrsInfos[i].size;
}
} }
} }
@ -305,12 +417,14 @@ struct cff2_subset_plan {
Remap fdmap; Remap fdmap;
ByteStrArray subset_charstrings; StrBuffArray subset_charstrings;
StrBuffArray flat_charstrings; StrBuffArray subset_globalsubrs;
hb_vector_t<StrBuffArray> subset_localsubrs;
hb_vector_t<TableInfo> privateDictInfos; hb_vector_t<TableInfo> privateDictInfos;
bool drop_hints; bool drop_hints;
bool desubroutinize; bool desubroutinize;
CFF2SubrSubsetter subr_subsetter;
}; };
static inline bool _write_cff2 (const cff2_subset_plan &plan, static inline bool _write_cff2 (const cff2_subset_plan &plan,
@ -346,9 +460,13 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
/* global subrs */ /* global subrs */
{ {
assert (cff2->topDict + plan.offsets.topDictInfo.size == c.head - c.start); assert (cff2->topDict + plan.offsets.topDictInfo.size == c.head - c.start);
CFF2Subrs *dest = c.allocate_size <CFF2Subrs> (HBUINT32::static_size); CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
if (unlikely (dest == nullptr)) return false; if (unlikely (dest == nullptr)) return false;
dest->count.set (0); if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs)))
{
DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines");
return false;
}
} }
/* variation store */ /* variation store */
@ -420,19 +538,31 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
assert (plan.offsets.privateDictsOffset == c.head - c.start); assert (plan.offsets.privateDictsOffset == c.head - c.start);
for (unsigned int i = 0; i < acc.privateDicts.len; i++) for (unsigned int i = 0; i < acc.privateDicts.len; i++)
{ {
if (!plan.fdmap.excludes (i)) if (plan.fdmap.includes (i))
{ {
PrivateDict *pd = c.start_embed<PrivateDict> (); PrivateDict *pd = c.start_embed<PrivateDict> ();
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;
CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints); CFFPrivateDict_OpSerializer privSzr (plan.desubroutinize, plan.drop_hints);
result = pd->serialize (&c, acc.privateDicts[i], privSzr, priv_size); /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0;
result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset);
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 CFF Private Dict[%d]", i);
return false; return false;
} }
if (plan.offsets.localSubrsInfos[i].size > 0)
{
CFF2Subrs *dest = c.start_embed <CFF2Subrs> ();
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;
}
}
} }
} }

Binary file not shown.

Binary file not shown.

View File

@ -84,7 +84,54 @@ test_subset_cff2_strip_hints (void)
face_abc_subset = hb_subset_test_create_subset (face_abc, input); face_abc_subset = hb_subset_test_create_subset (face_abc, input);
hb_set_destroy (codepoints); hb_set_destroy (codepoints);
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C', 'F', 'F', ' ')); hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C', 'F', 'F', '2'));
hb_face_destroy (face_abc_subset);
hb_face_destroy (face_abc);
hb_face_destroy (face_ac);
}
static void
test_subset_cff2_desubr (void)
{
hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.nosubrs.otf");
hb_set_t *codepoints = hb_set_create ();
hb_subset_input_t *input;
hb_face_t *face_abc_subset;
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'c');
input = hb_subset_test_create_input (codepoints);
hb_subset_input_set_desubroutinize (input, true);
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
hb_set_destroy (codepoints);
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C', 'F', 'F', '2'));
hb_face_destroy (face_abc_subset);
hb_face_destroy (face_abc);
hb_face_destroy (face_ac);
}
static void
test_subset_cff2_desubr_strip_hints (void)
{
hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf");
hb_set_t *codepoints = hb_set_create ();
hb_subset_input_t *input;
hb_face_t *face_abc_subset;
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'c');
input = hb_subset_test_create_input (codepoints);
hb_subset_input_set_desubroutinize (input, true);
hb_subset_input_set_drop_hints (input, true);
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
hb_set_destroy (codepoints);
hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('C', 'F', 'F', '2'));
hb_face_destroy (face_abc_subset); hb_face_destroy (face_abc_subset);
hb_face_destroy (face_abc); hb_face_destroy (face_abc);
@ -99,6 +146,8 @@ main (int argc, char **argv)
hb_test_add (test_subset_cff2_noop); hb_test_add (test_subset_cff2_noop);
hb_test_add (test_subset_cff2); hb_test_add (test_subset_cff2);
hb_test_add (test_subset_cff2_strip_hints); hb_test_add (test_subset_cff2_strip_hints);
hb_test_add (test_subset_cff2_desubr);
hb_test_add (test_subset_cff2_desubr_strip_hints);
return hb_test_run (); return hb_test_run ();
} }