[ot-font] Add a cmap cache

Speeds up Roboto shaping by 7%, for 1kb per face.
This commit is contained in:
Behdad Esfahbod 2023-01-28 13:37:43 -07:00
parent 1b53ed3c41
commit f8a744d9d5
2 changed files with 54 additions and 6 deletions

View File

@ -1901,20 +1901,37 @@ struct cmap
if (unlikely (!this->get_glyph_funcZ)) return false; if (unlikely (!this->get_glyph_funcZ)) return false;
return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
} }
template <typename cache_t = void>
inline bool _cached_get (hb_codepoint_t unicode,
hb_codepoint_t *glyph,
cache_t *cache) const
{
unsigned v;
if (cache && cache->get (unicode, &v))
{
*glyph = v;
return true;
}
bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
if (cache && ret)
cache->set (unicode, *glyph);
return ret;
}
template <typename cache_t = void>
unsigned int get_nominal_glyphs (unsigned int count, unsigned int get_nominal_glyphs (unsigned int count,
const hb_codepoint_t *first_unicode, const hb_codepoint_t *first_unicode,
unsigned int unicode_stride, unsigned int unicode_stride,
hb_codepoint_t *first_glyph, hb_codepoint_t *first_glyph,
unsigned int glyph_stride) const unsigned int glyph_stride,
cache_t *cache = nullptr) const
{ {
if (unlikely (!this->get_glyph_funcZ)) return 0; if (unlikely (!this->get_glyph_funcZ)) return 0;
hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
const void *get_glyph_data = this->get_glyph_data;
unsigned int done; unsigned int done;
for (done = 0; for (done = 0;
done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); done < count && _cached_get (*first_unicode, first_glyph, cache);
done++) done++)
{ {
first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);

View File

@ -60,12 +60,17 @@
* never need to call these functions directly. * never need to call these functions directly.
**/ **/
using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>;
using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key;
struct hb_ot_font_t struct hb_ot_font_t
{ {
const hb_ot_face_t *ot_face; const hb_ot_face_t *ot_face;
hb_ot_font_cmap_cache_t *cmap_cache;
/* h_advance caching */ /* h_advance caching */
mutable hb_atomic_int_t cached_coords_serial; mutable hb_atomic_int_t cached_coords_serial;
mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache; mutable hb_atomic_ptr_t<hb_ot_font_advance_cache_t> advance_cache;
@ -80,6 +85,31 @@ _hb_ot_font_create (hb_font_t *font)
ot_font->ot_face = &font->face->table; ot_font->ot_face = &font->face->table;
auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
&hb_ot_font_cmap_cache_user_data_key);
if (!cmap_cache)
{
cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t));
if (unlikely (!cmap_cache)) goto out;
cmap_cache->init ();
if (!hb_face_set_user_data (font->face,
&hb_ot_font_cmap_cache_user_data_key,
cmap_cache,
hb_free,
false))
{
/* Normally we would retry after this, but that would
* infinite-loop if the face is the empty-face.
* Just let it go and this font will be uncached if it
* happened to collide with anothe thread creating the
* cache at the same time. */
hb_free (cmap_cache);
cmap_cache = nullptr;
}
}
out:
ot_font->cmap_cache = cmap_cache;
return ot_font; return ot_font;
} }
@ -121,7 +151,8 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
const hb_ot_face_t *ot_face = ot_font->ot_face; const hb_ot_face_t *ot_face = ot_font->ot_face;
return ot_face->cmap->get_nominal_glyphs (count, return ot_face->cmap->get_nominal_glyphs (count,
first_unicode, unicode_stride, first_unicode, unicode_stride,
first_glyph, glyph_stride); first_glyph, glyph_stride,
ot_font->cmap_cache);
} }
static hb_bool_t static hb_bool_t