1
0
Fork 0

Codechange: Use ProviderManager interface to register FontCache factories.

This removes use of #ifdefs to select the appropriate loader, and also replaces FontCache self-registration.
pull/13303/head
Peter Nelson 2025-07-15 19:47:08 +01:00
parent bb6ef04d7a
commit 89f4e5da4e
No known key found for this signature in database
GPG Key ID: 8EF8F0A467DF75ED
14 changed files with 398 additions and 329 deletions

View File

@ -2369,7 +2369,7 @@ static bool ConFont(std::span<std::string_view> argv)
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs); FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
/* Make sure all non sprite fonts are loaded. */ /* Make sure all non sprite fonts are loaded. */
if (!setting->font.empty() && !fc->HasParent()) { if (!setting->font.empty() && !fc->HasParent()) {
InitFontCache(fs); FontCache::LoadFontCaches(fs);
fc = FontCache::Get(fs); fc = FontCache::Get(fs);
} }
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs)); IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));

View File

@ -12,7 +12,6 @@
#include "fontdetection.h" #include "fontdetection.h"
#include "blitter/factory.hpp" #include "blitter/factory.hpp"
#include "gfx_layout.h" #include "gfx_layout.h"
#include "fontcache/spritefontcache.h"
#include "openttd.h" #include "openttd.h"
#include "settings_func.h" #include "settings_func.h"
#include "strings_func.h" #include "strings_func.h"
@ -30,22 +29,19 @@
FontCacheSettings _fcsettings; FontCacheSettings _fcsettings;
/** /**
* Create a new font cache. * Try loading a font with any fontcache factory.
* @param fs The size of the font. * @param fs Font size to load.
* @param fonttype Font type requested.
* @return FontCache of the font if loaded, or nullptr.
*/ */
FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs) /* static */ std::unique_ptr<FontCache> FontProviderManager::LoadFont(FontSize fs, FontType fonttype)
{ {
assert(this->parent == nullptr || this->fs == this->parent->fs); for (auto &provider : FontProviderManager::GetProviders()) {
FontCache::caches[this->fs] = this; auto fc = provider->LoadFont(fs, fonttype);
Layouter::ResetFontCache(this->fs); if (fc != nullptr) return fc;
} }
/** Clean everything up. */ return nullptr;
FontCache::~FontCache()
{
assert(this->parent == nullptr || this->fs == this->parent->fs);
FontCache::caches[this->fs] = this->parent;
Layouter::ResetFontCache(this->fs);
} }
int FontCache::GetDefaultFontHeight(FontSize fs) int FontCache::GetDefaultFontHeight(FontSize fs)
@ -80,12 +76,16 @@ int GetCharacterHeight(FontSize size)
} }
/* static */ FontCache *FontCache::caches[FS_END]; /* static */ std::array<std::unique_ptr<FontCache>, FS_END> FontCache::caches{};
/**
* Initialise font caches with the base sprite font cache for all sizes.
*/
/* static */ void FontCache::InitializeFontCaches() /* static */ void FontCache::InitializeFontCaches()
{ {
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) { for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
if (FontCache::caches[fs] == nullptr) new SpriteFontCache(fs); /* FontCache inserts itself into to the cache. */ if (FontCache::Get(fs) != nullptr) continue;
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::Sprite));
} }
} }
@ -126,7 +126,7 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
CheckForMissingGlyphs(); CheckForMissingGlyphs();
_fcsettings = std::move(backup); _fcsettings = std::move(backup);
} else { } else {
InitFontCache(fontsize); FontCache::LoadFontCaches(fontsize);
} }
LoadStringWidthTable(fontsize); LoadStringWidthTable(fontsize);
@ -136,15 +136,6 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
if (_save_config) SaveToConfig(); if (_save_config) SaveToConfig();
} }
#ifdef WITH_FREETYPE
extern void LoadFreeTypeFont(FontSize fs);
extern void UninitFreeType();
#elif defined(_WIN32)
extern void LoadWin32Font(FontSize fs);
#elif defined(WITH_COCOA)
extern void LoadCoreTextFont(FontSize fs);
#endif
/** /**
* Test if a font setting uses the default font. * Test if a font setting uses the default font.
* @return true iff the font is not configured and no fallback font data is present. * @return true iff the font is not configured and no fallback font data is present.
@ -211,40 +202,57 @@ std::string GetFontCacheFontName(FontSize fs)
return GetDefaultTruetypeFontFile(fs); return GetDefaultTruetypeFontFile(fs);
} }
/**
* Register a FontCache for its font size.
* @param fc FontCache to register.
*/
/* static */ void FontCache::Register(std::unique_ptr<FontCache> &&fc)
{
if (fc == nullptr) return;
FontSize fs = fc->fs;
fc->parent = std::move(FontCache::caches[fs]);
FontCache::caches[fs] = std::move(fc);
}
/** /**
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts. * (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
* @param fontsizes Font sizes to be initialised. * @param fontsizes Font sizes to be initialised.
*/ */
void InitFontCache(FontSizes fontsizes) /* static */ void FontCache::LoadFontCaches(FontSizes fontsizes)
{ {
FontCache::InitializeFontCaches(); FontCache::InitializeFontCaches();
for (FontSize fs : fontsizes) { for (FontSize fs : fontsizes) {
FontCache *fc = FontCache::Get(fs); Layouter::ResetFontCache(fs);
if (fc->HasParent()) delete fc;
#ifdef WITH_FREETYPE /* Unload everything except the sprite font cache. */
LoadFreeTypeFont(fs); while (FontCache::Get(fs)->HasParent()) {
#elif defined(_WIN32) FontCache::caches[fs] = std::move(FontCache::caches[fs]->parent);
LoadWin32Font(fs); }
#elif defined(WITH_COCOA)
LoadCoreTextFont(fs); FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType));
#endif }
}
/**
* Clear cached information for the specified font caches.
* @param fontsizes Font sizes to clear.
*/
/* static */ void FontCache::ClearFontCaches(FontSizes fontsizes)
{
for (FontSize fs : fontsizes) {
FontCache::Get(fs)->ClearFontCache();
} }
} }
/** /**
* Free everything allocated w.r.t. fonts. * Free everything allocated w.r.t. fonts.
*/ */
void UninitFontCache() /* static */ void FontCache::UninitializeFontCaches()
{ {
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) { std::ranges::generate(FontCache::caches, []() { return nullptr; });
while (FontCache::Get(fs) != nullptr) delete FontCache::Get(fs);
}
#ifdef WITH_FREETYPE
UninitFreeType();
#endif /* WITH_FREETYPE */
} }
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) #if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)

