Codechange: MissingGlyphSearcher now contains which fontsizes to search for

This commit is contained in:
Peter Nelson
2026-04-02 10:00:38 +01:00
committed by Peter Nelson
parent 3c9a75a387
commit cdfbb113ce
12 changed files with 74 additions and 88 deletions
+17 -5
View File
@@ -46,16 +46,14 @@ FontCacheSettings _fcsettings;
/**
* We would like to have a fallback font as the current one
* doesn't contain all characters we need.
* This function must set all fonts of settings.
* @param settings the settings to overwrite the fontname of.
* @param language_isocode the language, e.g. en_GB.
* @param callback The function to call to check for missing glyphs.
* @return true if a font has been set, false otherwise.
*/
/* static */ bool FontProviderManager::FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
/* static */ bool FontProviderManager::FindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback)
{
return std::ranges::any_of(FontProviderManager::GetProviders(),
[&](auto *provider) { return provider->FindFallbackFont(settings, language_isocode, callback); });
[&](auto *provider) { return provider->FindFallbackFont(language_isocode, callback); });
}
int FontCache::GetDefaultFontHeight(FontSize fs)
@@ -157,7 +155,7 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
*/
static bool IsDefaultFont(const FontCacheSubSetting &setting)
{
return setting.font.empty() && setting.os_handle == nullptr;
return setting.font.empty() && !setting.os_handle.has_value();
}
/**
@@ -231,6 +229,20 @@ std::string GetFontCacheFontName(FontSize fs)
FontCache::caches[fs] = std::move(fc);
}
/**
* Add a fallback font, with optional OS-specific handle.
* @param fontsizes Fontsizes to add fallback to.
* @param name Name of font to add.
* @param os_handle OS-specific handle or data of font.
*/
/* static */ void FontCache::AddFallback(FontSizes fontsizes, std::string_view name, const std::any &os_handle)
{
for (FontSize fs : fontsizes) {
GetFontCacheSubSetting(fs)->font = name;
GetFontCacheSubSetting(fs)->os_handle = os_handle;
}
}
/**
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
* @param fontsizes Font sizes to be initialised.
+7 -6
View File
@@ -10,6 +10,7 @@
#ifndef FONTCACHE_H
#define FONTCACHE_H
#include <any>
#include "gfx_type.h"
#include "provider_manager.h"
#include "spritecache_type.h"
@@ -47,6 +48,8 @@ public:
static int GetDefaultFontHeight(FontSize fs);
static void AddFallback(FontSizes fontsizes, std::string_view name, const std::any &os_handle = {});
/**
* Get the FontSize of the font.
* @return The FontSize.
@@ -186,7 +189,7 @@ struct FontCacheSubSetting {
std::string font; ///< The name of the font, or path to the font.
uint size; ///< The (requested) size of the font.
const void *os_handle = nullptr; ///< Optional native OS font info. Only valid during font search.
std::any os_handle; ///< Optional native OS font info.
};
/** Settings for the four different fonts. */
@@ -254,19 +257,17 @@ public:
/**
* We would like to have a fallback font as the current one
* doesn't contain all characters we need.
* This function must set all fonts of settings.
* @param settings The settings to overwrite the fontname of.
* @param language_isocode The language, e.g. en_GB.
* @param callback The function to call to check for missing glyphs.
* @return \c true if a font has been set, false otherwise.
* @return \c true if a font has been set, \c false otherwise.
*/
virtual bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) const = 0;
virtual bool FindFallbackFont(const std::string &language_isocode, class MissingGlyphSearcher *callback) const = 0;
};
class FontProviderManager : ProviderManager<FontCacheFactory> {
public:
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype);
static bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
static bool FindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback);
};
/* Implemented in spritefontcache.cpp */
+5 -3
View File
@@ -242,7 +242,9 @@ public:
/* If font is an absolute path to a ttf, try loading that first. */
int32_t index = 0;
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
if (auto ptr = std::any_cast<int32_t>(&settings->os_handle)) {
index = *ptr;
}
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
if (error != FT_Err_Ok) {
@@ -266,10 +268,10 @@ public:
return LoadFont(fs, face, font, GetFontCacheFontSize(fs));
}
bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) const override
bool FindFallbackFont(const std::string &language_isocode, class MissingGlyphSearcher *callback) const override
{
#ifdef WITH_FONTCONFIG
if (FontConfigFindFallbackFont(settings, language_isocode, callback)) return true;
if (FontConfigFindFallbackFont(language_isocode, callback)) return true;
#endif /* WITH_FONTCONFIG */
return false;
+1 -1
View File
@@ -166,7 +166,7 @@ public:
return std::make_unique<SpriteFontCache>(fs);
}
bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) const override
bool FindFallbackFont(const std::string &, class MissingGlyphSearcher *) const override
{
return false;
}
+4 -4
View File
@@ -236,7 +236,7 @@ public:
return std::make_unique<CoreTextFontCache>(fs, std::move(font_ref), GetFontCacheFontSize(fs));
}
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) const override
bool FindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback) const override
{
/* Determine fallback font using CoreText. This uses the language isocode
* to find a suitable font. CoreText is available from 10.5 onwards. */
@@ -282,7 +282,7 @@ public:
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
if (symbolic_traits & kCTFontBoldTrait) continue;
/* Select monospaced fonts if asked for. */
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->missing_fontsizes.Test(FS_MONO)) continue;
/* Get font name. */
char buffer[128];
@@ -300,7 +300,7 @@ public:
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
/* Save result. */
callback->SetFontNames(settings, name);
FontCache::AddFallback(callback->missing_fontsizes, name);
if (!callback->FindMissingGlyphs()) {
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
result = true;
@@ -312,7 +312,7 @@ public:
if (!result) {
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
callback->SetFontNames(settings, "Arial Unicode MS");
FontCache::AddFallback(callback->missing_fontsizes, "Arial Unicode MS");
result = !callback->FindMissingGlyphs();
}
+11 -5
View File
@@ -139,7 +139,13 @@ static int GetPreferredWeightDistance(int weight)
return 0;
}
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
/**
* Use FontConfig to find a fallback font.
* @param language_isocode The language, e.g. en_GB.
* @param callback The function to call to check for missing glyphs.
* @return \c true if a font has been set, \c false otherwise.
*/
bool FontConfigFindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback)
{
bool ret = false;
@@ -174,7 +180,7 @@ bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &
/* Get a font with the right spacing .*/
int value = 0;
FcPatternGetInteger(font, FC_SPACING, 0, &value);
if (callback->Monospace() != (value == FC_MONO) && value != FC_DUAL) continue;
if (callback->missing_fontsizes.Test(FS_MONO) != (value == FC_MONO) && value != FC_DUAL) continue;
/* Do not use those that explicitly say they're slanted. */
FcPatternGetInteger(font, FC_SLANT, 0, &value);
@@ -190,7 +196,7 @@ bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &
res = FcPatternGetInteger(font, FC_INDEX, 0, &index);
if (res != FcResultMatch) continue;
callback->SetFontNames(settings, FromFcString(file), &index);
FontCache::AddFallback(callback->missing_fontsizes, FromFcString(file), index);
bool missing = callback->FindMissingGlyphs();
Debug(fontcache, 1, "Font \"{}\" misses{} glyphs", FromFcString(file), missing ? "" : " no");
@@ -204,7 +210,7 @@ bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &
if (best_font == nullptr) return false;
callback->SetFontNames(settings, best_font, &best_index);
FontCache::LoadFontCaches(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
FontCache::AddFallback(callback->missing_fontsizes, best_font, best_index);
FontCache::LoadFontCaches(callback->missing_fontsizes);
return true;
}
+1 -1
View File
@@ -19,7 +19,7 @@
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
bool FontConfigFindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback);
#endif /* WITH_FONTCONFIG */
+5 -7
View File
@@ -31,7 +31,6 @@
#include "../../safeguards.h"
struct EFCParam {
FontCacheSettings *settings;
LOCALESIGNATURE locale;
MissingGlyphSearcher *callback;
std::vector<std::wstring> fonts;
@@ -58,7 +57,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
/* Don't use SYMBOL fonts */
if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
/* Use monospaced fonts when asked for it. */
if (info->callback->Monospace() && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH)) return 1;
if (info->callback->missing_fontsizes.Test(FS_MONO) && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH)) return 1;
/* The font has to have at least one of the supported locales to be usable. */
auto check_bitfields = [&]() {
@@ -77,7 +76,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
char font_name[MAX_PATH];
convert_from_fs(logfont->elfFullName, font_name);
info->callback->SetFontNames(info->settings, font_name, &logfont->elfLogFont);
FontCache::AddFallback(info->callback->missing_fontsizes, font_name, logfont->elfLogFont);
if (info->callback->FindMissingGlyphs()) return 1;
Debug(fontcache, 1, "Fallback font: {}", font_name);
return 0; // stop enumerating
@@ -287,8 +286,8 @@ public:
/* If a GDI font description is present, e.g. from the automatic font
* fallback search, use it. Otherwise, try to resolve it by font name. */
if (settings->os_handle != nullptr) {
logfont = *(const LOGFONT *)settings->os_handle;
if (auto ptr = std::any_cast<LOGFONT>(&settings->os_handle)) {
logfont = *ptr;
} else if (font.find('.') != std::string::npos) {
/* Might be a font file name, try load it. */
if (!TryLoadFontFromFile(font, logfont)) {
@@ -304,7 +303,7 @@ public:
return LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
}
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) const override
bool FindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback) const override
{
Debug(fontcache, 1, "Trying fallback fonts");
EFCParam langInfo;
@@ -314,7 +313,6 @@ public:
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
return false;
}
langInfo.settings = settings;
langInfo.callback = callback;
LOGFONT font;
+13 -26
View File
@@ -2312,7 +2312,7 @@ std::string_view GetCurrentLanguageIsoCode()
*/
bool MissingGlyphSearcher::FindMissingGlyphs()
{
FontCache::LoadFontCaches(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
FontCache::LoadFontCaches(this->fontsizes);
this->Reset();
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
@@ -2325,6 +2325,10 @@ bool MissingGlyphSearcher::FindMissingGlyphs()
} else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && fc->MapCharToGlyph(c, false) == 0) {
/* The character is printable, but not in the normal font. This is the case we were testing for. */
Debug(fontcache, 0, "Font is missing glyphs to display char 0x{:X} in {} font size", static_cast<uint32_t>(c), FontSizeToName(size));
/* For now, assume all fontsizes need searching if any are missing. */
this->missing_fontsizes = this->fontsizes;
return true;
}
}
@@ -2334,6 +2338,10 @@ bool MissingGlyphSearcher::FindMissingGlyphs()
/** Helper for searching through the language pack. */
class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
public:
LanguagePackGlyphSearcher() : MissingGlyphSearcher(FONTSIZES_REQUIRED) {}
private:
uint i; ///< Iterator for the primary language tables.
uint j; ///< Iterator for the secondary language tables.
@@ -2362,24 +2370,6 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
return ret;
}
bool Monospace() override
{
return false;
}
void SetFontNames([[maybe_unused]] FontCacheSettings *settings, [[maybe_unused]] std::string_view font_name, [[maybe_unused]] const void *os_data) override
{
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
settings->small.font = font_name;
settings->medium.font = font_name;
settings->large.font = font_name;
settings->small.os_handle = os_data;
settings->medium.os_handle = os_data;
settings->large.os_handle = os_data;
#endif
}
};
/**
@@ -2406,10 +2396,7 @@ void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
bool any_font_configured = !_fcsettings.medium.font.empty();
FontCacheSettings backup = _fcsettings;
_fcsettings.mono.os_handle = nullptr;
_fcsettings.medium.os_handle = nullptr;
bad_font = !FontProviderManager::FindFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
bad_font = !FontProviderManager::FindFallbackFont(_langpack.langpack->isocode, searcher);
_fcsettings = std::move(backup);
@@ -2428,7 +2415,7 @@ void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
/* Our fallback font does miss characters too, so keep the
* user chosen font as that is more likely to be any good than
* the wild guess we made */
FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
FontCache::LoadFontCaches(searcher->fontsizes);
}
}
#endif
@@ -2445,12 +2432,12 @@ void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
ShowErrorMessage(GetEncodedString(STR_JUST_RAW_STRING, std::move(err_str)), {}, WL_WARNING);
/* Reset the font width */
LoadStringWidthTable(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
LoadStringWidthTable(searcher->fontsizes);
return;
}
/* Update the font with cache */
LoadStringWidthTable(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
LoadStringWidthTable(searcher->fontsizes);
#if !(defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ)) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA)
/*
+9 -14
View File
@@ -156,9 +156,18 @@ EncodedString GetEncodedString(StringID string, const Args&... args)
*/
class MissingGlyphSearcher {
public:
/**
* Create this glyph searcher.
* @param fontsizes Font sizes to consider.
*/
MissingGlyphSearcher(FontSizes fontsizes) : fontsizes(fontsizes) {}
/** Ensure the destructor of the sub classes are called as well. */
virtual ~MissingGlyphSearcher() = default;
const FontSizes fontsizes; ///< Font sizes this searcher will try to find.
FontSizes missing_fontsizes{}; ///< Font sizes to actually search for.
/**
* Get the next string to search through.
* @return The next string or nullopt if there is none.
@@ -176,20 +185,6 @@ public:
*/
virtual void Reset() = 0;
/**
* Whether to search for a monospace font or not.
* @return True if searching for monospace.
*/
virtual bool Monospace() = 0;
/**
* Set the right font names.
* @param settings The settings to modify.
* @param font_name The new font name.
* @param os_data Opaque pointer to OS-specific data.
*/
virtual void SetFontNames(struct FontCacheSettings *settings, std::string_view font_name, const void *os_data = nullptr) = 0;
bool FindMissingGlyphs();
};
+1 -14
View File
@@ -83,7 +83,7 @@ static WindowDesc _textfile_desc(
_nested_textfile_widgets
);
TextfileWindow::TextfileWindow(Window *parent, TextfileType file_type) : Window(_textfile_desc), file_type(file_type)
TextfileWindow::TextfileWindow(Window *parent, TextfileType file_type) : Window(_textfile_desc), MissingGlyphSearcher(FS_MONO), file_type(file_type)
{
/* Init of nested tree is deferred.
* TextfileWindow::ConstructWindow must be called by the inheriting window. */
@@ -754,19 +754,6 @@ bool TextfileWindow::IsTextWrapped() const
return this->lines[this->search_iterator++].text;
}
/* virtual */ bool TextfileWindow::Monospace()
{
return true;
}
/* virtual */ void TextfileWindow::SetFontNames([[maybe_unused]] FontCacheSettings *settings, [[maybe_unused]] std::string_view font_name, [[maybe_unused]] const void *os_data)
{
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
settings->mono.font = font_name;
settings->mono.os_handle = os_data;
#endif
}
#if defined(WITH_ZLIB)
/**
-2
View File
@@ -38,8 +38,6 @@ struct TextfileWindow : public Window, MissingGlyphSearcher {
void Reset() override;
FontSize DefaultSize() override;
std::optional<std::string_view> NextString() override;
bool Monospace() override;
void SetFontNames(FontCacheSettings *settings, std::string_view font_name, const void *os_data) override;
void ScrollToLine(size_t line);
bool IsTextWrapped() const;