From e4866be91ee81037701fc82bc8262f287bfa62b3 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 28 Jan 2025 06:13:28 -0800
Subject: [PATCH] Fixed glyph hash collisions with fallback fonts
---
CMakeLists.txt | 1 +
VisualC/SDL_ttf.vcxproj | 3 +-
VisualC/SDL_ttf.vcxproj.filters | 5 +-
Xcode/SDL_ttf.xcodeproj/project.pbxproj | 8 +++
src/SDL_gpu_textengine.c | 35 ++++++-----
src/SDL_hashtable_ttf.c | 82 +++++++++++++++++++++++++
src/SDL_hashtable_ttf.h | 28 +++++++++
src/SDL_renderer_textengine.c | 35 ++++++-----
src/SDL_surface_textengine.c | 13 ++--
9 files changed, 167 insertions(+), 43 deletions(-)
create mode 100644 src/SDL_hashtable_ttf.c
create mode 100644 src/SDL_hashtable_ttf.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3bff411b..c0768b8a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -125,6 +125,7 @@ endif()
add_library(${sdl3_ttf_target_name}
src/SDL_hashtable.c
+ src/SDL_hashtable_ttf.c
src/SDL_gpu_textengine.c
src/SDL_renderer_textengine.c
src/SDL_surface_textengine.c
diff --git a/VisualC/SDL_ttf.vcxproj b/VisualC/SDL_ttf.vcxproj
index a33a84cb..ee86262a 100644
--- a/VisualC/SDL_ttf.vcxproj
+++ b/VisualC/SDL_ttf.vcxproj
@@ -380,6 +380,7 @@
<ClCompile Include="..\external\harfbuzz\src\hb-wasm-shape.cc" />
<ClCompile Include="..\src\SDL_gpu_textengine.c" />
<ClCompile Include="..\src\SDL_hashtable.c" />
+ <ClCompile Include="..\src\SDL_hashtable_ttf.c" />
<ClCompile Include="..\src\SDL_renderer_textengine.c" />
<ClCompile Include="..\src\SDL_surface_textengine.c" />
<ClCompile Include="..\src\SDL_ttf.c" />
@@ -393,4 +394,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/VisualC/SDL_ttf.vcxproj.filters b/VisualC/SDL_ttf.vcxproj.filters
index fd3efc5e..0b11c29b 100644
--- a/VisualC/SDL_ttf.vcxproj.filters
+++ b/VisualC/SDL_ttf.vcxproj.filters
@@ -24,6 +24,9 @@
<ClCompile Include="..\src\SDL_hashtable.c">
<Filter>Sources</Filter>
</ClCompile>
+ <ClCompile Include="..\src\SDL_hashtable_ttf.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
<ClCompile Include="..\src\SDL_renderer_textengine.c">
<Filter>Sources</Filter>
</ClCompile>
@@ -415,4 +418,4 @@
<Filter>x64</Filter>
</CustomBuild>
</ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/Xcode/SDL_ttf.xcodeproj/project.pbxproj b/Xcode/SDL_ttf.xcodeproj/project.pbxproj
index 4685184f..08be75a7 100644
--- a/Xcode/SDL_ttf.xcodeproj/project.pbxproj
+++ b/Xcode/SDL_ttf.xcodeproj/project.pbxproj
@@ -65,6 +65,8 @@
F341242A2D42C44700D6C2B7 /* INSTALL.md in Resources */ = {isa = PBXBuildFile; fileRef = F34124292D42C44700D6C2B7 /* INSTALL.md */; };
F341242D2D42C47A00D6C2B7 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = F341242B2D42C47A00D6C2B7 /* LICENSE.txt */; };
F341242E2D42C47A00D6C2B7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = F341242C2D42C47A00D6C2B7 /* README.md */; };
+ F34125C72D491AA800D6C2B7 /* SDL_hashtable_ttf.h in Headers */ = {isa = PBXBuildFile; fileRef = F34125C52D491AA800D6C2B7 /* SDL_hashtable_ttf.h */; };
+ F34125C82D491AA800D6C2B7 /* SDL_hashtable_ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = F34125C62D491AA800D6C2B7 /* SDL_hashtable_ttf.c */; };
F34400402D4033CE003F26D7 /* SDL3.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F344003F2D4033CE003F26D7 /* SDL3.framework */; };
F344FFBF2D3EB53C003F26D7 /* SDL_gpu_textengine.c in Sources */ = {isa = PBXBuildFile; fileRef = F344FFBE2D3EB53C003F26D7 /* SDL_gpu_textengine.c */; };
F3696FE4278F7107003A7F94 /* sdf.c in Sources */ = {isa = PBXBuildFile; fileRef = F3696FE3278F7107003A7F94 /* sdf.c */; };
@@ -191,6 +193,8 @@
F341242B2D42C47A00D6C2B7 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = LICENSE.txt; path = ../LICENSE.txt; sourceTree = SOURCE_ROOT; };
F341242C2D42C47A00D6C2B7 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = SOURCE_ROOT; };
F341242F2D42C49B00D6C2B7 /* INSTALL.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = INSTALL.md; sourceTree = "<group>"; };
+ F34125C52D491AA800D6C2B7 /* SDL_hashtable_ttf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_hashtable_ttf.h; sourceTree = "<group>"; };
+ F34125C62D491AA800D6C2B7 /* SDL_hashtable_ttf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hashtable_ttf.c; sourceTree = "<group>"; };
F344003F2D4033CE003F26D7 /* SDL3.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SDL3.framework; sourceTree = "<group>"; };
F344FFBE2D3EB53C003F26D7 /* SDL_gpu_textengine.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_gpu_textengine.c; sourceTree = "<group>"; };
F3696FE3278F7107003A7F94 /* sdf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sdf.c; path = ../external/freetype/src/sdf/sdf.c; sourceTree = "<group>"; };
@@ -335,6 +339,8 @@
F344FFBE2D3EB53C003F26D7 /* SDL_gpu_textengine.c */,
F3F7BDF12CB6FD6700C984AF /* SDL_hashtable.h */,
F3F7BDF22CB6FD6700C984AF /* SDL_hashtable.c */,
+ F34125C52D491AA800D6C2B7 /* SDL_hashtable_ttf.h */,
+ F34125C62D491AA800D6C2B7 /* SDL_hashtable_ttf.c */,
F3F7BDF32CB6FD6700C984AF /* SDL_renderer_textengine.c */,
F3F7BDF42CB6FD6700C984AF /* SDL_surface_textengine.c */,
F567D67A01CD962A01F3E8B9 /* SDL_ttf.c */,
@@ -500,6 +506,7 @@
buildActionMask = 2147483647;
files = (
F3F7BDF72CB6FD6700C984AF /* SDL_hashtable.h in Headers */,
+ F34125C72D491AA800D6C2B7 /* SDL_hashtable_ttf.h in Headers */,
F3F7BDF82CB6FD6700C984AF /* stb_rect_pack.h in Headers */,
BE48FD5F07AFA17000BB41DA /* SDL_ttf.h in Headers */,
F33F083D2CC41C810062C26D /* SDL_textengine.h in Headers */,
@@ -648,6 +655,7 @@
F384BDBF261EC7650028A248 /* hb-buffer.cc in Sources */,
F384BD83261EC7650028A248 /* hb-shaper.cc in Sources */,
F384BCD4261EC2BE0028A248 /* type42.c in Sources */,
+ F34125C82D491AA800D6C2B7 /* SDL_hashtable_ttf.c in Sources */,
F384BDEF261EC7650028A248 /* hb-face.cc in Sources */,
F384BCDF261EC2CF0028A248 /* winfnt.c in Sources */,
F384BC2F261EC1710028A248 /* cff.c in Sources */,
diff --git a/src/SDL_gpu_textengine.c b/src/SDL_gpu_textengine.c
index 35c05742..5479702e 100644
--- a/src/SDL_gpu_textengine.c
+++ b/src/SDL_gpu_textengine.c
@@ -23,6 +23,7 @@
#include <SDL3_ttf/SDL_ttf.h>
#include "SDL_hashtable.h"
+#include "SDL_hashtable_ttf.h"
#define ATLAS_TEXTURE_SIZE 1024
@@ -387,9 +388,9 @@ static bool UpdateGlyph(SDL_GPUDevice *device, AtlasGlyph *glyph, SDL_Surface *s
return true;
}
-static bool AddGlyphToFont(TTF_GPUTextEngineFontData *fontdata, Uint32 glyph_index, AtlasGlyph *glyph)
+static bool AddGlyphToFont(TTF_GPUTextEngineFontData *fontdata, TTF_Font *glyph_font, Uint32 glyph_index, AtlasGlyph *glyph)
{
- if (!SDL_InsertIntoHashTable(fontdata->glyphs, (const void *)(uintptr_t)glyph_index, glyph)) {
+ if (!SDL_InsertIntoGlyphHashTable(fontdata->glyphs, glyph_font, glyph_index, glyph)) {
return false;
}
return true;
@@ -411,12 +412,13 @@ static bool ResolveMissingGlyphs(TTF_GPUTextEngineData *enginedata, AtlasTexture
return false;
}
- if (!AddGlyphToFont(fontdata, ops[missing[i].id].copy.glyph_index, glyph)) {
+ TTF_DrawOperation *op = &ops[missing[i].id];
+ if (!AddGlyphToFont(fontdata, op->copy.glyph_font, op->copy.glyph_index, glyph)) {
ReleaseGlyph(glyph);
return false;
}
- ops[missing[i].id].copy.reserved = glyph;
+ op->copy.reserved = glyph;
// Remove this from the missing entries
--num_missing;
@@ -447,12 +449,13 @@ static bool ResolveMissingGlyphs(TTF_GPUTextEngineData *enginedata, AtlasTexture
return false;
}
- if (!AddGlyphToFont(fontdata, ops[missing[i].id].copy.glyph_index, glyph)) {
+ TTF_DrawOperation *op = &ops[missing[i].id];
+ if (!AddGlyphToFont(fontdata, op->copy.glyph_font, op->copy.glyph_index, glyph)) {
ReleaseGlyph(glyph);
return false;
}
- ops[missing[i].id].copy.reserved = glyph;
+ op->copy.reserved = glyph;
}
if (all_packed) {
@@ -496,7 +499,7 @@ static bool CreateMissingGlyphs(TTF_GPUTextEngineData *enginedata, TTF_GPUTextEn
goto done;
}
- checked = SDL_CreateHashTable(NULL, 4, SDL_HashID, SDL_KeyMatchID, NULL, false, false);
+ checked = SDL_CreateGlyphHashTable(NULL);
if (!checked) {
goto done;
}
@@ -507,10 +510,10 @@ static bool CreateMissingGlyphs(TTF_GPUTextEngineData *enginedata, TTF_GPUTextEn
if (op->cmd == TTF_DRAW_COMMAND_COPY && !op->copy.reserved) {
TTF_Font *glyph_font = op->copy.glyph_font;
Uint32 glyph_index = op->copy.glyph_index;
- if (SDL_FindInHashTable(checked, (const void *)(uintptr_t)glyph_index, NULL)) {
+ if (SDL_FindInGlyphHashTable(checked, glyph_font, glyph_index, NULL)) {
continue;
}
- if (!SDL_InsertIntoHashTable(checked, (const void *)(uintptr_t)glyph_index, NULL)) {
+ if (!SDL_InsertIntoGlyphHashTable(checked, glyph_font, glyph_index, NULL)) {
goto done;
}
@@ -553,7 +556,7 @@ static bool CreateMissingGlyphs(TTF_GPUTextEngineData *enginedata, TTF_GPUTextEn
for (int i = 0; i < num_ops; ++i) {
TTF_DrawOperation *op = &ops[i];
if (op->cmd == TTF_DRAW_COMMAND_COPY && !op->copy.reserved) {
- if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)op->copy.glyph_index, (const void **)&op->copy.reserved)) {
+ if (!SDL_FindInGlyphHashTable(fontdata->glyphs, op->copy.glyph_font, op->copy.glyph_index, (const void **)&op->copy.reserved)) {
// Something is very wrong...
goto done;
}
@@ -563,7 +566,7 @@ static bool CreateMissingGlyphs(TTF_GPUTextEngineData *enginedata, TTF_GPUTextEn
result = true;
done:
- SDL_DestroyHashTable(checked);
+ SDL_DestroyGlyphHashTable(checked);
if (surfaces) {
for (int i = 0; i < num_ops; ++i) {
SDL_DestroySurface(surfaces[i]);
@@ -747,7 +750,7 @@ static TTF_GPUTextEngineTextData *CreateTextData(TTF_GPUTextEngineData *engineda
++num_glyphs;
- if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)op->copy.glyph_index, (const void **)&op->copy.reserved)) {
+ if (!SDL_FindInGlyphHashTable(fontdata->glyphs, op->copy.glyph_font, op->copy.glyph_index, (const void **)&op->copy.reserved)) {
++num_missing;
}
}
@@ -791,17 +794,15 @@ static void DestroyFontData(TTF_GPUTextEngineFontData *data)
{
if (data) {
if (data->glyphs) {
- SDL_DestroyHashTable(data->glyphs);
+ SDL_DestroyGlyphHashTable(data->glyphs);
}
SDL_free(data);
}
}
-static void NukeGlyph(const void *key, const void *value, void *unused)
+static void NukeGlyph(const void *value)
{
AtlasGlyph *glyph = (AtlasGlyph *)value;
- (void)key;
- (void)unused;
ReleaseGlyph(glyph);
}
@@ -813,7 +814,7 @@ static TTF_GPUTextEngineFontData *CreateFontData(TTF_GPUTextEngineData *engineda
}
data->font = font;
data->generation = font_generation;
- data->glyphs = SDL_CreateHashTable(NULL, 4, SDL_HashID, SDL_KeyMatchID, NukeGlyph, false, false);
+ data->glyphs = SDL_CreateGlyphHashTable(NukeGlyph);
if (!data->glyphs) {
DestroyFontData(data);
return NULL;
diff --git a/src/SDL_hashtable_ttf.c b/src/SDL_hashtable_ttf.c
new file mode 100644
index 00000000..e14c2560
--- /dev/null
+++ b/src/SDL_hashtable_ttf.c
@@ -0,0 +1,82 @@
+/*
+ SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
+ Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include <SDL3_ttf/SDL_ttf.h>
+
+#include "SDL_hashtable.h"
+#include "SDL_hashtable_ttf.h"
+
+typedef struct GlyphHashtableKey {
+ TTF_Font *font;
+ Uint32 glyph_index;
+} GlyphHashtableKey;
+
+static Uint32 SDL_HashGlyphHashtableKey(const void *key, void *unused)
+{
+ (void)unused;
+ return SDL_murmur3_32(key, sizeof(GlyphHashtableKey), 0);
+}
+
+static bool SDL_KeyMatchGlyphHashtableKey(const void *a, const void *b, void *unused)
+{
+ (void)unused;
+ GlyphHashtableKey *A = (GlyphHashtableKey *)a;
+ GlyphHashtableKey *B = (GlyphHashtableKey *)b;
+ return (A->font == B->font && A->glyph_index == B->glyph_index);
+}
+
+static void SDL_NukeFreeGlyphHashtableKey(const void *key, const void *value, void *data)
+{
+ SDL_GlyphHashTable_NukeFn nukefn = (SDL_GlyphHashTable_NukeFn)data;
+
+ if (nukefn) {
+ nukefn(value);
+ }
+ SDL_free((void *)key);
+}
+
+SDL_HashTable *SDL_CreateGlyphHashTable(SDL_GlyphHashTable_NukeFn nukefn)
+{
+ const int num_buckets = 4; // FIXME: Is this a good value?
+ return SDL_CreateHashTable(nukefn, num_buckets, SDL_HashGlyphHashtableKey, SDL_KeyMatchGlyphHashtableKey, SDL_NukeFreeGlyphHashtableKey, false, false);
+}
+
+bool SDL_InsertIntoGlyphHashTable(SDL_HashTable *table, TTF_Font *font, Uint32 glyph_index, const void *value)
+{
+ GlyphHashtableKey *key = (GlyphHashtableKey *)SDL_calloc(1, sizeof(*key));
+ key->font = font;
+ key->glyph_index = glyph_index;
+ return SDL_InsertIntoHashTable(table, key, value);
+}
+
+bool SDL_FindInGlyphHashTable(SDL_HashTable *table, TTF_Font *font, Uint32 glyph_index, const void **value)
+{
+ GlyphHashtableKey key;
+ SDL_zero(key);
+ key.font = font;
+ key.glyph_index = glyph_index;
+ return SDL_FindInHashTable(table, &key, value);
+}
+
+void SDL_DestroyGlyphHashTable(SDL_HashTable *table)
+{
+ SDL_DestroyHashTable(table);
+}
+
diff --git a/src/SDL_hashtable_ttf.h b/src/SDL_hashtable_ttf.h
new file mode 100644
index 00000000..a19b82e5
--- /dev/null
+++ b/src/SDL_hashtable_ttf.h
@@ -0,0 +1,28 @@
+/*
+ SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
+ Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+typedef void (*SDL_GlyphHashTable_NukeFn)(const void *value);
+
+extern SDL_HashTable *SDL_CreateGlyphHashTable(SDL_GlyphHashTable_NukeFn nukefn);
+extern bool SDL_InsertIntoGlyphHashTable(SDL_HashTable *table, TTF_Font *font, Uint32 glyph_index, const void *value);
+extern bool SDL_FindInGlyphHashTable(SDL_HashTable *table, TTF_Font *font, Uint32 glyph_index, const void **value);
+extern void SDL_DestroyGlyphHashTable(SDL_HashTable *table);
+
diff --git a/src/SDL_renderer_textengine.c b/src/SDL_renderer_textengine.c
index 3ff42e1f..d5521934 100644
--- a/src/SDL_renderer_textengine.c
+++ b/src/SDL_renderer_textengine.c
@@ -21,6 +21,7 @@
#include <SDL3_ttf/SDL_textengine.h>
#include "SDL_hashtable.h"
+#include "SDL_hashtable_ttf.h"
#define ATLAS_TEXTURE_SIZE 1024
@@ -321,9 +322,9 @@ static bool UpdateGlyph(AtlasGlyph *glyph, SDL_Surface *surface)
return true;
}
-static bool AddGlyphToFont(TTF_RendererTextEngineFontData *fontdata, Uint32 glyph_index, AtlasGlyph *glyph)
+static bool AddGlyphToFont(TTF_RendererTextEngineFontData *fontdata, TTF_Font *glyph_font, Uint32 glyph_index, AtlasGlyph *glyph)
{
- if (!SDL_InsertIntoHashTable(fontdata->glyphs, (const void *)(uintptr_t)glyph_index, glyph)) {
+ if (!SDL_InsertIntoGlyphHashTable(fontdata->glyphs, glyph_font, glyph_index, glyph)) {
return false;
}
return true;
@@ -345,12 +346,13 @@ static bool ResolveMissingGlyphs(TTF_RendererTextEngineData *enginedata, AtlasTe
return false;
}
- if (!AddGlyphToFont(fontdata, ops[missing[i].id].copy.glyph_index, glyph)) {
+ TTF_DrawOperation *op = &ops[missing[i].id];
+ if (!AddGlyphToFont(fontdata, op->copy.glyph_font, op->copy.glyph_index, glyph)) {
ReleaseGlyph(glyph);
return false;
}
- ops[missing[i].id].copy.reserved = glyph;
+ op->copy.reserved = glyph;
// Remove this from the missing entries
--num_missing;
@@ -381,12 +383,13 @@ static bool ResolveMissingGlyphs(TTF_RendererTextEngineData *enginedata, AtlasTe
return false;
}
- if (!AddGlyphToFont(fontdata, ops[missing[i].id].copy.glyph_index, glyph)) {
+ TTF_DrawOperation *op = &ops[missing[i].id];
+ if (!AddGlyphToFont(fontdata, op->copy.glyph_font, op->copy.glyph_index, glyph)) {
ReleaseGlyph(glyph);
return false;
}
- ops[missing[i].id].copy.reserved = glyph;
+ op->copy.reserved = glyph;
}
if (all_packed) {
@@ -430,7 +433,7 @@ static bool CreateMissingGlyphs(TTF_RendererTextEngineData *enginedata, TTF_Rend
goto done;
}
- checked = SDL_CreateHashTable(NULL, 4, SDL_HashID, SDL_KeyMatchID, NULL, false, false);
+ checked = SDL_CreateGlyphHashTable(NULL);
if (!checked) {
goto done;
}
@@ -441,10 +444,10 @@ static bool CreateMissingGlyphs(TTF_RendererTextEngineData *enginedata, TTF_Rend
if (op->cmd == TTF_DRAW_COMMAND_COPY && !op->copy.reserved) {
TTF_Font *glyph_font = op->copy.glyph_font;
Uint32 glyph_index = op->copy.glyph_index;
- if (SDL_FindInHashTable(checked, (const void *)(uintptr_t)glyph_index, NULL)) {
+ if (SDL_FindInGlyphHashTable(checked, glyph_font, glyph_index, NULL)) {
continue;
}
- if (!SDL_InsertIntoHashTable(checked, (const void *)(uintptr_t)glyph_index, NULL)) {
+ if (!SDL_InsertIntoGlyphHashTable(checked, glyph_font, glyph_index, NULL)) {
goto done;
}
@@ -486,7 +489,7 @@ static bool CreateMissingGlyphs(TTF_RendererTextEngineData *enginedata, TTF_Rend
for (int i = 0; i < num_ops; ++i) {
TTF_DrawOperation *op = &ops[i];
if (op->cmd == TTF_DRAW_COMMAND_COPY && !op->copy.reserved) {
- if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)op->copy.glyph_index, (const void **)&op->copy.reserved)) {
+ if (!SDL_FindInGlyphHashTable(fontdata->glyphs, op->copy.glyph_font, op->copy.glyph_index, (const void **)&op->copy.reserved)) {
// Something is very wrong...
goto done;
}
@@ -496,7 +499,7 @@ static bool CreateMissingGlyphs(TTF_RendererTextEngineData *enginedata, TTF_Rend
result = true;
done:
- SDL_DestroyHashTable(checked);
+ SDL_DestroyGlyphHashTable(checked);
if (surfaces) {
for (int i = 0; i < num_ops; ++i) {
SDL_DestroySurface(surfaces[i]);
@@ -659,7 +662,7 @@ static TTF_RendererTextEngineTextData *CreateTextData(TTF_RendererTextEngineData
++num_glyphs;
- if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)op->copy.glyph_index, (const void **)&op->copy.reserved)) {
+ if (!SDL_FindInGlyphHashTable(fontdata->glyphs, op->copy.glyph_font, op->copy.glyph_index, (const void **)&op->copy.reserved)) {
++num_missing;
}
}
@@ -703,17 +706,15 @@ static void DestroyFontData(TTF_RendererTextEngineFontData *data)
{
if (data) {
if (data->glyphs) {
- SDL_DestroyHashTable(data->glyphs);
+ SDL_DestroyGlyphHashTable(data->glyphs);
}
SDL_free(data);
}
}
-static void NukeGlyph(const void *key, const void *value, void *unused)
+static void NukeGlyph(const void *value)
{
AtlasGlyph *glyph = (AtlasGlyph *)value;
- (void)key;
- (void)unused;
ReleaseGlyph(glyph);
}
@@ -725,7 +726,7 @@ static TTF_RendererTextEngineFontData *CreateFontData(TTF_RendererTextEngineData
}
data->font = font;
data->generation = font_generation;
- data->glyphs = SDL_CreateHashTable(NULL, 4, SDL_HashID, SDL_KeyMatchID, NukeGlyph, false, false);
+ data->glyphs = SDL_CreateGlyphHashTable(NukeGlyph);
if (!data->glyphs) {
DestroyFontData(data);
return NULL;
diff --git a/src/SDL_surface_textengine.c b/src/SDL_surface_textengine.c
index 5f1a3565..10e24978 100644
--- a/src/SDL_surface_textengine.c
+++ b/src/SDL_surface_textengine.c
@@ -21,6 +21,7 @@
#include <SDL3_ttf/SDL_textengine.h>
#include "SDL_hashtable.h"
+#include "SDL_hashtable_ttf.h"
typedef struct TTF_SurfaceTextEngineGlyphData
@@ -84,7 +85,7 @@ static TTF_SurfaceTextEngineGlyphData *GetGlyphData(TTF_SurfaceTextEngineFontDat
{
TTF_SurfaceTextEngineGlyphData *data;
- if (!SDL_FindInHashTable(fontdata->glyphs, (const void *)(uintptr_t)glyph_index, (const void **)&data)) {
+ if (!SDL_FindInGlyphHashTable(fontdata->glyphs, glyph_font, glyph_index, (const void **)&data)) {
SDL_Surface *surface = TTF_GetGlyphImageForIndex(glyph_font, glyph_index);
if (!surface) {
return NULL;
@@ -95,7 +96,7 @@ static TTF_SurfaceTextEngineGlyphData *GetGlyphData(TTF_SurfaceTextEngineFontDat
return NULL;
}
- if (!SDL_InsertIntoHashTable(fontdata->glyphs, (const void *)(uintptr_t)glyph_index, data)) {
+ if (!SDL_InsertIntoGlyphHashTable(fontdata->glyphs, glyph_font, glyph_index, data)) {
DestroyGlyphData(data);
return NULL;
}
@@ -159,16 +160,14 @@ static void DestroyFontData(TTF_SurfaceTextEngineFontData *data)
}
if (data->glyphs) {
- SDL_DestroyHashTable(data->glyphs);
+ SDL_DestroyGlyphHashTable(data->glyphs);
}
SDL_free(data);
}
-static void NukeGlyphData(const void *key, const void *value, void *unused)
+static void NukeGlyphData(const void *value)
{
TTF_SurfaceTextEngineGlyphData *data = (TTF_SurfaceTextEngineGlyphData *)value;
- (void)key;
- (void)unused;
DestroyGlyphData(data);
}
@@ -181,7 +180,7 @@ static TTF_SurfaceTextEngineFontData *CreateFontData(TTF_SurfaceTextEngineData *
data->font = font;
data->generation = font_generation;
- data->glyphs = SDL_CreateHashTable(NULL, 4, SDL_HashID, SDL_KeyMatchID, NukeGlyphData, false, false);
+ data->glyphs = SDL_CreateGlyphHashTable(NukeGlyphData);
if (!data->glyphs) {
DestroyFontData(data);
return NULL;