View File

@ -10,6 +10,7 @@
#ifndef FONTCACHE_H #ifndef FONTCACHE_H
#define FONTCACHE_H #define FONTCACHE_H
#include "provider_manager.h"
#include "string_type.h" #include "string_type.h"
#include "spritecache.h" #include "spritecache.h"
@ -20,18 +21,23 @@ static const GlyphID SPRITE_GLYPH = 1U << 30;
/** Font cache for basic fonts. */ /** Font cache for basic fonts. */
class FontCache { class FontCache {
protected: protected:
static FontCache *caches[FS_END]; ///< All the font caches. static std::array<std::unique_ptr<FontCache>, FS_END> caches; ///< All the font caches.
FontCache *parent; ///< The parent of this font cache. std::unique_ptr<FontCache>parent; ///< The parent of this font cache.
const FontSize fs; ///< The size of the font. const FontSize fs; ///< The size of the font.
int height = 0; ///< The height of the font. int height = 0; ///< The height of the font.
int ascender = 0; ///< The ascender value of the font. int ascender = 0; ///< The ascender value of the font.
int descender = 0; ///< The descender value of the font. int descender = 0; ///< The descender value of the font.
FontCache(FontSize fs) : fs(fs) {}
static void Register(std::unique_ptr<FontCache> &&fc);
public: public:
FontCache(FontSize fs); virtual ~FontCache() {}
virtual ~FontCache();
static void InitializeFontCaches(); static void InitializeFontCaches();
static void UninitializeFontCaches();
static void LoadFontCaches(FontSizes fontsizes);
static void ClearFontCaches(FontSizes fontsizes);
/** Default unscaled font heights. */ /** Default unscaled font heights. */
static const int DEFAULT_FONT_HEIGHT[FS_END]; static const int DEFAULT_FONT_HEIGHT[FS_END];
@ -124,7 +130,7 @@ public:
static inline FontCache *Get(FontSize fs) static inline FontCache *Get(FontSize fs)
{ {
assert(fs < FS_END); assert(fs < FS_END);
return FontCache::caches[fs]; return FontCache::caches[fs].get();
} }
static std::string GetName(FontSize fs); static std::string GetName(FontSize fs);
@ -143,13 +149,6 @@ public:
virtual bool IsBuiltInFont() = 0; virtual bool IsBuiltInFont() = 0;
}; };
inline void ClearFontCache(FontSizes fontsizes)
{
for (FontSize fs : fontsizes) {
FontCache::Get(fs)->ClearFontCache();
}
}
/** Get the Sprite for a glyph */ /** Get the Sprite for a glyph */
inline const Sprite *GetGlyph(FontSize size, char32_t key) inline const Sprite *GetGlyph(FontSize size, char32_t key)
{ {
@ -207,12 +206,37 @@ inline FontCacheSubSetting *GetFontCacheSubSetting(FontSize fs)
uint GetFontCacheFontSize(FontSize fs); uint GetFontCacheFontSize(FontSize fs);
std::string GetFontCacheFontName(FontSize fs); std::string GetFontCacheFontName(FontSize fs);
void InitFontCache(FontSizes fontsizes);
void UninitFontCache();
bool GetFontAAState(); bool GetFontAAState();
void SetFont(FontSize fontsize, const std::string &font, uint size); void SetFont(FontSize fontsize, const std::string &font, uint size);
/** Different types of font that can be loaded. */
enum class FontType : uint8_t {
Sprite, ///< Bitmap sprites from GRF files.
TrueType, ///< Scalable TrueType fonts.
};
/** Factory for FontCaches. */
class FontCacheFactory : public BaseProvider<FontCacheFactory> {
public:
FontCacheFactory(std::string_view name, std::string_view description) : BaseProvider<FontCacheFactory>(name, description)
{
ProviderManager<FontCacheFactory>::Register(*this);
}
virtual ~FontCacheFactory()
{
ProviderManager<FontCacheFactory>::Unregister(*this);
}
virtual std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) = 0;
};
class FontProviderManager : ProviderManager<FontCacheFactory> {
public:
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype);
};
/* Implemented in spritefontcache.cpp */ /* Implemented in spritefontcache.cpp */
void InitializeUnicodeGlyphMap(); void InitializeUnicodeGlyphMap();
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite); void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);

