From d038e9e1e1c8330779bd0a5693440089946156b0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 26 Jan 2025 18:54:47 -0800
Subject: [PATCH] Improved glyph and glyph index caching
---
src/SDL_ttf.c | 84 ++++++++++++++++++++++++++++-----------------------
1 file changed, 46 insertions(+), 38 deletions(-)
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index 4f9e2615..c4d5386b 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -284,8 +284,8 @@ struct TTF_Font {
int strikethrough_top_row;
// Cache for style-transformed glyphs
- c_glyph cache[256];
- FT_UInt cache_index[128];
+ SDL_HashTable *glyphs;
+ SDL_HashTable *glyph_indices;
// We are responsible for closing the font stream
SDL_IOStream *src;
@@ -1994,6 +1994,18 @@ TTF_Font *TTF_OpenFontWithProperties(SDL_PropertiesID props)
return NULL;
}
+ font->glyphs = SDL_CreateHashTable(NULL, 32, SDL_HashID, SDL_KeyMatchID, SDL_NukeFreeValue, false, false);
+ if (!font->glyphs) {
+ TTF_CloseFont(font);
+ return NULL;
+ }
+
+ font->glyph_indices = SDL_CreateHashTable(NULL, 32, SDL_HashID, SDL_KeyMatchID, NULL, false, false);
+ if (!font->glyph_indices) {
+ TTF_CloseFont(font);
+ return NULL;
+ }
+
stream = (FT_Stream)SDL_malloc(sizeof (*stream));
if (stream == NULL) {
SDL_SetError("Out of memory");
@@ -2319,7 +2331,8 @@ static void TTF_InitFontMetrics(TTF_Font *font)
font->glyph_overhang = face->size->metrics.y_ppem / 10;
}
-static void Flush_Glyph_Image(TTF_Image *image) {
+static void Flush_Glyph_Image(TTF_Image *image)
+{
if (image->buffer) {
SDL_free(image->buffer);
image->buffer = NULL;
@@ -2329,19 +2342,17 @@ static void Flush_Glyph_Image(TTF_Image *image) {
static void Flush_Glyph(c_glyph *glyph)
{
glyph->stored = 0;
- glyph->index = 0;
Flush_Glyph_Image(&glyph->pixmap);
Flush_Glyph_Image(&glyph->bitmap);
}
static void Flush_Cache(TTF_Font *font)
{
- int i;
- int size = sizeof (font->cache) / sizeof (font->cache[0]);
-
- for (i = 0; i < size; ++i) {
- if (font->cache[i].stored) {
- Flush_Glyph(&font->cache[i]);
+ c_glyph *glyph = NULL;
+ void *iter = NULL;
+ while (SDL_IterateHashTable(font->glyphs, NULL, (const void **)&glyph, &iter)) {
+ if (glyph->stored) {
+ Flush_Glyph(glyph);
}
}
@@ -2857,8 +2868,19 @@ static bool Find_GlyphByIndex(TTF_Font *font, FT_UInt idx,
int want_bitmap, int want_pixmap, int want_color, int want_lcd, int want_subpixel,
int translation, c_glyph **out_glyph, TTF_Image **out_image)
{
- // cache size is 256, get key by masking
- c_glyph *glyph = &font->cache[idx & 0xff];
+ c_glyph *glyph = NULL;
+ if (!SDL_FindInHashTable(font->glyphs, (const void *)(uintptr_t)idx, (const void **)&glyph)) {
+ glyph = (c_glyph *)SDL_calloc(1, sizeof(*glyph));
+ if (!glyph) {
+ return false;
+ }
+ glyph->index = idx;
+
+ if (!SDL_InsertIntoHashTable(font->glyphs, (const void *)(uintptr_t)idx, (const void *)glyph)) {
+ SDL_free(glyph);
+ return false;
+ }
+ }
if (out_glyph) {
*out_glyph = glyph;
@@ -2877,10 +2899,6 @@ static bool Find_GlyphByIndex(TTF_Font *font, FT_UInt idx,
* this allows to render as fast as normal mode. */
int want = CACHED_METRICS | want_bitmap | want_pixmap | want_color | want_lcd | want_subpixel;
- if (glyph->stored && glyph->index != idx) {
- Flush_Glyph(glyph);
- }
-
if (glyph->subpixel.translation == translation) {
want &= ~CACHED_SUBPIX;
}
@@ -2895,31 +2913,30 @@ static bool Find_GlyphByIndex(TTF_Font *font, FT_UInt idx,
}
}
- glyph->index = idx;
return Load_Glyph(font, glyph, want, translation);
} else {
const int want = CACHED_METRICS | want_bitmap | want_pixmap | want_color | want_lcd;
// Faster check as it gets inlined
if (want_pixmap) {
- if ((glyph->stored & CACHED_PIXMAP) && glyph->index == idx) {
+ if (glyph->stored & CACHED_PIXMAP) {
return true;
}
} else if (want_bitmap) {
- if ((glyph->stored & CACHED_BITMAP) && glyph->index == idx) {
+ if (glyph->stored & CACHED_BITMAP) {
return true;
}
} else if (want_color) {
- if ((glyph->stored & CACHED_COLOR) && glyph->index == idx) {
+ if (glyph->stored & CACHED_COLOR) {
return true;
}
} else if (want_lcd) {
- if ((glyph->stored & CACHED_LCD) && glyph->index == idx) {
+ if (glyph->stored & CACHED_LCD) {
return true;
}
} else {
// Get metrics
- if (glyph->stored && glyph->index == idx) {
+ if (glyph->stored) {
return true;
}
}
@@ -2932,30 +2949,18 @@ static bool Find_GlyphByIndex(TTF_Font *font, FT_UInt idx,
}
}
- if (glyph->stored && glyph->index != idx) {
- Flush_Glyph(glyph);
- }
-
- glyph->index = idx;
return Load_Glyph(font, glyph, want, 0);
}
}
static FT_UInt get_char_index(TTF_Font *font, Uint32 ch)
{
- Uint32 cache_index_size = sizeof (font->cache_index) / sizeof (font->cache_index[0]);
-
- if (ch < cache_index_size) {
- FT_UInt idx = font->cache_index[ch];
- if (idx) {
- return idx;
- }
+ FT_UInt idx = 0;
+ if (!SDL_FindInHashTable(font->glyph_indices, (const void *)(uintptr_t)ch, (const void **)&idx)) {
idx = FT_Get_Char_Index(font->face, ch);
- font->cache_index[ch] = idx;
- return idx;
+ SDL_InsertIntoHashTable(font->glyphs, (const void *)(uintptr_t)ch, (const void *)(uintptr_t)idx);
}
-
- return FT_Get_Char_Index(font->face, ch);
+ return idx;
}
static FT_UInt get_char_index_fallback(TTF_Font *font, Uint32 ch, TTF_Font *initial_font, TTF_Font **glyph_font)
@@ -5723,6 +5728,9 @@ void TTF_CloseFont(TTF_Font *font)
TTF_RemoveFallbackFont(font->fallback_for->font, font);
}
+ SDL_DestroyHashTable(font->glyphs);
+ SDL_DestroyHashTable(font->glyph_indices);
+
#if TTF_USE_HARFBUZZ
hb_font_destroy(font->hb_font);
#endif