char buf[16]; /* FontTools has the following comment: * * # Note: 14 decimal digits seems to be the limitation for CFF real numbers * # in macOS. However, we use 8 here to match the implementation of AFDKO. * * We use 8 here to match FontTools X-).
*/
// the parsed charstrings point to memory in the original CFF table so we must hold a reference // to it to keep the memory valid.
original_blob = hb_blob_reference (original_blob_);
}
~cff_subset_accelerator_t()
{
hb_blob_destroy (original_blob); auto *mapping = glyph_to_sid_map.get_relaxed (); if (mapping)
{
mapping->~glyph_to_sid_map_t ();
hb_free (mapping);
}
}
case CSType_LocalSubr: if (likely (context.subr_num < parsed_local_subrs->length)) return &(*parsed_local_subrs)[context.subr_num]; break;
case CSType_GlobalSubr: if (likely (context.subr_num < parsed_global_subrs->length)) return &(*parsed_global_subrs)[context.subr_num]; break;
} return nullptr;
}
template <typename ENV> void set_current_str (ENV &env, bool calling)
{
parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); if (unlikely (!parsed_str))
{
env.set_error (); return;
} /* If the called subroutine is parsed partially but not completely yet, * it must be because we are calling it recursively.
* Handle it as an error. */ if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0)))
env.set_error (); else
{ if (!parsed_str->is_parsed ())
parsed_str->alloc (env.str_ref.total_size ());
current_parsed_str = parsed_str;
}
}
struct subr_remap_t : hb_inc_bimap_t
{ void create (const hb_set_t *closure)
{ /* create a remapping of subroutine numbers from old to new. * no optimization based on usage counts. fonttools doesn't appear doing that either.
*/
alloc (closure->get_population ()); for (auto old_num : *closure)
add (old_num);
/* Subroutine subsetting with --no-desubroutinize runs in phases: * * 1. execute charstrings/subroutines to determine subroutine closures * 2. parse out all operators and numbers * 3. mark hint operators and operands for removal if --no-hinting * 4. re-encode all charstrings and subroutines with new subroutine numbers * * Phases #1 and #2 are done at the same time in collect_subrs (). * Phase #3 walks charstrings/subroutines forward then backward (hence parsing required), * because we can't tell if a number belongs to a hint op until we see the first moveto. * * 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 (void)
{ unsigned fd_count = acc.fdCount; const cff_subset_accelerator_t* cff_accelerator = nullptr; if (acc.cff_accelerator) {
cff_accelerator = acc.cff_accelerator;
fd_count = cff_accelerator->parsed_local_subrs.length;
}
if (cff_accelerator) { // If we are not dropping hinting then charstrings are not modified so we can // just use a reference to the cached copies.
cached_charstrings.resize_exact (plan->num_output_glyphs ());
parsed_global_subrs = &cff_accelerator->parsed_global_subrs;
parsed_local_subrs = &cff_accelerator->parsed_local_subrs;
} else {
parsed_charstrings.resize_exact (plan->num_output_glyphs ());
parsed_global_subrs_storage.resize_exact (acc.globalSubrs->count);
if (unlikely (!parsed_local_subrs_storage.resize (fd_count))) returnfalse;
for (unsignedint i = 0; i < acc.fdCount; i++)
{ unsigned count = acc.privateDicts[i].localSubrs->count;
parsed_local_subrs_storage[i].resize (count); if (unlikely (parsed_local_subrs_storage[i].in_error ())) returnfalse;
}
if (cff_accelerator)
{ // parsed string already exists in accelerator, copy it and move // on. if (cached_charstrings)
cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph]; else
parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
if (unlikely (!interp.interpret (param))) returnfalse;
/* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
/* mark hint ops and arguments for drop */ if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
{
subr_subset_param_t param (&parsed_charstrings[new_glyph],
&parsed_global_subrs_storage,
&parsed_local_subrs_storage[fd],
&closures.global_closure,
&closures.local_closures[fd],
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
drop_hints_param_t drop; if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
{
parsed_charstrings[new_glyph].set_hint_dropped (); if (drop.vsindex_dropped)
parsed_charstrings[new_glyph].set_vsindex_dropped ();
}
}
/* Doing this here one by one instead of compacting all at the end * has massive peak-memory saving. * * The compacting both saves memory and makes further operations * faster.
*/
parsed_charstrings[new_glyph].compact ();
}
/* Since parsed strings were loaded from accelerator, we still need * to compute the subroutine closures which would have normally happened during * parsing. * * Or if we are dropping hinting, redo closure to get actually used subrs.
*/ if ((cff_accelerator ||
(!cff_accelerator && plan->flags & HB_SUBSET_FLAGS_NO_HINTING)) &&
!closure_subroutines(*parsed_global_subrs,
*parsed_local_subrs)) returnfalse;
if (endchar_op != OpCode_Invalid) for (; last < gid; last++)
{ // Hack to point vector to static string. auto &b = buffArray.arrayZ[last];
b.length = 1;
b.arrayZ = const_cast<unsignedchar *>(endchar_str);
}
last++; // Skip over gid unsignedint fd = acc.fdSelect->get_fd (old_glyph); if (unlikely (fd >= acc.fdCount)) returnfalse; if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix))) returnfalse;
} if (endchar_op != OpCode_Invalid) for (; last < num_glyphs; last++)
{ // Hack to point vector to static string. auto &b = buffArray.arrayZ[last];
b.length = 1;
b.arrayZ = const_cast<unsignedchar *>(endchar_str);
}
/* 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)
{
str.values[pos].set_hinting (); /* if this subr call is at the end of the parent subr, propagate the flag
* otherwise reset the flag */ if (!str.at_end (pos))
drop.ends_in_hint = false;
} elseif (drop.all_dropped)
{
str.values[pos].set_hinting ();
}
return has_hint;
}
/* returns true if it sees a hint op before the first moveto */ bool drop_hints_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m, drop_hints_param_t &drop)
{ bool seen_hint = false;
case OpCode_rmoveto: case OpCode_hmoveto: case OpCode_vmoveto:
drop.seen_moveto = true; break;
case OpCode_hintmask: case OpCode_cntrmask: if (drop.seen_moveto)
{
values[pos].set_hinting (); break;
}
HB_FALLTHROUGH;
case OpCode_hstemhm: case OpCode_vstemhm: case OpCode_hstem: case OpCode_vstem:
has_hint = true;
values[pos].set_hinting (); if (str.at_end (pos))
drop.ends_in_hint = true; break;
case OpCode_dotsection:
values[pos].set_hinting (); break;
default: /* NONE */ break;
} if (has_hint)
{ for (int i = pos - 1; i >= 0; i--)
{
parsed_cs_op_t &csop = values[(unsigned)i]; if (csop.is_hinting ()) break;
csop.set_hinting (); if (csop.op == OpCode_vsindexcs)
drop.vsindex_dropped = true;
}
seen_hint |= has_hint;
}
}
/* 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 (unsignedint pos = 0; pos < count; pos++)
{
parsed_cs_op_t &csop = values[pos]; if (csop.op == OpCode_return) break; if (!csop.is_hinting ())
{
drop.all_dropped = false; break;
}
}
// Note: const cast is safe here because the collect_subr_refs_in_str only performs a // closure and does not modify any of the charstrings.
subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)), const_cast<parsed_cs_str_vec_t*> (&global_subrs), const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
&closures.global_closure,
&closures.local_closures[fd],
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.