diff --git a/src/fontcache.cpp b/src/fontcache.cpp index f75ff1e0a4..1136d93db8 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -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. diff --git a/src/fontcache.h b/src/fontcache.h index a9f2b26ab9..e670ec3a99 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -10,6 +10,7 @@ #ifndef FONTCACHE_H #define FONTCACHE_H +#include #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 { public: static std::unique_ptr 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 */ diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp index 69b88fb20c..f954775bc4 100644 --- a/src/fontcache/freetypefontcache.cpp +++ b/src/fontcache/freetypefontcache.cpp @@ -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(settings->os_handle); + if (auto ptr = std::any_cast(&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; diff --git a/src/fontcache/spritefontcache.cpp b/src/fontcache/spritefontcache.cpp index 009937e92c..7dfe936ae0 100644 --- a/src/fontcache/spritefontcache.cpp +++ b/src/fontcache/spritefontcache.cpp @@ -166,7 +166,7 @@ public: return std::make_unique(fs); } - bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) const override + bool FindFallbackFont(const std::string &, class MissingGlyphSearcher *) const override { return false; } diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index 73f3174a31..bc29e29467 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -236,7 +236,7 @@ public: return std::make_unique(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(); } diff --git a/src/os/unix/font_unix.cpp b/src/os/unix/font_unix.cpp index ff7f2f7028..267502c7f1 100644 --- a/src/os/unix/font_unix.cpp +++ b/src/os/unix/font_unix.cpp @@ -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; } diff --git a/src/os/unix/font_unix.h b/src/os/unix/font_unix.h index d47f28150e..1dac79182c 100644 --- a/src/os/unix/font_unix.h +++ b/src/os/unix/font_unix.h @@ -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 */ diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index 74c6487064..3e8ef81814 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -31,7 +31,6 @@ #include "../../safeguards.h" struct EFCParam { - FontCacheSettings *settings; LOCALESIGNATURE locale; MissingGlyphSearcher *callback; std::vector 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(&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; diff --git a/src/strings.cpp b/src/strings.cpp index ec49c8d94b..0a2af8e387 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -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(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) /* diff --git a/src/strings_func.h b/src/strings_func.h index 8ef2dd4d04..159e5597ab 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -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(); }; diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index ac95ef4d4f..b155c284df 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -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) /** diff --git a/src/textfile_gui.h b/src/textfile_gui.h index a8211f0988..e66f382c64 100644 --- a/src/textfile_gui.h +++ b/src/textfile_gui.h @@ -38,8 +38,6 @@ struct TextfileWindow : public Window, MissingGlyphSearcher { void Reset() override; FontSize DefaultSize() override; std::optional 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;