View File

@ -46,9 +46,6 @@ public:
const void *GetOSHandle() override { return &face; } const void *GetOSHandle() override { return &face; }
}; };
FT_Library _ft_library = nullptr;
/** /**
* Create a new FreeTypeFontCache. * Create a new FreeTypeFontCache.
* @param fs The font size that is going to be cached. * @param fs The font size that is going to be cached.
@ -113,93 +110,6 @@ void FreeTypeFontCache::SetFontSize(int pixels)
} }
} }
static FT_Error LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
{
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
/* Attempt to select the unicode character map */
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
if (error == FT_Err_Ok) goto found_face; // Success
if (error == FT_Err_Invalid_CharMap_Handle) {
/* Try to pick a different character map instead. We default to
* the first map, but platform_id 0 encoding_id 0 should also
* be unicode (strange system...) */
FT_CharMap found = face->charmaps[0];
int i;
for (i = 0; i < face->num_charmaps; i++) {
FT_CharMap charmap = face->charmaps[i];
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
found = charmap;
}
}
if (found != nullptr) {
error = FT_Set_Charmap(face, found);
if (error == FT_Err_Ok) goto found_face;
}
}
FT_Done_Face(face);
return error;
found_face:
new FreeTypeFontCache(fs, face, size);
return FT_Err_Ok;
}
/**
* Loads the freetype font.
* First type to load the fontname as if it were a path. If that fails,
* try to resolve the filename of the font using fontconfig, where the
* format is 'font family name' or 'font family name, font style'.
* @param fs The font size to load.
*/
void LoadFreeTypeFont(FontSize fs)
{
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
std::string font = GetFontCacheFontName(fs);
if (font.empty()) return;
if (_ft_library == nullptr) {
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
return;
}
Debug(fontcache, 2, "Initialized");
}
FT_Face face = nullptr;
/* 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);
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
if (error != FT_Err_Ok) {
/* Check if font is a relative filename in one of our search-paths. */
std::string full_font = FioFindFullPath(BASE_DIR, font);
if (!full_font.empty()) {
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
}
}
/* Try loading based on font face name (OS-wide fonts). */
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
if (error == FT_Err_Ok) {
error = LoadFont(fs, face, font, GetFontCacheFontSize(fs));
if (error != FT_Err_Ok) {
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font, FontSizeToName(fs), error);
}
} else {
FT_Done_Face(face);
}
}
/** /**
* Free everything that was allocated for this font cache. * Free everything that was allocated for this font cache.
*/ */
@ -296,14 +206,106 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
return glyph; return glyph;
} }
/** FT_Library _ft_library = nullptr;
* Free everything allocated w.r.t. freetype.
*/ class FreeTypeFontCacheFactory : public FontCacheFactory {
void UninitFreeType() public:
{ FreeTypeFontCacheFactory() : FontCacheFactory("freetype", "FreeType font provider") {}
virtual ~FreeTypeFontCacheFactory()
{
FT_Done_FreeType(_ft_library); FT_Done_FreeType(_ft_library);
_ft_library = nullptr; _ft_library = nullptr;
} }
/**
* Loads the freetype font.
* First type to load the fontname as if it were a path. If that fails,
* try to resolve the filename of the font using fontconfig, where the
* format is 'font family name' or 'font family name, font style'.
* @param fs The font size to load.
*/
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
{
if (fonttype != FontType::TrueType) return nullptr;
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
std::string font = GetFontCacheFontName(fs);
if (font.empty()) return nullptr;
if (_ft_library == nullptr) {
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
return nullptr;
}
Debug(fontcache, 2, "Initialized");
}
FT_Face face = nullptr;
/* 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);
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
if (error != FT_Err_Ok) {
/* Check if font is a relative filename in one of our search-paths. */
std::string full_font = FioFindFullPath(BASE_DIR, font);
if (!full_font.empty()) {
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
}
}
/* Try loading based on font face name (OS-wide fonts). */
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
if (error != FT_Err_Ok) {
FT_Done_Face(face);
return nullptr;
}
return LoadFont(fs, face, font, GetFontCacheFontSize(fs));
}
private:
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
{
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
/* Attempt to select the unicode character map */
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
if (error == FT_Err_Invalid_CharMap_Handle) {
/* Try to pick a different character map instead. We default to
* the first map, but platform_id 0 encoding_id 0 should also
* be unicode (strange system...) */
FT_CharMap found = face->charmaps[0];
for (int i = 0; i < face->num_charmaps; ++i) {
FT_CharMap charmap = face->charmaps[i];
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
found = charmap;
}
}
if (found != nullptr) {
error = FT_Set_Charmap(face, found);
}
}
if (error != FT_Err_Ok) {
FT_Done_Face(face);
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
return nullptr;
}
return std::make_unique<FreeTypeFontCache>(fs, face, size);
}
};
static FreeTypeFontCacheFactory s_freetype_fontcache_factory;
#if !defined(WITH_FONTCONFIG) #if !defined(WITH_FONTCONFIG)

