Implement subset --regain-gids option with CFF1/2
along with api tests & expected results
This commit is contained in:
parent
d14d2c20b0
commit
f2908b4d8f
|
@ -43,7 +43,7 @@ using namespace CFF;
|
|||
**/
|
||||
|
||||
bool
|
||||
hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||
hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
|
||||
unsigned int fdCount,
|
||||
const FDSelect &src, /* IN */
|
||||
unsigned int &subset_fd_count /* OUT */,
|
||||
|
@ -57,7 +57,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
|||
subset_fdselect_format = 0;
|
||||
unsigned int num_ranges = 0;
|
||||
|
||||
unsigned int subset_num_glyphs = glyphs.length;
|
||||
unsigned int subset_num_glyphs = plan->num_output_glyphs ();
|
||||
if (subset_num_glyphs == 0)
|
||||
return true;
|
||||
|
||||
|
@ -69,7 +69,18 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
|||
hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
|
||||
for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
|
||||
{
|
||||
hb_codepoint_t fd = src.get_fd (glyphs[i]);
|
||||
hb_codepoint_t glyph;
|
||||
hb_codepoint_t fd;
|
||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||
{
|
||||
/* for a missing glyph, use the same fd as the previous
|
||||
* as an attempt to minimize the number of ranges */
|
||||
fd = (prev_fd == CFF_UNDEF_CODE)? 0: prev_fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = src.get_fd (glyph);
|
||||
}
|
||||
set->add (fd);
|
||||
|
||||
if (fd != prev_fd)
|
||||
|
|
|
@ -282,30 +282,35 @@ struct flatten_param_t
|
|||
bool drop_hints;
|
||||
};
|
||||
|
||||
template <typename ACC, typename ENV, typename OPSET>
|
||||
template <typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
|
||||
struct subr_flattener_t
|
||||
{
|
||||
subr_flattener_t (const ACC &acc_,
|
||||
const hb_vector_t<hb_codepoint_t> &glyphs_,
|
||||
bool drop_hints_) : acc (acc_), glyphs (glyphs_),
|
||||
drop_hints (drop_hints_) {}
|
||||
const hb_subset_plan_t *plan_)
|
||||
: acc (acc_), plan (plan_) {}
|
||||
|
||||
bool flatten (str_buff_vec_t &flat_charstrings)
|
||||
{
|
||||
if (!flat_charstrings.resize (glyphs.length))
|
||||
if (!flat_charstrings.resize (plan->num_output_glyphs ()))
|
||||
return false;
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||
flat_charstrings[i].init ();
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||
{
|
||||
hb_codepoint_t glyph = glyphs[i];
|
||||
hb_codepoint_t glyph;
|
||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||
{
|
||||
/* add an endchar only charstring for a missing glyph if CFF1 */
|
||||
if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op);
|
||||
continue;
|
||||
}
|
||||
const byte_str_t str = (*acc.charStrings)[glyph];
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||
if (unlikely (fd >= acc.fdCount))
|
||||
return false;
|
||||
cs_interpreter_t<ENV, OPSET, flatten_param_t> interp;
|
||||
interp.env.init (str, acc, fd);
|
||||
flatten_param_t param = { flat_charstrings[i], drop_hints };
|
||||
flatten_param_t param = { flat_charstrings[i], plan->drop_hints };
|
||||
if (unlikely (!interp.interpret (param)))
|
||||
return false;
|
||||
}
|
||||
|
@ -313,8 +318,7 @@ struct subr_flattener_t
|
|||
}
|
||||
|
||||
const ACC &acc;
|
||||
const hb_vector_t<hb_codepoint_t> &glyphs;
|
||||
bool drop_hints;
|
||||
const hb_subset_plan_t *plan;
|
||||
};
|
||||
|
||||
struct subr_closures_t
|
||||
|
@ -611,10 +615,11 @@ struct subr_remap_ts
|
|||
hb_vector_t<subr_remap_t> local_remaps;
|
||||
};
|
||||
|
||||
template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET>
|
||||
template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typename OPSET, op_code_t endchar_op=OpCode_Invalid>
|
||||
struct subr_subsetter_t
|
||||
{
|
||||
subr_subsetter_t ()
|
||||
subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_)
|
||||
: acc (acc_), plan (plan_)
|
||||
{
|
||||
parsed_charstrings.init ();
|
||||
parsed_global_subrs.init ();
|
||||
|
@ -644,12 +649,12 @@ struct subr_subsetter_t
|
|||
* Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number
|
||||
* within the same charstring/subroutine, e.g., not split across a charstring and a subroutine.
|
||||
*/
|
||||
bool subset (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, bool drop_hints)
|
||||
bool subset (void)
|
||||
{
|
||||
closures.init (acc.fdCount);
|
||||
remaps.init (acc.fdCount);
|
||||
|
||||
parsed_charstrings.init (glyphs.length);
|
||||
parsed_charstrings.init (plan->num_output_glyphs ());
|
||||
parsed_global_subrs.init (acc.globalSubrs->count);
|
||||
parsed_local_subrs.resize (acc.fdCount);
|
||||
for (unsigned int i = 0; i < acc.fdCount; i++)
|
||||
|
@ -660,9 +665,11 @@ struct subr_subsetter_t
|
|||
return false;
|
||||
|
||||
/* phase 1 & 2 */
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||
{
|
||||
hb_codepoint_t glyph = glyphs[i];
|
||||
hb_codepoint_t glyph;
|
||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||
continue;
|
||||
const byte_str_t str = (*acc.charStrings)[glyph];
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||
if (unlikely (fd >= acc.fdCount))
|
||||
|
@ -675,7 +682,7 @@ struct subr_subsetter_t
|
|||
param.init (&parsed_charstrings[i],
|
||||
&parsed_global_subrs, &parsed_local_subrs[fd],
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
plan->drop_hints);
|
||||
|
||||
if (unlikely (!interp.interpret (param)))
|
||||
return false;
|
||||
|
@ -684,19 +691,22 @@ struct subr_subsetter_t
|
|||
SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]);
|
||||
}
|
||||
|
||||
if (drop_hints)
|
||||
if (plan->drop_hints)
|
||||
{
|
||||
/* mark hint ops and arguments for drop */
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||
{
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
|
||||
hb_codepoint_t glyph;
|
||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||
continue;
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||
if (unlikely (fd >= acc.fdCount))
|
||||
return false;
|
||||
subr_subset_param_t param;
|
||||
param.init (&parsed_charstrings[i],
|
||||
&parsed_global_subrs, &parsed_local_subrs[fd],
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
plan->drop_hints);
|
||||
|
||||
drop_hints_param_t drop;
|
||||
if (drop_hints_in_str (parsed_charstrings[i], param, drop))
|
||||
|
@ -709,16 +719,19 @@ struct subr_subsetter_t
|
|||
|
||||
/* after dropping hints recreate closures of actually used subrs */
|
||||
closures.reset ();
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||
{
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
|
||||
hb_codepoint_t glyph;
|
||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||
continue;
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||
if (unlikely (fd >= acc.fdCount))
|
||||
return false;
|
||||
subr_subset_param_t param;
|
||||
param.init (&parsed_charstrings[i],
|
||||
&parsed_global_subrs, &parsed_local_subrs[fd],
|
||||
closures.global_closure, closures.local_closures[fd],
|
||||
drop_hints);
|
||||
plan->drop_hints);
|
||||
collect_subr_refs_in_str (parsed_charstrings[i], param);
|
||||
}
|
||||
}
|
||||
|
@ -728,13 +741,20 @@ struct subr_subsetter_t
|
|||
return true;
|
||||
}
|
||||
|
||||
bool encode_charstrings (ACC &acc, const hb_vector_t<hb_codepoint_t> &glyphs, str_buff_vec_t &buffArray) const
|
||||
bool encode_charstrings (str_buff_vec_t &buffArray) const
|
||||
{
|
||||
if (unlikely (!buffArray.resize (glyphs.length)))
|
||||
if (unlikely (!buffArray.resize (plan->num_output_glyphs ())))
|
||||
return false;
|
||||
for (unsigned int i = 0; i < glyphs.length; i++)
|
||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||
{
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyphs[i]);
|
||||
hb_codepoint_t glyph;
|
||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||
{
|
||||
/* add an endchar only charstring for a missing glyph if CFF1 */
|
||||
if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op);
|
||||
continue;
|
||||
}
|
||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||
if (unlikely (fd >= acc.fdCount))
|
||||
return false;
|
||||
if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i])))
|
||||
|
@ -954,13 +974,16 @@ struct subr_subsetter_t
|
|||
}
|
||||
|
||||
protected:
|
||||
subr_closures_t closures;
|
||||
const ACC &acc;
|
||||
const hb_subset_plan_t *plan;
|
||||
|
||||
parsed_cs_str_vec_t parsed_charstrings;
|
||||
parsed_cs_str_vec_t parsed_global_subrs;
|
||||
subr_closures_t closures;
|
||||
|
||||
parsed_cs_str_vec_t parsed_charstrings;
|
||||
parsed_cs_str_vec_t parsed_global_subrs;
|
||||
hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
|
||||
|
||||
subr_remap_ts remaps;
|
||||
subr_remap_ts remaps;
|
||||
|
||||
private:
|
||||
typedef typename SUBRS::count_type subr_count_type;
|
||||
|
@ -969,7 +992,7 @@ struct subr_subsetter_t
|
|||
} /* namespace CFF */
|
||||
|
||||
HB_INTERNAL bool
|
||||
hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||
hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
|
||||
unsigned int fdCount,
|
||||
const CFF::FDSelect &src, /* IN */
|
||||
unsigned int &subset_fd_count /* OUT */,
|
||||
|
|
|
@ -392,8 +392,11 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t<cff1_cs_opset_subr_subset_t
|
|||
typedef cff1_cs_opset_t<cff1_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
|
||||
};
|
||||
|
||||
struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t>
|
||||
struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs, const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_subr_subset_t, OpCode_endchar>
|
||||
{
|
||||
cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc, const hb_subset_plan_t *plan)
|
||||
: subr_subsetter_t (acc, plan) {}
|
||||
|
||||
static void finalize_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
|
||||
{
|
||||
/* insert width at the beginning of the charstring as necessary */
|
||||
|
@ -469,16 +472,25 @@ struct cff_subset_plan {
|
|||
supp_size = 0;
|
||||
supp_codes.init ();
|
||||
|
||||
subset_enc_num_codes = plan->glyphs_deprecated.length - 1;
|
||||
subset_enc_num_codes = plan->num_output_glyphs () - 1;
|
||||
unsigned int glyph;
|
||||
for (glyph = 1; glyph < plan->glyphs_deprecated.length; glyph++)
|
||||
for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
|
||||
{
|
||||
hb_codepoint_t orig_glyph = plan->glyphs_deprecated[glyph];
|
||||
code = acc.glyph_to_code (orig_glyph);
|
||||
if (code == CFF_UNDEF_CODE)
|
||||
hb_codepoint_t orig_glyph;
|
||||
if (!plan->old_gid_for_new_gid (glyph, &orig_glyph))
|
||||
{
|
||||
subset_enc_num_codes = glyph - 1;
|
||||
break;
|
||||
/* pretend a missing glyph has the last code + 1
|
||||
* as an attempt to minimize the number of ranges */
|
||||
code = last_code + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
code = acc.glyph_to_code (orig_glyph);
|
||||
if (code == CFF_UNDEF_CODE)
|
||||
{
|
||||
subset_enc_num_codes = glyph - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (code != last_code + 1)
|
||||
|
@ -526,13 +538,22 @@ struct cff_subset_plan {
|
|||
|
||||
subset_charset_ranges.resize (0);
|
||||
unsigned int glyph;
|
||||
for (glyph = 1; glyph < plan->glyphs_deprecated.length; glyph++)
|
||||
for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
|
||||
{
|
||||
hb_codepoint_t orig_glyph = plan->glyphs_deprecated[glyph];
|
||||
sid = acc.glyph_to_sid (orig_glyph);
|
||||
hb_codepoint_t orig_glyph;
|
||||
if (!plan->old_gid_for_new_gid (glyph, &orig_glyph))
|
||||
{
|
||||
/* pretend a missing glyph has the last sid + 1
|
||||
* as an attempt to minimize the number of ranges */
|
||||
sid = last_sid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sid = acc.glyph_to_sid (orig_glyph);
|
||||
|
||||
if (!acc.is_CID ())
|
||||
sid = sidmap.add (sid);
|
||||
if (!acc.is_CID ())
|
||||
sid = sidmap.add (sid);
|
||||
}
|
||||
|
||||
if (sid != last_sid + 1)
|
||||
{
|
||||
|
@ -544,7 +565,7 @@ struct cff_subset_plan {
|
|||
|
||||
bool two_byte = subset_charset_ranges.finalize (glyph);
|
||||
|
||||
size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs_deprecated.length - 1);
|
||||
size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
|
||||
if (!two_byte)
|
||||
size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
|
||||
else
|
||||
|
@ -559,7 +580,7 @@ struct cff_subset_plan {
|
|||
|
||||
return Charset::calculate_serialized_size (
|
||||
subset_charset_format,
|
||||
subset_charset_format? subset_charset_ranges.length: plan->glyphs_deprecated.length);
|
||||
subset_charset_format? subset_charset_ranges.length: plan->num_output_glyphs ());
|
||||
}
|
||||
|
||||
bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
|
||||
|
@ -586,22 +607,25 @@ struct cff_subset_plan {
|
|||
}
|
||||
|
||||
bool create (const OT::cff1::accelerator_subset_t &acc,
|
||||
hb_subset_plan_t *plan)
|
||||
hb_subset_plan_t *plan)
|
||||
{
|
||||
/* make sure notdef is first */
|
||||
if ((plan->glyphs_deprecated.length == 0) || (plan->glyphs_deprecated[0] != 0)) return false;
|
||||
/* make sure notdef is first */
|
||||
hb_codepoint_t old_glyph;
|
||||
if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
|
||||
|
||||
final_size = 0;
|
||||
num_glyphs = plan->glyphs_deprecated.length;
|
||||
num_glyphs = plan->num_output_glyphs ();
|
||||
orig_fdcount = acc.fdCount;
|
||||
drop_hints = plan->drop_hints;
|
||||
desubroutinize = plan->desubroutinize;
|
||||
|
||||
/* check whether the subset renumbers any glyph IDs */
|
||||
gid_renum = false;
|
||||
for (unsigned int glyph = 0; glyph < plan->glyphs_deprecated.length; glyph++)
|
||||
for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
|
||||
{
|
||||
if (plan->glyphs_deprecated[glyph] != glyph) {
|
||||
if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
|
||||
continue;
|
||||
if (new_glyph != old_glyph) {
|
||||
gid_renum = true;
|
||||
break;
|
||||
}
|
||||
|
@ -644,7 +668,7 @@ struct cff_subset_plan {
|
|||
/* Determine re-mapping of font index as fdmap among other info */
|
||||
if (acc.fdSelect != &Null(CFF1FDSelect))
|
||||
{
|
||||
if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs_deprecated,
|
||||
if (unlikely (!hb_plan_subset_cff_fdselect (plan,
|
||||
orig_fdcount,
|
||||
*acc.fdSelect,
|
||||
subset_fdcount,
|
||||
|
@ -680,8 +704,8 @@ struct cff_subset_plan {
|
|||
if (desubroutinize)
|
||||
{
|
||||
/* Flatten global & local subrs */
|
||||
subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t>
|
||||
flattener(acc, plan->glyphs_deprecated, plan->drop_hints);
|
||||
subr_flattener_t<const OT::cff1::accelerator_subset_t, cff1_cs_interp_env_t, cff1_cs_opset_flatten_t, OpCode_endchar>
|
||||
flattener(acc, plan);
|
||||
if (!flattener.flatten (subset_charstrings))
|
||||
return false;
|
||||
|
||||
|
@ -690,12 +714,14 @@ struct cff_subset_plan {
|
|||
}
|
||||
else
|
||||
{
|
||||
cff1_subr_subsetter_t subr_subsetter (acc, plan);
|
||||
|
||||
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
|
||||
if (!subr_subsetter.subset (acc, plan->glyphs_deprecated, plan->drop_hints))
|
||||
if (!subr_subsetter.subset ())
|
||||
return false;
|
||||
|
||||
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
|
||||
if (!subr_subsetter.encode_charstrings (acc, plan->glyphs_deprecated, subset_charstrings))
|
||||
if (!subr_subsetter.encode_charstrings (subset_charstrings))
|
||||
return false;
|
||||
|
||||
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
||||
|
@ -784,7 +810,7 @@ struct cff_subset_plan {
|
|||
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
|
||||
if (unlikely (offsets.charStringsInfo.offSize > 4))
|
||||
return false;
|
||||
final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs_deprecated.length, dataSize);
|
||||
final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
|
||||
}
|
||||
|
||||
/* private dicts & local subrs */
|
||||
|
@ -816,7 +842,7 @@ struct cff_subset_plan {
|
|||
if (!acc.is_CID ())
|
||||
offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
|
||||
|
||||
return ((subset_charstrings.length == plan->glyphs_deprecated.length)
|
||||
return ((subset_charstrings.length == plan->num_output_glyphs ())
|
||||
&& (fontdicts_mod.length == subset_fdcount));
|
||||
}
|
||||
|
||||
|
@ -859,12 +885,11 @@ struct cff_subset_plan {
|
|||
unsigned int topDictModSIDs[name_dict_values_t::ValCount];
|
||||
|
||||
bool desubroutinize;
|
||||
cff1_subr_subsetter_t subr_subsetter;
|
||||
};
|
||||
|
||||
static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||
const OT::cff1::accelerator_subset_t &acc,
|
||||
const hb_vector_t<hb_codepoint_t>& glyphs,
|
||||
unsigned int num_glyphs,
|
||||
unsigned int dest_sz,
|
||||
void *dest)
|
||||
{
|
||||
|
@ -972,7 +997,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
|||
{
|
||||
assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
|
||||
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount,
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *acc.fdSelect, acc.fdCount,
|
||||
plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
|
||||
plan.subset_fdselect_ranges)))
|
||||
{
|
||||
|
@ -1064,7 +1089,7 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
|
|||
unsigned int cff_prime_size = cff_plan.get_final_size ();
|
||||
char *cff_prime_data = (char *) calloc (1, cff_prime_size);
|
||||
|
||||
if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs_deprecated,
|
||||
if (unlikely (!_write_cff1 (cff_plan, acc, plan->num_output_glyphs (),
|
||||
cff_prime_size, cff_prime_data))) {
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
|
||||
free (cff_prime_data);
|
||||
|
|
|
@ -225,6 +225,9 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
|
|||
|
||||
struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
|
||||
{
|
||||
cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc, const hb_subset_plan_t *plan)
|
||||
: subr_subsetter_t (acc, plan) {}
|
||||
|
||||
static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
|
||||
{
|
||||
/* vsindex is inserted at the beginning of the charstring as necessary */
|
||||
|
@ -287,7 +290,7 @@ struct cff2_subset_plan {
|
|||
{
|
||||
/* Flatten global & local subrs */
|
||||
subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
|
||||
flattener(acc, plan->glyphs_deprecated, plan->drop_hints);
|
||||
flattener(acc, plan);
|
||||
if (!flattener.flatten (subset_charstrings))
|
||||
return false;
|
||||
|
||||
|
@ -296,12 +299,14 @@ struct cff2_subset_plan {
|
|||
}
|
||||
else
|
||||
{
|
||||
cff2_subr_subsetter_t subr_subsetter (acc, plan);
|
||||
|
||||
/* Subset subrs: collect used subroutines, leaving all unused ones behind */
|
||||
if (!subr_subsetter.subset (acc, plan->glyphs_deprecated, plan->drop_hints))
|
||||
if (!subr_subsetter.subset ())
|
||||
return false;
|
||||
|
||||
/* encode charstrings, global subrs, local subrs with new subroutine numbers */
|
||||
if (!subr_subsetter.encode_charstrings (acc, plan->glyphs_deprecated, subset_charstrings))
|
||||
if (!subr_subsetter.encode_charstrings (subset_charstrings))
|
||||
return false;
|
||||
|
||||
if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs))
|
||||
|
@ -352,7 +357,7 @@ struct cff2_subset_plan {
|
|||
if (acc.fdSelect != &Null(CFF2FDSelect))
|
||||
{
|
||||
offsets.FDSelectInfo.offset = final_size;
|
||||
if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs_deprecated,
|
||||
if (unlikely (!hb_plan_subset_cff_fdselect (plan,
|
||||
orig_fdcount,
|
||||
*(const FDSelect *)acc.fdSelect,
|
||||
subset_fdcount,
|
||||
|
@ -385,7 +390,7 @@ struct cff2_subset_plan {
|
|||
offsets.charStringsInfo.offset = final_size;
|
||||
unsigned int dataSize = subset_charstrings.total_size ();
|
||||
offsets.charStringsInfo.offSize = calcOffSize (dataSize);
|
||||
final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs_deprecated.length, dataSize);
|
||||
final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize);
|
||||
}
|
||||
|
||||
/* private dicts & local subrs */
|
||||
|
@ -431,12 +436,11 @@ struct cff2_subset_plan {
|
|||
|
||||
bool drop_hints;
|
||||
bool desubroutinize;
|
||||
cff2_subr_subsetter_t subr_subsetter;
|
||||
};
|
||||
|
||||
static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||
const OT::cff2::accelerator_subset_t &acc,
|
||||
const hb_vector_t<hb_codepoint_t>& glyphs,
|
||||
unsigned int num_glyphs,
|
||||
unsigned int dest_sz,
|
||||
void *dest)
|
||||
{
|
||||
|
@ -493,7 +497,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
|||
{
|
||||
assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start));
|
||||
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
|
||||
plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size,
|
||||
plan.subset_fdselect_ranges)))
|
||||
{
|
||||
|
@ -584,7 +588,7 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
|
|||
unsigned int cff2_prime_size = cff2_plan.get_final_size ();
|
||||
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
|
||||
|
||||
if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs_deprecated,
|
||||
if (unlikely (!_write_cff2 (cff2_plan, acc, plan->num_output_glyphs (),
|
||||
cff2_prime_size, cff2_prime_data))) {
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
|
||||
free (cff2_prime_data);
|
||||
|
@ -592,10 +596,10 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
|
|||
}
|
||||
|
||||
*prime = hb_blob_create (cff2_prime_data,
|
||||
cff2_prime_size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
cff2_prime_data,
|
||||
free);
|
||||
cff2_prime_size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
cff2_prime_data,
|
||||
free);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -290,6 +290,52 @@ test_subset_cff1_dotsection (void)
|
|||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
static void
|
||||
test_subset_cff1_retaingids (void)
|
||||
{
|
||||
hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansPro-Regular.abc.otf");
|
||||
hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansPro-Regular.ac.retaingids.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_retain_gids (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',' '));
|
||||
|
||||
hb_face_destroy (face_abc_subset);
|
||||
hb_face_destroy (face_abc);
|
||||
hb_face_destroy (face_ac);
|
||||
}
|
||||
|
||||
static void
|
||||
test_subset_cff1_j_retaingids (void)
|
||||
{
|
||||
hb_face_t *face_41_3041_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,3041,4C2E.otf");
|
||||
hb_face_t *face_41_4c2e = hb_test_open_font_file ("fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf");
|
||||
|
||||
hb_set_t *codepoints = hb_set_create ();
|
||||
hb_subset_input_t *input;
|
||||
hb_face_t *face_41_3041_4c2e_subset;
|
||||
hb_set_add (codepoints, 0x41);
|
||||
hb_set_add (codepoints, 0x4C2E);
|
||||
input = hb_subset_test_create_input (codepoints);
|
||||
hb_subset_input_set_retain_gids (input, true);
|
||||
face_41_3041_4c2e_subset = hb_subset_test_create_subset (face_41_3041_4c2e, input);
|
||||
hb_set_destroy (codepoints);
|
||||
|
||||
hb_subset_test_check (face_41_4c2e, face_41_3041_4c2e_subset, HB_TAG ('C','F','F',' '));
|
||||
|
||||
hb_face_destroy (face_41_3041_4c2e_subset);
|
||||
hb_face_destroy (face_41_3041_4c2e);
|
||||
hb_face_destroy (face_41_4c2e);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
@ -307,6 +353,8 @@ main (int argc, char **argv)
|
|||
hb_test_add (test_subset_cff1_expert);
|
||||
hb_test_add (test_subset_cff1_seac);
|
||||
hb_test_add (test_subset_cff1_dotsection);
|
||||
hb_test_add (test_subset_cff1_retaingids);
|
||||
hb_test_add (test_subset_cff1_j_retaingids);
|
||||
|
||||
return hb_test_run ();
|
||||
}
|
||||
|
|
|
@ -138,6 +138,29 @@ test_subset_cff2_desubr_strip_hints (void)
|
|||
hb_face_destroy (face_ac);
|
||||
}
|
||||
|
||||
static void
|
||||
test_subset_cff2_retaingids (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.retaingids.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_retain_gids (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);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
@ -148,6 +171,7 @@ main (int argc, char **argv)
|
|||
hb_test_add (test_subset_cff2_strip_hints);
|
||||
hb_test_add (test_subset_cff2_desubr);
|
||||
hb_test_add (test_subset_cff2_desubr_strip_hints);
|
||||
hb_test_add (test_subset_cff2_retaingids);
|
||||
|
||||
return hb_test_run ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue