From 9b7617d433158eeef45461715dd416bce34328a5 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 29 Nov 2022 20:29:58 -0700 Subject: [PATCH] [ClassDef2] Use a faster algorithm in subset() Speedup across the board; up to 40% for MPlus1 at small sizes. --- src/hb-ot-layout-common.hh | 66 +++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 92612456c..180a54563 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -1530,6 +1530,11 @@ struct ClassDefFormat1_3 return classValue[(unsigned int) (glyph_id - startGlyph)]; } + unsigned get_population () const + { + return classValue.len; + } + template bool serialize (hb_serialize_context_t *c, @@ -1744,6 +1749,14 @@ struct ClassDefFormat2_4 return rangeRecord.bsearch (glyph_id).value; } + unsigned get_population () const + { + typename Types::large_int ret = 0; + for (const auto &r : rangeRecord) + ret += r.get_population (); + return ret > UINT_MAX ? UINT_MAX : (unsigned) ret; + } + template bool serialize (hb_serialize_context_t *c, @@ -1807,28 +1820,46 @@ struct ClassDefFormat2_4 { TRACE_SUBSET (this); const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; + const hb_set_t &glyph_set = *c->plan->glyphset_gsub (); hb_sorted_vector_t> glyph_and_klass; hb_set_t orig_klasses; - unsigned num_source_glyphs = c->plan->source->get_num_glyphs (); - unsigned count = rangeRecord.len; - for (unsigned i = 0; i < count; i++) + if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2 + < get_population ()) { - unsigned klass = rangeRecord.arrayZ[i].value; - if (!klass) continue; - hb_codepoint_t start = rangeRecord.arrayZ[i].first; - hb_codepoint_t end = hb_min (rangeRecord.arrayZ[i].last + 1, num_source_glyphs); - for (hb_codepoint_t g = start; g < end; g++) + for (hb_codepoint_t g : glyph_set) { - hb_codepoint_t new_gid = glyph_map[g]; + unsigned klass = get_class (g); + if (!klass) continue; + hb_codepoint_t new_gid = glyph_map[g]; if (new_gid == HB_MAP_VALUE_INVALID) continue; - if (glyph_filter && !glyph_filter->has (g)) continue; - + if (glyph_filter && !glyph_filter->has (g)) continue; glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } } + else + { + unsigned num_source_glyphs = c->plan->source->get_num_glyphs (); + unsigned count = rangeRecord.len; + for (unsigned i = 0; i < count; i++) + { + unsigned klass = rangeRecord.arrayZ[i].value; + if (!klass) continue; + hb_codepoint_t start = rangeRecord.arrayZ[i].first; + hb_codepoint_t end = hb_min (rangeRecord.arrayZ[i].last + 1, num_source_glyphs); + for (hb_codepoint_t g = start; g < end; g++) + { + hb_codepoint_t new_gid = glyph_map[g]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; + if (glyph_filter && !glyph_filter->has (g)) continue; + + glyph_and_klass.push (hb_pair (new_gid, klass)); + orig_klasses.add (klass); + } + } + } const hb_set_t& glyphset = *c->plan->glyphset_gsub (); unsigned glyph_count = glyph_filter @@ -2018,6 +2049,19 @@ struct ClassDef } } + unsigned get_population () const + { + switch (u.format) { + case 1: return u.format1.get_population (); + case 2: return u.format2.get_population (); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.get_population (); + case 4: return u.format4.get_population (); +#endif + default:return NOT_COVERED; + } + } + template bool serialize (hb_serialize_context_t *c, Iterator it_with_class_zero)