Add multi-font support to the final text-rendering backend (SDL_ttf)

This commit is contained in:
Henrik Rydgård committed 2025-11-09 08:52:21 +01:00
1 parent 582c2e28ca
commit bf5e524243
3 files changed
+53 -41

No files matched your search

+45 -38
View File
@@ -187,12 +187,15 @@ void TextDrawerSDL::PrepareFallbackFonts(std::string_view locale) {
}
uint32_t TextDrawerSDL::CheckMissingGlyph(std::string_view text) {
auto iter = fontMap_.find(fontHash_);
auto iter = fontMap_.find(fontStyle_);
if (iter == fontMap_.end()) {
return 0;
}
TTF_Font *font = iter->second;
if (!font) {
return 0;
}
UTF8 utf8Decoded(text);
uint32_t missingGlyph = 0;
@@ -245,48 +248,42 @@ int TextDrawerSDL::FindFallbackFonts(uint32_t missingGlyph, int ptSize) {
return -1;
}
uint32_t TextDrawerSDL::SetOrCreateFont(const FontStyle &style) {
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
void TextDrawerSDL::SetOrCreateFont(const FontStyle &style) {
auto iter = fontMap_.find(style);
if (iter != fontMap_.end()) {
fontHash_ = fontHash;
return fontHash;
fontStyle_ = style;
return;
}
std::string useFont = !style.fontName.empty() ? style.fontName : std::string("Roboto-Condensed.ttf");
const int ptSize = (int)((style.sizePts + 6) / dpiScale_);
std::string useFont = "assets/" + GetFilenameForFontStyle(style) + ".ttf";
TTF_Font *font = TTF_OpenFont(useFont.c_str(), ptSize);
if (!font) {
File::FileInfo fileInfo;
g_VFS.GetFileInfo("Roboto-Condensed.ttf", &fileInfo);
font = TTF_OpenFont(fileInfo.fullName.c_str(), ptSize);
if (loadedFonts_.find(useFont) == loadedFonts_.end()) {
int ptSize = static_cast<int>(style.sizePts / dpiScale_ * 1.25f);
TTF_Font *font = TTF_OpenFont(useFont.c_str(), ptSize);
if (!font) {
ERROR_LOG(Log::G3D, "Failed to load font file %s", useFont.c_str());
}
// Still, mark it with a nullptr to avoid retrying.
loadedFonts_[useFont] = font;
}
fontMap_[fontHash] = font;
fontHash_ = fontHash;
return fontHash;
}
void TextDrawerSDL::SetFont(uint32_t fontHandle) {
uint32_t fontHash = fontHandle;
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
fontHash_ = fontHandle;
} else {
ERROR_LOG(Log::G3D, "Invalid font handle %08x", fontHandle);
}
fontMap_[style] = loadedFonts_[useFont];
fontStyle_ = style;
}
void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float *h) {
TTF_Font *font = fontMap_.find(fontHash_)->second;
int ptSize = TTF_FontHeight(font) / 1.35;
TTF_Font *font = fontMap_.find(fontStyle_)->second;
if (!font) {
*w = 1.0f;
*h = 1.0f;
return;
}
uint32_t missingGlyph = CheckMissingGlyph(str);
if (missingGlyph) {
int ptSize = static_cast<int>(fontStyle_.sizePts / dpiScale_ * 1.25f);
int fallbackFont = FindFallbackFonts(missingGlyph, ptSize);
if (fallbackFont >= 0 && fallbackFont < (int)fallbackFonts_.size()) {
font = fallbackFonts_[fallbackFont];
@@ -300,8 +297,8 @@ void TextDrawerSDL::MeasureStringInternal(std::string_view str, float *w, float
std::string text(str);
TTF_SizeUTF8(font, text.c_str(), &width, &height);
*w = width;
*h = height;
*w = (float)width;
*h = (float)height;
}
bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) {
@@ -322,14 +319,17 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
processedStr.push_back(' ');
}
auto fontIter = fontMap_.find(fontHash_);
auto fontIter = fontMap_.find(fontStyle_);
if (fontIter == fontMap_.end()) {
ERROR_LOG(Log::G3D, "Font hash not in map: %08x", fontHash_);
ERROR_LOG(Log::G3D, "Font style not in map");
return false;
}
TTF_Font *font = fontIter->second;
int ptSize = TTF_FontHeight(font) / 1.35;
if (!font) {
return false;
}
int ptSize = TTF_FontHeight(font) / 1.25;
uint32_t missingGlyph = CheckMissingGlyph(processedStr);
@@ -392,12 +392,19 @@ bool TextDrawerSDL::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStrin
}
void TextDrawerSDL::ClearFonts() {
for (auto iter : fontMap_) {
TTF_CloseFont(iter.second);
for (auto iter : loadedFonts_) {
if (iter.second) {
TTF_CloseFont(iter.second);
}
}
for (auto iter : fallbackFonts_) {
TTF_CloseFont(iter);
if (iter) {
TTF_CloseFont(iter);
}
}
// We wipe all the maps, including fontMap_. Everything it contains is also in loadedFonts_ which is cleared above.
loadedFonts_.clear();
fontMap_.clear();
fallbackFonts_.clear();
}
+6 -3
View File
@@ -19,8 +19,7 @@ public:
TextDrawerSDL(Draw::DrawContext *draw);
~TextDrawerSDL();
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
void SetOrCreateFont(const FontStyle &style) override;
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
protected:
@@ -34,7 +33,11 @@ private:
uint32_t CheckMissingGlyph(std::string_view text);
int FindFallbackFonts(uint32_t missingGlyph, int ptSize);
std::map<uint32_t, TTF_Font *> fontMap_;
// NOTE: This can contain dupes. The below doesn't.
std::map<FontStyle, TTF_Font *> fontMap_;
// These are the ones we free. fontMap points into this map.
std::map<std::string, TTF_Font *> loadedFonts_;
std::vector<TTF_Font *> fallbackFonts_;
std::vector<std::pair<std::string, int>> fallbackFontPaths_; // path and font face index
+2
View File
@@ -32,12 +32,14 @@ void ApplyGravity(const Bounds &outer, const Margins &margins, float w, float h,
case Gravity::G_LEFT: inner.x = outer.x + margins.left; break;
case Gravity::G_RIGHT: inner.x = outer.x + outer.w - w - margins.right; break;
case Gravity::G_HCENTER: inner.x = outer.x + (outer.w - w) * 0.5f; break;
default: break;
}
switch ((Gravity)((int)gravity & (int)Gravity::G_VERTMASK)) {
case Gravity::G_TOP: inner.y = outer.y + margins.top; break;
case Gravity::G_BOTTOM: inner.y = outer.y + outer.h - h - margins.bottom; break;
case Gravity::G_VCENTER: inner.y = outer.y + (outer.h - h) * 0.5f; break;
default: break;
}
}