View File

@ -151,3 +151,17 @@ bool SpriteFontCache::GetDrawGlyphShadow()
{ {
return false; return false;
} }
class SpriteFontCacheFactory : public FontCacheFactory {
public:
SpriteFontCacheFactory() : FontCacheFactory("sprite", "Sprite font provider") {}
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
{
if (fonttype != FontType::Sprite) return nullptr;
return std::make_unique<SpriteFontCache>(fs);
}
};
static SpriteFontCacheFactory s_sprite_fontcache_factory;

View File

@ -1246,7 +1246,7 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode,
*/ */
void LoadStringWidthTable(FontSizes fontsizes) void LoadStringWidthTable(FontSizes fontsizes)
{ {
ClearFontCache(fontsizes); FontCache::ClearFontCaches(fontsizes);
for (FontSize fs : fontsizes) { for (FontSize fs : fontsizes) {
for (uint i = 0; i != 224; i++) { for (uint i = 0; i != 224; i++) {
@ -1813,7 +1813,7 @@ bool AdjustGUIZoom(bool automatic)
if (old_font_zoom != _font_zoom) { if (old_font_zoom != _font_zoom) {
GfxClearFontSpriteCache(); GfxClearFontSpriteCache();
} }
ClearFontCache(FONTSIZES_ALL); FontCache::ClearFontCaches(FONTSIZES_ALL);
LoadStringWidthTable(); LoadStringWidthTable();
SetupWidgetDimensions(); SetupWidgetDimensions();

View File

@ -245,7 +245,7 @@ static void RealChangeBlitter(std::string_view repl_blitter)
/* Clear caches that might have sprites for another blitter. */ /* Clear caches that might have sprites for another blitter. */
VideoDriver::GetInstance()->ClearSystemSprites(); VideoDriver::GetInstance()->ClearSystemSprites();
ClearFontCache(FONTSIZES_ALL); FontCache::ClearFontCaches(FONTSIZES_ALL);
GfxClearSpriteCache(); GfxClearSpriteCache();
ReInitAllWindows(false); ReInitAllWindows(false);
} }
@ -326,7 +326,7 @@ void CheckBlitter()
{ {
if (!SwitchNewGRFBlitter()) return; if (!SwitchNewGRFBlitter()) return;
ClearFontCache(FONTSIZES_ALL); FontCache::ClearFontCaches(FONTSIZES_ALL);
GfxClearSpriteCache(); GfxClearSpriteCache();
ReInitAllWindows(false); ReInitAllWindows(false);
} }
@ -338,7 +338,7 @@ void GfxLoadSprites()
SwitchNewGRFBlitter(); SwitchNewGRFBlitter();
VideoDriver::GetInstance()->ClearSystemSprites(); VideoDriver::GetInstance()->ClearSystemSprites();
ClearFontCache(FONTSIZES_ALL); FontCache::ClearFontCaches(FONTSIZES_ALL);
GfxInitSpriteMem(); GfxInitSpriteMem();
LoadSpriteTables(); LoadSpriteTables();
GfxInitPalettes(); GfxInitPalettes();

View File

@ -315,7 +315,7 @@ static void ShutdownGame()
/* No NewGRFs were loaded when it was still bootstrapping. */ /* No NewGRFs were loaded when it was still bootstrapping. */
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData(); if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
UninitFontCache(); FontCache::UninitializeFontCaches();
} }
/** /**
@ -700,7 +700,7 @@ int openttd_main(std::span<std::string_view> arguments)
InitializeLanguagePacks(); InitializeLanguagePacks();
/* Initialize the font cache */ /* Initialize the font cache */
InitFontCache(FONTSIZES_REQUIRED); FontCache::LoadFontCaches(FONTSIZES_REQUIRED);
/* This must be done early, since functions use the SetWindowDirty* calls */ /* This must be done early, since functions use the SetWindowDirty* calls */
InitWindowSystem(); InitWindowSystem();

View File

@ -287,52 +287,24 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite(); return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
} }
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name) class CoreTextFontCacheFactory : public FontCacheFactory {
{ public:
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr; CoreTextFontCacheFactory() : FontCacheFactory("coretext", "CoreText font loader") {}
/* Might be a font file name, try load it. Direct font loading is /**
* only supported starting on OSX 10.6. */
CFAutoRelease<CFStringRef> path;
/* See if this is an absolute path. */
if (FileExists(font_name)) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
} else {
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
}
}
if (path) {
/* Try getting a font descriptor to see if the system can use it. */
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
if (descs && CFArrayGetCount(descs.get()) > 0) {
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
CFRetain(font_ref);
return font_ref;
}
}
return nullptr;
}
/**
* Loads the TrueType font. * Loads the TrueType font.
* If a CoreText font description is present, e.g. from the automatic font * If a CoreText font description is present, e.g. from the automatic font
* fallback search, use it. Otherwise, try to resolve it by font name. * fallback search, use it. Otherwise, try to resolve it by font name.
* @param fs The font size to load. * @param fs The font size to load.
*/ */
void LoadCoreTextFont(FontSize fs) std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
{ {
if (fonttype != FontType::TrueType) return nullptr;
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs); FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
std::string font = GetFontCacheFontName(fs); std::string font = GetFontCacheFontName(fs);
if (font.empty()) return; if (font.empty()) return nullptr;
CFAutoRelease<CTFontDescriptorRef> font_ref; CFAutoRelease<CTFontDescriptorRef> font_ref;
@ -367,8 +339,46 @@ void LoadCoreTextFont(FontSize fs)
if (!font_ref) { if (!font_ref) {
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs)); ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
return; return nullptr;
} }
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs)); return std::make_unique<CoreTextFontCache>(fs, std::move(font_ref), GetFontCacheFontSize(fs));
} }
private:
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
{
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
/* Might be a font file name, try load it. Direct font loading is
* only supported starting on OSX 10.6. */
CFAutoRelease<CFStringRef> path;
/* See if this is an absolute path. */
if (FileExists(font_name)) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
} else {
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
if (!full_font.empty()) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
}
}
if (path) {
/* Try getting a font descriptor to see if the system can use it. */
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
if (descs && CFArrayGetCount(descs.get()) > 0) {
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
CFRetain(font_ref);
return font_ref;
}
}
return nullptr;
}
};
static CoreTextFontCacheFactory s_coretext_fontcache_Factory;

