[subset] optimize glyf subsetting w/ retain gids.

When retain gids is enabled the subset plan may require the output of many empty glyphs. This change optimizes the glyf subsetting code when the number of retained glyphs << number of output glyphs. Unnessecary lookups to the glyph map are reduced by iterating through the glyph map instead of the output glyph set.
This commit is contained in:
Garret Rieger 2022-09-27 22:50:54 +00:00
parent e94fe2adf3
commit 8f1bf23cc9
3 changed files with 32 additions and 31 deletions

View File

@ -346,10 +346,16 @@ struct Glyph
hb_bytes_t get_bytes () const { return bytes; } hb_bytes_t get_bytes () const { return bytes; }
Glyph (hb_bytes_t bytes_ = hb_bytes_t (), Glyph () : bytes (),
hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), header (bytes.as<GlyphHeader> ()),
header (bytes.as<GlyphHeader> ()), gid (-1),
gid (gid_) type(EMPTY)
{}
Glyph (hb_bytes_t bytes_,
hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
header (bytes.as<GlyphHeader> ()),
gid (gid_)
{ {
int num_contours = header->numberOfContours; int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY; if (unlikely (num_contours == 0)) type = EMPTY;

View File

@ -14,7 +14,6 @@ namespace glyf_impl {
struct SubsetGlyph struct SubsetGlyph
{ {
hb_codepoint_t new_gid;
hb_codepoint_t old_gid; hb_codepoint_t old_gid;
Glyph source_glyph; Glyph source_glyph;
hb_bytes_t dest_start; /* region of source_glyph to copy first */ hb_bytes_t dest_start; /* region of source_glyph to copy first */

View File

@ -72,7 +72,7 @@ struct glyf
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs; hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
_populate_subset_glyphs (c->plan, &glyphs); _populate_subset_glyphs (c->plan, glyphs);
if (!c->plan->pinned_at_default) if (!c->plan->pinned_at_default)
{ {
@ -108,7 +108,7 @@ struct glyf
void void
_populate_subset_glyphs (const hb_subset_plan_t *plan, _populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const; hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
bool bool
_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
@ -377,34 +377,30 @@ struct glyf_accelerator_t
inline void inline void
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{ {
OT::glyf_accelerator_t glyf (plan->source); OT::glyf_accelerator_t glyf (plan->source);
unsigned num_glyphs = plan->num_output_glyphs ();
if (!glyphs.resize (num_glyphs)) return;
+ hb_range (plan->num_output_glyphs ()) for (auto p : plan->glyph_map->iter ())
| hb_map ([&] (hb_codepoint_t new_gid) {
{ unsigned new_gid = p.second;
glyf_impl::SubsetGlyph subset_glyph = {0}; glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
subset_glyph.new_gid = new_gid; subset_glyph.old_gid = p.first;
/* should never fail: all old gids should be mapped */ if (unlikely (new_gid == 0 &&
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
return subset_glyph; plan->pinned_at_default)
subset_glyph.source_glyph = glyf_impl::Glyph ();
else
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
if (new_gid == 0 && if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) && subset_glyph.drop_hints_bytes ();
plan->pinned_at_default) else
subset_glyph.source_glyph = glyf_impl::Glyph (); subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
else }
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
subset_glyph.drop_hints_bytes ();
else
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
return subset_glyph;
})
| hb_sink (glyphs)
;
} }
inline bool inline bool