Merge pull request #1583 from harfbuzz/cff-retain-gids
[subset] Implement --retain-gids with CFF/CFF2
This commit is contained in:
commit
5000550183
@ -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,14 @@ 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))
|
||||
{
|
||||
/* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
|
||||
glyph = i;
|
||||
}
|
||||
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])))
|
||||
@ -777,10 +797,12 @@ struct subr_subsetter_t
|
||||
drop_hints_param_t ()
|
||||
: seen_moveto (false),
|
||||
ends_in_hint (false),
|
||||
all_dropped (false),
|
||||
vsindex_dropped (false) {}
|
||||
|
||||
bool seen_moveto;
|
||||
bool ends_in_hint;
|
||||
bool all_dropped;
|
||||
bool vsindex_dropped;
|
||||
};
|
||||
|
||||
@ -791,7 +813,7 @@ struct subr_subsetter_t
|
||||
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),
|
||||
/* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto),
|
||||
* then this entire subroutine must be a hint. drop its call. */
|
||||
if (drop.ends_in_hint)
|
||||
{
|
||||
@ -801,6 +823,10 @@ struct subr_subsetter_t
|
||||
if (!str.at_end (pos))
|
||||
drop.ends_in_hint = false;
|
||||
}
|
||||
else if (drop.all_dropped)
|
||||
{
|
||||
str.values[pos].set_drop ();
|
||||
}
|
||||
|
||||
return has_hint;
|
||||
}
|
||||
@ -819,7 +845,6 @@ struct subr_subsetter_t
|
||||
has_hint = drop_hints_in_subr (str, pos,
|
||||
*param.parsed_local_subrs, str.values[pos].subr_num,
|
||||
param, drop);
|
||||
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
@ -876,6 +901,23 @@ struct subr_subsetter_t
|
||||
}
|
||||
}
|
||||
|
||||
/* Raise all_dropped flag if all operators except return are dropped from a subr.
|
||||
* It may happen even after seeing the first moveto if a subr contains
|
||||
* only (usually one) hintmask operator, then calls to this subr can be dropped.
|
||||
*/
|
||||
drop.all_dropped = true;
|
||||
for (unsigned int pos = 0; pos < str.values.length; pos++)
|
||||
{
|
||||
parsed_cs_op_t &csop = str.values[pos];
|
||||
if (csop.op == OpCode_return)
|
||||
break;
|
||||
if (!csop.for_drop ())
|
||||
{
|
||||
drop.all_dropped = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return seen_hint;
|
||||
}
|
||||
|
||||
@ -954,13 +996,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 +1014,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,19 +472,24 @@ 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);
|
||||
hb_codepoint_t old_glyph;
|
||||
if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
|
||||
{
|
||||
/* Retain the code for the old missing glyph ID */
|
||||
old_glyph = glyph;
|
||||
}
|
||||
code = acc.glyph_to_code (old_glyph);
|
||||
if (code == CFF_UNDEF_CODE)
|
||||
{
|
||||
subset_enc_num_codes = glyph - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (code != last_code + 1)
|
||||
if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
|
||||
{
|
||||
code_pair_t pair = { code, glyph };
|
||||
subset_enc_code_ranges.push (pair);
|
||||
@ -490,7 +498,7 @@ struct cff_subset_plan {
|
||||
|
||||
if (encoding != &Null(Encoding))
|
||||
{
|
||||
hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph);
|
||||
hb_codepoint_t sid = acc.glyph_to_sid (old_glyph);
|
||||
encoding->get_supplement_codes (sid, supp_codes);
|
||||
for (unsigned int i = 0; i < supp_codes.length; i++)
|
||||
{
|
||||
@ -526,15 +534,20 @@ 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 old_glyph;
|
||||
if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
|
||||
{
|
||||
/* Retain the SID for the old missing glyph ID */
|
||||
old_glyph = glyph;
|
||||
}
|
||||
sid = acc.glyph_to_sid (old_glyph);
|
||||
|
||||
if (!acc.is_CID ())
|
||||
sid = sidmap.add (sid);
|
||||
|
||||
if (sid != last_sid + 1)
|
||||
if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
|
||||
{
|
||||
code_pair_t pair = { sid, glyph };
|
||||
subset_charset_ranges.push (pair);
|
||||
@ -544,7 +557,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 +572,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 +599,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 +660,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 +696,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 +706,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 +802,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 +834,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 +877,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 +989,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 +1081,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;
|
||||
}
|
||||
|
||||
|
BIN
test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
Normal file
BIN
test/api/fonts/AdobeVFPrototype.ac.retaingids.otf
Normal file
Binary file not shown.
BIN
test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
Normal file
BIN
test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf
Normal file
Binary file not shown.
BIN
test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
Normal file
BIN
test/api/fonts/SourceSansPro-Regular.ac.retaingids.otf
Normal file
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 ();
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
test/subset/data/profiles/desubroutinize-retain-gids.txt
Normal file
2
test/subset/data/profiles/desubroutinize-retain-gids.txt
Normal file
@ -0,0 +1,2 @@
|
||||
--desubroutinize
|
||||
--retain-gids
|
@ -0,0 +1,3 @@
|
||||
--no-hinting
|
||||
--desubroutinize
|
||||
--retain-gids
|
18
test/subset/data/tests/cff-full-font.tests
Normal file
18
test/subset/data/tests/cff-full-font.tests
Normal file
@ -0,0 +1,18 @@
|
||||
FONTS:
|
||||
SourceSansPro-Regular.otf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
drop-hints.txt
|
||||
drop-hints-retain-gids.txt
|
||||
retain-gids.txt
|
||||
desubroutinize.txt
|
||||
desubroutinize-retain-gids.txt
|
||||
drop-hints-desubroutinize.txt
|
||||
drop-hints-desubroutinize-retain-gids.txt
|
||||
|
||||
SUBSETS:
|
||||
abc
|
||||
Ǽ!A bc
|
||||
×ØÙÚÞ
|
||||
|
22
test/subset/data/tests/cff-japanese.tests
Normal file
22
test/subset/data/tests/cff-japanese.tests
Normal file
@ -0,0 +1,22 @@
|
||||
FONTS:
|
||||
SourceHanSans-Regular.otf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
drop-hints.txt
|
||||
drop-hints-retain-gids.txt
|
||||
retain-gids.txt
|
||||
desubroutinize.txt
|
||||
desubroutinize-retain-gids.txt
|
||||
drop-hints-desubroutinize.txt
|
||||
drop-hints-desubroutinize-retain-gids.txt
|
||||
|
||||
SUBSETS:
|
||||
明
|
||||
acek
|
||||
明極珠度輸清
|
||||
あいうえおか
|
||||
あいう珠度輸
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
FONTS:
|
||||
Roboto-Regular.ttf
|
||||
SourceSansPro-Regular.otf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
|
@ -1,6 +1,5 @@
|
||||
FONTS:
|
||||
Mplus1p-Regular.ttf
|
||||
SourceHanSans-Regular.otf
|
||||
|
||||
PROFILES:
|
||||
default.txt
|
||||
|
@ -33,9 +33,6 @@ class Test:
|
||||
font_base_name_parts = os.path.splitext(font_base_name)
|
||||
return font_base_name_parts[1]
|
||||
|
||||
def applicable(self):
|
||||
return self.profile_path.find("desubroutinize") < 0 or self.get_font_extension() == "otf"
|
||||
|
||||
# A group of tests to perform on the subsetter. Each test
|
||||
# Identifies a font a subsetting profile, and a subset to be cut.
|
||||
class SubsetTestSuite:
|
||||
@ -65,9 +62,7 @@ class SubsetTestSuite:
|
||||
for profile in self.profiles:
|
||||
profile = os.path.join(self._base_path(), "profiles", profile)
|
||||
for subset in self.subsets:
|
||||
test = Test(font, profile, subset)
|
||||
if test.applicable():
|
||||
yield test
|
||||
yield Test(font, profile, subset)
|
||||
|
||||
def _base_path(self):
|
||||
return os.path.dirname(os.path.dirname(self.test_path))
|
||||
|
Loading…
Reference in New Issue
Block a user