View File

@ -182,6 +182,6 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
if (best_font == nullptr) return false; if (best_font == nullptr) return false;
callback->SetFontNames(settings, best_font, &best_index); callback->SetFontNames(settings, best_font, &best_index);
InitFontCache(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED); FontCache::LoadFontCaches(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
return true; return true;
} }

View File

@ -293,9 +293,63 @@ void Win32FontCache::ClearFontCache()
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0; return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
} }
class Win32FontCacheFactory : FontCacheFactory {
public:
Win32FontCacheFactory() : FontCacheFactory("win32", "Win32 font loader") {}
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont) /**
{ * Loads the GDI font.
* 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.
* @param fs The font size to load.
*/
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
{
if (fonttype != FontType::TrueType) return nullptr;
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
std::string font = GetFontCacheFontName(fs);
if (font.empty()) return nullptr;
LOGFONT logfont{};
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
if (settings->os_handle != nullptr) {
logfont = *(const LOGFONT *)settings->os_handle;
} else if (font.find('.') != std::string::npos) {
/* Might be a font file name, try load it. */
if (!TryLoadFontFromFile(font, logfont)) {
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
}
}
if (logfont.lfFaceName[0] == 0) {
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
convert_to_fs(font, logfont.lfFaceName);
}
return LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
}
private:
static std::unique_ptr<FontCache> LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
{
HFONT font = CreateFontIndirect(&logfont);
if (font == nullptr) {
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
return nullptr;
}
DeleteObject(font);
return std::make_unique<Win32FontCache>(fs, logfont, size);
}
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
{
wchar_t fontPath[MAX_PATH] = {}; wchar_t fontPath[MAX_PATH] = {};
/* See if this is an absolute path. */ /* See if this is an absolute path. */
@ -341,51 +395,7 @@ static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
} }
return logfont.lfFaceName[0] != 0; return logfont.lfFaceName[0] != 0;
}
static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
{
HFONT font = CreateFontIndirect(&logfont);
if (font == nullptr) {
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
return;
} }
DeleteObject(font); };
new Win32FontCache(fs, logfont, size); static Win32FontCacheFactory s_win32_fontcache_factory;
}
/**
* Loads the GDI font.
* 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.
* @param fs The font size to load.
*/
void LoadWin32Font(FontSize fs)
{
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
std::string font = GetFontCacheFontName(fs);
if (font.empty()) return;
LOGFONT logfont{};
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
if (settings->os_handle != nullptr) {
logfont = *(const LOGFONT *)settings->os_handle;
} else if (font.find('.') != std::string::npos) {
/* Might be a font file name, try load it. */
if (!TryLoadFontFromFile(font, logfont)) {
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
}
}
if (logfont.lfFaceName[0] == 0) {
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
convert_to_fs(font, logfont.lfFaceName);
}
LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
}

