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:
parent
43ee0e4d00
commit
0996c0ff62
@ -262,12 +262,12 @@ struct DictInterpreter : Interpreter<ENV>
|
||||
inline bool interpret (PARAM& param)
|
||||
{
|
||||
param.init ();
|
||||
do
|
||||
while (SUPER::env.substr.avail ())
|
||||
{
|
||||
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
|
||||
if (unlikely (SUPER::env.in_error ()))
|
||||
return false;
|
||||
} while (SUPER::env.substr.avail ());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
|
||||
num_coords = num_coords_;
|
||||
varStore = acc.varStore;
|
||||
seen_blend = false;
|
||||
seen_vsindex = false;
|
||||
seen_vsindex_ = false;
|
||||
scalars.init ();
|
||||
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
|
||||
set_ivs (acc.privateDicts[fd].ivs);
|
||||
@ -145,18 +145,22 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
|
||||
inline void process_vsindex (void)
|
||||
{
|
||||
unsigned int index = argStack.pop_uint ();
|
||||
if (do_blend)
|
||||
if (unlikely (seen_vsindex () || seen_blend))
|
||||
{
|
||||
if (likely (!seen_vsindex && !seen_blend))
|
||||
set_ivs (index);
|
||||
set_error ();
|
||||
}
|
||||
seen_vsindex = true;
|
||||
else
|
||||
{
|
||||
set_ivs (index);
|
||||
}
|
||||
seen_vsindex_ = true;
|
||||
}
|
||||
|
||||
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 unsigned int get_ivs (void) const { return ivs; }
|
||||
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
|
||||
inline bool seen_vsindex (void) const { return seen_vsindex_; }
|
||||
|
||||
protected:
|
||||
inline void blend_arg (BlendArg &arg)
|
||||
@ -184,7 +188,7 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
|
||||
unsigned int ivs;
|
||||
hb_vector_t<float> scalars;
|
||||
bool do_blend;
|
||||
bool seen_vsindex;
|
||||
bool seen_vsindex_;
|
||||
bool seen_blend;
|
||||
|
||||
typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER;
|
||||
|
@ -418,14 +418,14 @@ struct TableInfo
|
||||
struct Remap : hb_vector_t<hb_codepoint_t>
|
||||
{
|
||||
inline void init (void)
|
||||
{ hb_vector_t<hb_codepoint_t>::init (); }
|
||||
{ SUPER::init (); }
|
||||
|
||||
inline void fini (void)
|
||||
{ hb_vector_t<hb_codepoint_t>::fini (); }
|
||||
{ SUPER::fini (); }
|
||||
|
||||
inline bool reset (unsigned int size)
|
||||
{
|
||||
if (unlikely (!hb_vector_t<hb_codepoint_t>::resize (size)))
|
||||
if (unlikely (!SUPER::resize (size)))
|
||||
return false;
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
(*this)[i] = CFF_UNDEF_CODE;
|
||||
@ -436,7 +436,7 @@ struct Remap : hb_vector_t<hb_codepoint_t>
|
||||
inline bool fullset (void) const
|
||||
{
|
||||
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 true;
|
||||
}
|
||||
@ -452,13 +452,13 @@ struct Remap : hb_vector_t<hb_codepoint_t>
|
||||
if (fullset ())
|
||||
return i;
|
||||
else
|
||||
return hb_vector_t<hb_codepoint_t>::operator[] (i);
|
||||
return SUPER::operator[] (i);
|
||||
}
|
||||
|
||||
inline hb_codepoint_t &operator[] (hb_codepoint_t i)
|
||||
{
|
||||
assert (i < len);
|
||||
return hb_vector_t<hb_codepoint_t>::operator[] (i);
|
||||
return SUPER::operator[] (i);
|
||||
}
|
||||
|
||||
inline unsigned int add (unsigned int i)
|
||||
@ -473,6 +473,9 @@ struct Remap : hb_vector_t<hb_codepoint_t>
|
||||
|
||||
protected:
|
||||
hb_codepoint_t count;
|
||||
|
||||
private:
|
||||
typedef hb_vector_t<hb_codepoint_t> SUPER;
|
||||
};
|
||||
|
||||
template <typename COUNT>
|
||||
@ -533,7 +536,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
unsigned int offset = 1;
|
||||
unsigned int fid = 0;
|
||||
for (unsigned i = 0; i < fontDicts.len; i++)
|
||||
if (!fdmap.excludes (i))
|
||||
if (fdmap.includes (i))
|
||||
{
|
||||
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
|
||||
offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||
@ -542,7 +545,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
|
||||
/* serialize font dicts */
|
||||
for (unsigned int i = 0; i < fontDicts.len; i++)
|
||||
if (!fdmap.excludes (i))
|
||||
if (fdmap.includes (i))
|
||||
{
|
||||
FontDict *dict = c->start_embed<FontDict> ();
|
||||
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
|
||||
@ -561,7 +564,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
{
|
||||
unsigned int dictsSize = 0;
|
||||
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);
|
||||
|
||||
offSize_ = calcOffSize (dictsSize);
|
||||
@ -720,4 +723,3 @@ struct Subrs : CFFIndex<COUNT>
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_OT_CFF_COMMON_HH */
|
||||
|
||||
|
@ -411,7 +411,7 @@ struct ParsedCStr : ParsedValues<ParsedCSOp>
|
||||
{
|
||||
SUPER::init ();
|
||||
parsed = false;
|
||||
hint_removed = false;
|
||||
hint_dropped = false;
|
||||
has_prefix_ = false;
|
||||
}
|
||||
|
||||
@ -444,15 +444,18 @@ struct ParsedCStr : ParsedValues<ParsedCSOp>
|
||||
|
||||
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 is_hint_dropped (void) const { return hint_dropped; }
|
||||
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 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 hint_dropped;
|
||||
bool vsindex_dropped;
|
||||
bool has_prefix_;
|
||||
OpCode prefix_op_;
|
||||
Number prefix_num_;
|
||||
@ -697,10 +700,13 @@ struct SubrSubsetter
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
|
||||
bool seen_moveto = false;
|
||||
bool ends_in_hint = false;
|
||||
if (drop_hints_in_str (parsed_charstrings[i], param, seen_moveto, ends_in_hint))
|
||||
parsed_charstrings[i].set_hint_removed ();
|
||||
DropHintsParam drop;
|
||||
if (drop_hints_in_str (parsed_charstrings[i], param, drop))
|
||||
{
|
||||
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 */
|
||||
@ -764,24 +770,35 @@ struct SubrSubsetter
|
||||
}
|
||||
|
||||
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,
|
||||
ParsedCStrs &subrs, unsigned int subr_num,
|
||||
const SubrSubsetParam ¶m, bool &seen_moveto)
|
||||
const SubrSubsetParam ¶m, DropHintsParam &drop)
|
||||
{
|
||||
bool ends_in_hint = false;
|
||||
bool has_hint = drop_hints_in_str (subrs[subr_num], param, seen_moveto, ends_in_hint);
|
||||
drop.ends_in_hint = false;
|
||||
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),
|
||||
* 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 ();
|
||||
|
||||
return has_hint;
|
||||
}
|
||||
|
||||
/* returns true if it sees a hint op before the first moveto */
|
||||
inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam ¶m,
|
||||
bool &seen_moveto, bool &ends_in_hint)
|
||||
inline bool drop_hints_in_str (ParsedCStr &str, const SubrSubsetParam ¶m, DropHintsParam &drop)
|
||||
{
|
||||
bool seen_hint = false;
|
||||
|
||||
@ -793,25 +810,25 @@ struct SubrSubsetter
|
||||
case OpCode_callsubr:
|
||||
has_hint = drop_hints_in_subr (str, pos,
|
||||
*param.parsed_local_subrs, str.values[pos].subr_num,
|
||||
param, seen_moveto);
|
||||
param, drop);
|
||||
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
has_hint = drop_hints_in_subr (str, pos,
|
||||
*param.parsed_global_subrs, str.values[pos].subr_num,
|
||||
param, seen_moveto);
|
||||
param, drop);
|
||||
break;
|
||||
|
||||
case OpCode_rmoveto:
|
||||
case OpCode_hmoveto:
|
||||
case OpCode_vmoveto:
|
||||
seen_moveto = true;
|
||||
drop.seen_moveto = true;
|
||||
break;
|
||||
|
||||
case OpCode_hintmask:
|
||||
case OpCode_cntrmask:
|
||||
if (seen_moveto)
|
||||
if (drop.seen_moveto)
|
||||
{
|
||||
str.values[pos].set_drop ();
|
||||
break;
|
||||
@ -826,7 +843,7 @@ struct SubrSubsetter
|
||||
str.values[pos].set_drop ();
|
||||
if ((pos + 1 >= str.values.len) /* CFF2 */
|
||||
|| (str.values[pos + 1].op == OpCode_return))
|
||||
ends_in_hint = true;
|
||||
drop.ends_in_hint = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -837,9 +854,12 @@ struct SubrSubsetter
|
||||
{
|
||||
for (int i = pos - 1; i >= 0; i--)
|
||||
{
|
||||
if (str.values[i].for_drop ())
|
||||
ParsedCSOp &csop = str.values[i];
|
||||
if (csop.for_drop ())
|
||||
break;
|
||||
str.values[i].set_drop ();
|
||||
csop.set_drop ();
|
||||
if (csop.op == OpCode_vsindexcs)
|
||||
drop.vsindex_dropped = true;
|
||||
}
|
||||
seen_hint |= has_hint;
|
||||
}
|
||||
@ -890,7 +910,7 @@ struct SubrSubsetter
|
||||
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 ())
|
||||
if (str.has_prefix () && str.is_hint_dropped ())
|
||||
{
|
||||
encoder.encode_num (str.prefix_num ());
|
||||
if (str.prefix_op () != OpCode_Invalid)
|
||||
|
@ -167,6 +167,68 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
|
||||
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 {
|
||||
inline cff2_subset_plan (void)
|
||||
: final_size (0),
|
||||
@ -179,7 +241,8 @@ struct cff2_subset_plan {
|
||||
subset_fdselect_ranges.init ();
|
||||
fdmap.init ();
|
||||
subset_charstrings.init ();
|
||||
flat_charstrings.init ();
|
||||
subset_globalsubrs.init ();
|
||||
subset_localsubrs.init ();
|
||||
privateDictInfos.init ();
|
||||
}
|
||||
|
||||
@ -187,8 +250,9 @@ struct cff2_subset_plan {
|
||||
{
|
||||
subset_fdselect_ranges.fini ();
|
||||
fdmap.fini ();
|
||||
subset_charstrings.fini ();
|
||||
flat_charstrings.fini_deep ();
|
||||
subset_charstrings.fini_deep ();
|
||||
subset_globalsubrs.fini_deep ();
|
||||
subset_localsubrs.fini_deep ();
|
||||
privateDictInfos.fini ();
|
||||
}
|
||||
|
||||
@ -211,17 +275,60 @@ struct cff2_subset_plan {
|
||||
final_size += offsets.topDictInfo.size;
|
||||
}
|
||||
|
||||
if (desubroutinize)
|
||||
{
|
||||
/* Flatten global & local subrs */
|
||||
SubrFlattener<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_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 = 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 */
|
||||
offsets.globalSubrsInfo.offset = final_size;
|
||||
final_size += offsets.globalSubrsInfo.size;
|
||||
@ -256,20 +363,19 @@ struct cff2_subset_plan {
|
||||
{
|
||||
offsets.FDArrayInfo.offset = final_size;
|
||||
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 */
|
||||
{
|
||||
offsets.charStringsInfo.offset = final_size;
|
||||
unsigned int dataSize = 0;
|
||||
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;
|
||||
}
|
||||
unsigned int dataSize = subset_charstrings.total_size ();
|
||||
offsets.charStringsInfo.offSize = calcOffSize (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;
|
||||
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);
|
||||
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 };
|
||||
privateDictInfos.push (privInfo);
|
||||
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;
|
||||
|
||||
ByteStrArray subset_charstrings;
|
||||
StrBuffArray flat_charstrings;
|
||||
StrBuffArray subset_charstrings;
|
||||
StrBuffArray subset_globalsubrs;
|
||||
hb_vector_t<StrBuffArray> subset_localsubrs;
|
||||
hb_vector_t<TableInfo> privateDictInfos;
|
||||
|
||||
bool drop_hints;
|
||||
bool desubroutinize;
|
||||
CFF2SubrSubsetter subr_subsetter;
|
||||
};
|
||||
|
||||
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 */
|
||||
{
|
||||
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;
|
||||
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 */
|
||||
@ -420,19 +538,31 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||
assert (plan.offsets.privateDictsOffset == c.head - c.start);
|
||||
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> ();
|
||||
if (unlikely (pd == nullptr)) return false;
|
||||
unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size;
|
||||
bool result;
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
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.
Binary file not shown.
BIN
test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf
Normal file
BIN
test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf
Normal file
Binary file not shown.
BIN
test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
Normal file
BIN
test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf
Normal file
Binary file not shown.
Binary file not shown.
@ -84,7 +84,54 @@ test_subset_cff2_strip_hints (void)
|
||||
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', ' '));
|
||||
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);
|
||||
@ -99,6 +146,8 @@ main (int argc, char **argv)
|
||||
hb_test_add (test_subset_cff2_noop);
|
||||
hb_test_add (test_subset_cff2);
|
||||
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 ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user