Merge pull request #3894 from googlefonts/cff_accel
[subset] Cache parsed char strings in CFF accelerator
This commit is contained in:
commit
22990fca1d
|
@ -1295,10 +1295,10 @@ struct cff1
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
hb_blob_t *blob = nullptr;
|
|
||||||
hb_sanitize_context_t sc;
|
hb_sanitize_context_t sc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
hb_blob_t *blob = nullptr;
|
||||||
const Encoding *encoding = nullptr;
|
const Encoding *encoding = nullptr;
|
||||||
const Charset *charset = nullptr;
|
const Charset *charset = nullptr;
|
||||||
const CFF1NameIndex *nameIndex = nullptr;
|
const CFF1NameIndex *nameIndex = nullptr;
|
||||||
|
|
|
@ -486,10 +486,10 @@ struct cff2
|
||||||
bool is_valid () const { return blob; }
|
bool is_valid () const { return blob; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
hb_blob_t *blob = nullptr;
|
|
||||||
hb_sanitize_context_t sc;
|
hb_sanitize_context_t sc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
hb_blob_t *blob = nullptr;
|
||||||
cff2_top_dict_values_t topDict;
|
cff2_top_dict_values_t topDict;
|
||||||
const CFF2Subrs *globalSubrs = nullptr;
|
const CFF2Subrs *globalSubrs = nullptr;
|
||||||
const CFF2VariationStore *varStore = nullptr;
|
const CFF2VariationStore *varStore = nullptr;
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
|
|
||||||
extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
|
extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
|
||||||
|
|
||||||
|
namespace CFF {
|
||||||
|
struct cff_subset_accelerator_t;
|
||||||
|
}
|
||||||
|
|
||||||
struct hb_subset_accelerator_t
|
struct hb_subset_accelerator_t
|
||||||
{
|
{
|
||||||
static hb_user_data_key_t* user_data_key()
|
static hb_user_data_key_t* user_data_key()
|
||||||
|
@ -56,17 +60,28 @@ struct hb_subset_accelerator_t
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
|
||||||
hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
|
hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
|
||||||
|
|
||||||
|
if (accel->cff_accelerator && accel->destroy_cff_accelerator)
|
||||||
|
accel->destroy_cff_accelerator ((void*) accel->cff_accelerator);
|
||||||
|
|
||||||
accel->~hb_subset_accelerator_t ();
|
accel->~hb_subset_accelerator_t ();
|
||||||
hb_free (accel);
|
hb_free (accel);
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
|
hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
|
||||||
const hb_set_t& unicodes_)
|
const hb_set_t& unicodes_)
|
||||||
: unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {}
|
: unicode_to_gid(unicode_to_gid_), unicodes(unicodes_),
|
||||||
|
has_seac(false), cff_accelerator(nullptr), destroy_cff_accelerator(nullptr) {}
|
||||||
|
|
||||||
|
// Generic
|
||||||
const hb_map_t unicode_to_gid;
|
const hb_map_t unicode_to_gid;
|
||||||
const hb_set_t unicodes;
|
const hb_set_t unicodes;
|
||||||
|
|
||||||
|
// CFF
|
||||||
bool has_seac;
|
bool has_seac;
|
||||||
|
CFF::cff_subset_accelerator_t* cff_accelerator;
|
||||||
|
hb_destroy_func_t destroy_cff_accelerator;
|
||||||
|
|
||||||
// TODO(garretrieger): cumulative glyf checksum map
|
// TODO(garretrieger): cumulative glyf checksum map
|
||||||
// TODO(garretrieger): sanitized table cache.
|
// TODO(garretrieger): sanitized table cache.
|
||||||
|
|
||||||
|
|
|
@ -403,6 +403,57 @@ struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t>
|
||||||
typedef hb_vector_t<parsed_cs_str_t> SUPER;
|
typedef hb_vector_t<parsed_cs_str_t> SUPER;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cff_subset_accelerator_t
|
||||||
|
{
|
||||||
|
static cff_subset_accelerator_t* create (
|
||||||
|
hb_blob_t* original_blob,
|
||||||
|
const parsed_cs_str_vec_t& parsed_charstrings,
|
||||||
|
const parsed_cs_str_vec_t& parsed_global_subrs,
|
||||||
|
const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
|
||||||
|
cff_subset_accelerator_t* accel =
|
||||||
|
(cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
|
||||||
|
new (accel) cff_subset_accelerator_t (original_blob,
|
||||||
|
parsed_charstrings,
|
||||||
|
parsed_global_subrs,
|
||||||
|
parsed_local_subrs);
|
||||||
|
return accel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy (void* value) {
|
||||||
|
if (!value) return;
|
||||||
|
|
||||||
|
cff_subset_accelerator_t* accel = (cff_subset_accelerator_t*) value;
|
||||||
|
accel->~cff_subset_accelerator_t ();
|
||||||
|
hb_free (accel);
|
||||||
|
}
|
||||||
|
|
||||||
|
cff_subset_accelerator_t(
|
||||||
|
hb_blob_t* original_blob_,
|
||||||
|
const parsed_cs_str_vec_t& parsed_charstrings_,
|
||||||
|
const parsed_cs_str_vec_t& parsed_global_subrs_,
|
||||||
|
const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs_)
|
||||||
|
{
|
||||||
|
parsed_charstrings = parsed_charstrings_;
|
||||||
|
parsed_global_subrs = parsed_global_subrs_;
|
||||||
|
parsed_local_subrs = parsed_local_subrs_;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
private:
|
||||||
|
hb_blob_t* original_blob;
|
||||||
|
};
|
||||||
|
|
||||||
struct subr_subset_param_t
|
struct subr_subset_param_t
|
||||||
{
|
{
|
||||||
subr_subset_param_t (parsed_cs_str_t *parsed_charstring_,
|
subr_subset_param_t (parsed_cs_str_t *parsed_charstring_,
|
||||||
|
@ -557,27 +608,49 @@ struct subr_subsetter_t
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false;
|
unsigned fd_count = acc.fdCount;
|
||||||
|
cff_subset_accelerator_t* cff_accelerator = nullptr;
|
||||||
|
if (plan->accelerator && plan->accelerator->cff_accelerator) {
|
||||||
|
cff_accelerator = plan->accelerator->cff_accelerator;
|
||||||
|
fd_count = cff_accelerator->parsed_local_subrs.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (unlikely (!parsed_local_subrs.resize (fd_count))) return false;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < acc.fdCount; i++)
|
for (unsigned int i = 0; i < acc.fdCount; i++)
|
||||||
{
|
{
|
||||||
parsed_local_subrs[i].resize (acc.privateDicts[i].localSubrs->count);
|
unsigned count = cff_accelerator
|
||||||
|
? cff_accelerator->parsed_local_subrs[i].length
|
||||||
|
: acc.privateDicts[i].localSubrs->count;
|
||||||
|
parsed_local_subrs[i].resize (count);
|
||||||
if (unlikely (parsed_local_subrs[i].in_error ())) return false;
|
if (unlikely (parsed_local_subrs[i].in_error ())) return false;
|
||||||
}
|
}
|
||||||
if (unlikely (!closures.valid))
|
if (unlikely (!closures.valid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
/* phase 1 & 2 */
|
/* phase 1 & 2 */
|
||||||
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
|
||||||
{
|
{
|
||||||
hb_codepoint_t glyph;
|
hb_codepoint_t glyph;
|
||||||
if (!plan->old_gid_for_new_gid (i, &glyph))
|
if (!plan->old_gid_for_new_gid (i, &glyph))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const hb_ubytes_t str = (*acc.charStrings)[glyph];
|
const hb_ubytes_t str = (*acc.charStrings)[glyph];
|
||||||
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
unsigned int fd = acc.fdSelect->get_fd (glyph);
|
||||||
if (unlikely (fd >= acc.fdCount))
|
if (unlikely (fd >= acc.fdCount))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (cff_accelerator)
|
||||||
|
{
|
||||||
|
// parsed string already exists in accelerator, copy it and move
|
||||||
|
// on.
|
||||||
|
parsed_charstrings[i] =
|
||||||
|
cff_accelerator->parsed_charstrings[glyph];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ENV env (str, acc, fd);
|
ENV env (str, acc, fd);
|
||||||
cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
|
cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
|
||||||
|
|
||||||
|
@ -596,6 +669,14 @@ struct subr_subsetter_t
|
||||||
SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
|
SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since parsed strings were loaded from accelerator, we still need
|
||||||
|
// to compute the subroutine closures which would have normally happened during
|
||||||
|
// parsing.
|
||||||
|
if (cff_accelerator &&
|
||||||
|
!closure_and_copy_subroutines(cff_accelerator->parsed_global_subrs,
|
||||||
|
cff_accelerator->parsed_local_subrs))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||||
{
|
{
|
||||||
/* mark hint ops and arguments for drop */
|
/* mark hint ops and arguments for drop */
|
||||||
|
@ -624,27 +705,12 @@ struct subr_subsetter_t
|
||||||
}
|
}
|
||||||
|
|
||||||
/* after dropping hints recreate closures of actually used subrs */
|
/* after dropping hints recreate closures of actually used subrs */
|
||||||
closures.reset ();
|
if (!closure_subroutines(parsed_global_subrs, parsed_local_subrs)) return false;
|
||||||
for (unsigned int i = 0; i < plan->num_output_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 (&parsed_charstrings[i],
|
|
||||||
&parsed_global_subrs,
|
|
||||||
&parsed_local_subrs[fd],
|
|
||||||
&closures.global_closure,
|
|
||||||
&closures.local_closures[fd],
|
|
||||||
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
|
|
||||||
collect_subr_refs_in_str (parsed_charstrings[i], param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remaps.create (closures);
|
remaps.create (closures);
|
||||||
|
|
||||||
|
populate_subset_accelerator();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,7 +894,54 @@ struct subr_subsetter_t
|
||||||
return seen_hint;
|
return seen_hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_subr_refs_in_subr (parsed_cs_str_t &str, unsigned int pos,
|
bool closure_and_copy_subroutines (parsed_cs_str_vec_t& global_subrs,
|
||||||
|
hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
|
||||||
|
{
|
||||||
|
if (!closure_subroutines(global_subrs,
|
||||||
|
local_subrs)) return false;
|
||||||
|
|
||||||
|
|
||||||
|
for (unsigned s : closures.global_closure) {
|
||||||
|
parsed_global_subrs[s] = global_subrs[s];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned fd = 0;
|
||||||
|
for (const hb_set_t& c : closures.local_closures) {
|
||||||
|
for (unsigned s : c) {
|
||||||
|
parsed_local_subrs[fd][s] = local_subrs[fd][s];
|
||||||
|
}
|
||||||
|
fd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool closure_subroutines (parsed_cs_str_vec_t& global_subrs,
|
||||||
|
hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
|
||||||
|
{
|
||||||
|
closures.reset ();
|
||||||
|
for (unsigned int i = 0; i < plan->num_output_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 (&parsed_charstrings[i],
|
||||||
|
&global_subrs,
|
||||||
|
&local_subrs[fd],
|
||||||
|
&closures.global_closure,
|
||||||
|
&closures.local_closures[fd],
|
||||||
|
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
|
||||||
|
collect_subr_refs_in_str (parsed_charstrings[i], param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect_subr_refs_in_subr (const parsed_cs_str_t &str, unsigned int pos,
|
||||||
unsigned int subr_num, parsed_cs_str_vec_t &subrs,
|
unsigned int subr_num, parsed_cs_str_vec_t &subrs,
|
||||||
hb_set_t *closure,
|
hb_set_t *closure,
|
||||||
const subr_subset_param_t ¶m)
|
const subr_subset_param_t ¶m)
|
||||||
|
@ -839,7 +952,7 @@ struct subr_subsetter_t
|
||||||
collect_subr_refs_in_str (subrs[subr_num], param);
|
collect_subr_refs_in_str (subrs[subr_num], param);
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_subr_refs_in_str (parsed_cs_str_t &str, const subr_subset_param_t ¶m)
|
void collect_subr_refs_in_str (const parsed_cs_str_t &str, const subr_subset_param_t ¶m)
|
||||||
{
|
{
|
||||||
unsigned count = str.values.length;
|
unsigned count = str.values.length;
|
||||||
auto &values = str.values.arrayZ;
|
auto &values = str.values.arrayZ;
|
||||||
|
@ -908,6 +1021,20 @@ struct subr_subsetter_t
|
||||||
return !encoder.in_error ();
|
return !encoder.in_error ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void populate_subset_accelerator() const
|
||||||
|
{
|
||||||
|
if (!plan->inprogress_accelerator) return;
|
||||||
|
|
||||||
|
plan->inprogress_accelerator->cff_accelerator =
|
||||||
|
cff_subset_accelerator_t::create(acc.blob,
|
||||||
|
parsed_charstrings,
|
||||||
|
parsed_global_subrs,
|
||||||
|
parsed_local_subrs);
|
||||||
|
plan->inprogress_accelerator->destroy_cff_accelerator =
|
||||||
|
cff_subset_accelerator_t::destroy;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const ACC &acc;
|
const ACC &acc;
|
||||||
const hb_subset_plan_t *plan;
|
const hb_subset_plan_t *plan;
|
||||||
|
|
Loading…
Reference in New Issue