View File

@ -1036,8 +1036,8 @@ struct GameOptionsWindow : Window {
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite); this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
this->SetDirty(); this->SetDirty();
InitFontCache(FONTSIZES_ALL); FontCache::LoadFontCaches(FONTSIZES_ALL);
ClearFontCache(FONTSIZES_ALL); FontCache::ClearFontCaches(FONTSIZES_ALL);
CheckForMissingGlyphs(); CheckForMissingGlyphs();
SetupWidgetDimensions(); SetupWidgetDimensions();
UpdateAllVirtCoords(); UpdateAllVirtCoords();
@ -1050,7 +1050,7 @@ struct GameOptionsWindow : Window {
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa); this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
MarkWholeScreenDirty(); MarkWholeScreenDirty();
ClearFontCache(FONTSIZES_ALL); FontCache::ClearFontCaches(FONTSIZES_ALL);
break; break;
#endif /* HAS_TRUETYPE_FONT */ #endif /* HAS_TRUETYPE_FONT */

View File

@ -2278,7 +2278,7 @@ std::string_view GetCurrentLanguageIsoCode()
*/ */
bool MissingGlyphSearcher::FindMissingGlyphs() bool MissingGlyphSearcher::FindMissingGlyphs()
{ {
InitFontCache(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED); FontCache::LoadFontCaches(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
this->Reset(); this->Reset();
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) { for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
@ -2395,7 +2395,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
/* Our fallback font does miss characters too, so keep the /* Our fallback font does miss characters too, so keep the
* user chosen font as that is more likely to be any good than * user chosen font as that is more likely to be any good than
* the wild guess we made */ * the wild guess we made */
InitFontCache(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED); FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
} }
} }
#endif #endif

View File

@ -32,7 +32,8 @@ public:
static void InitializeFontCaches() static void InitializeFontCaches()
{ {
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) { for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
if (FontCache::caches[fs] == nullptr) new MockFontCache(fs); /* FontCache inserts itself into to the cache. */ if (FontCache::Get(fs) != nullptr) continue;
FontCache::caches[fs] = std::make_unique<MockFontCache>(fs);
} }
} }
}; };