1
0
Fork 0

Codechange: Use ProviderManager interface to register FontCache factories.

pull/13303/head
Peter Nelson 2025-06-10 11:26:05 +01:00
parent 6a1625f2d0
commit ddb128f10d
No known key found for this signature in database
GPG Key ID: 8EF8F0A467DF75ED
6 changed files with 337 additions and 277 deletions

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"
@ -28,6 +27,18 @@ static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
FontCacheSettings _fcsettings; FontCacheSettings _fcsettings;
/**
* Try loading a font with any fontcache factory.
* @param fs Font size to load.
* @param fonttype Font type requested.
*/
/* static */ void FontProviderManager::LoadFont(FontSize fs, FontType fonttype)
{
for (auto &provider : FontProviderManager::GetProviders()) {
provider->LoadFont(fs, fonttype);
}
}
/** /**
* Create a new font cache. * Create a new font cache.
* @param fs The size of the font. * @param fs The size of the font.
@ -85,7 +96,7 @@ int GetCharacterHeight(FontSize size)
/* 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::caches[fs] == nullptr) FontProviderManager::LoadFont(fs, FontType::Sprite); /* FontCache inserts itself into to the cache. */
} }
} }
@ -136,15 +147,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.
@ -223,13 +225,7 @@ void InitFontCache(FontSizes fontsizes)
FontCache *fc = FontCache::Get(fs); FontCache *fc = FontCache::Get(fs);
if (fc->HasParent()) delete fc; if (fc->HasParent()) delete fc;
#ifdef WITH_FREETYPE FontProviderManager::LoadFont(fs, FontType::TrueType);
LoadFreeTypeFont(fs);
#elif defined(_WIN32)
LoadWin32Font(fs);
#elif defined(WITH_COCOA)
LoadCoreTextFont(fs);
#endif
} }
} }
@ -242,10 +238,6 @@ void UninitFontCache()
FontCache *fc = FontCache::Get(fs); FontCache *fc = FontCache::Get(fs);
if (fc->HasParent()) delete fc; if (fc->HasParent()) delete fc;
} }
#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"
@ -208,6 +209,33 @@ 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 void LoadFont(FontSize fs, FontType fonttype) = 0;
};
class FontProviderManager : ProviderManager<FontCacheFactory> {
public:
static void 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,110 @@ 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") {}
FT_Done_FreeType(_ft_library);
_ft_library = nullptr; virtual ~FreeTypeFontCacheFactory()
} {
FT_Done_FreeType(_ft_library);
_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.
*/
void LoadFont(FontSize fs, FontType fonttype) override
{
if (fonttype != FontType::TrueType) return;
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);
}
}
private:
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;
}
};
static FreeTypeFontCacheFactory s_freetype_fontcache_factory;
#if !defined(WITH_FONTCONFIG) #if !defined(WITH_FONTCONFIG)

View File

@ -91,6 +91,20 @@ bool SpriteFontCache::GetDrawGlyphShadow()
return false; return false;
} }
class SpriteFontCacheFactory : public FontCacheFactory {
public:
SpriteFontCacheFactory() : FontCacheFactory("sprite", "Sprite font provider") {}
void LoadFont(FontSize fs, FontType fonttype) override
{
if (fonttype != FontType::Sprite) return;
new SpriteFontCache(fs);
}
};
static SpriteFontCacheFactory s_sprite_fontcache_factory;
/** /**
* Set the SpriteID for a unicode character. * Set the SpriteID for a unicode character.
* @param fs Font size to set. * @param fs Font size to set.

View File

@ -287,88 +287,98 @@ 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. */ * Loads the TrueType font.
CFAutoRelease<CFStringRef> path; * 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.
* @param fs The font size to load.
*/
void LoadFont(FontSize fs, FontType fonttype)
{
if (fonttype != FontType::TrueType) return;
/* See if this is an absolute path. */ FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
if (FileExists(font_name)) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8)); std::string font = GetFontCacheFontName(fs);
} else { if (font.empty()) return;
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name); CFAutoRelease<CTFontDescriptorRef> font_ref;
if (!full_font.empty()) {
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8)); if (settings->os_handle != nullptr) {
font_ref.reset(static_cast<CTFontDescriptorRef>(const_cast<void *>(settings->os_handle)));
CFRetain(font_ref.get()); // Increase ref count to match a later release.
} }
}
if (path) { if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
/* Try getting a font descriptor to see if the system can use it. */ /* Might be a font file name, try load it. */
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false)); font_ref.reset(LoadFontFromFile(font));
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get())); if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
if (descs && CFArrayGetCount(descs.get()) > 0) {
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
CFRetain(font_ref);
return font_ref;
} }
}
return nullptr; if (!font_ref) {
} CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
/** /* Simply creating the font using CTFontCreateWithNameAndSize will *always* return
* Loads the TrueType font. * something, no matter the name. As such, we can't use it to check for existence.
* If a CoreText font description is present, e.g. from the automatic font * We instead query the list of all font descriptors that match the given name which
* fallback search, use it. Otherwise, try to resolve it by font name. * does not do this stupid name fallback. */
* @param fs The font size to load. CFAutoRelease<CTFontDescriptorRef> name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0));
*/ CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void * const *>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
void LoadCoreTextFont(FontSize fs) CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
{
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
std::string font = GetFontCacheFontName(fs); /* Assume the first result is the one we want. */
if (font.empty()) return; if (descs && CFArrayGetCount(descs.get()) > 0) {
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
CFAutoRelease<CTFontDescriptorRef> font_ref; CFRetain(font_ref.get());
}
if (settings->os_handle != nullptr) {
font_ref.reset(static_cast<CTFontDescriptorRef>(const_cast<void *>(settings->os_handle)));
CFRetain(font_ref.get()); // Increase ref count to match a later release.
}
if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
/* Might be a font file name, try load it. */
font_ref.reset(LoadFontFromFile(font));
if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
}
if (!font_ref) {
CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
/* Simply creating the font using CTFontCreateWithNameAndSize will *always* return
* something, no matter the name. As such, we can't use it to check for existence.
* We instead query the list of all font descriptors that match the given name which
* does not do this stupid name fallback. */
CFAutoRelease<CTFontDescriptorRef> name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0));
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void * const *>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
/* Assume the first result is the one we want. */
if (descs && CFArrayGetCount(descs.get()) > 0) {
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
CFRetain(font_ref.get());
} }
if (!font_ref) {
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
return;
}
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs));
} }
if (!font_ref) { private:
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs)); static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
return; {
} if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs)); /* 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

@ -293,99 +293,109 @@ 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.
wchar_t fontPath[MAX_PATH] = {}; * 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 LoadFont(FontSize fs, FontType fonttype) override
{
if (fonttype != FontType::TrueType) return;
/* See if this is an absolute path. */ FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
if (FileExists(font_name)) {
convert_to_fs(font_name, fontPath); std::string font = GetFontCacheFontName(fs);
} else { if (font.empty()) return;
/* Scan the search-paths to see if it can be found. */
std::string full_font = FioFindFullPath(BASE_DIR, font_name); LOGFONT logfont{};
if (!full_font.empty()) { logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
convert_to_fs(font_name, fontPath); 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);
} }
if (fontPath[0] != 0) { private:
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) { static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
/* Try a nice little undocumented function first for getting the internal font name. {
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */ HFONT font = CreateFontIndirect(&logfont);
static LibraryLoader _gdi32("gdi32.dll"); if (font == nullptr) {
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD); ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW"); return;
}
DeleteObject(font);
if (GetFontResourceInfo != nullptr) { new Win32FontCache(fs, logfont, size);
/* Try to query an array of LOGFONTs that describe the file. */ }
DWORD len = 0;
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) { static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
LOGFONT *buf = (LOGFONT *)new uint8_t[len]; {
if (GetFontResourceInfo(fontPath, &len, buf, 2)) { wchar_t fontPath[MAX_PATH] = {};
logfont = *buf; // Just use first entry.
/* See if this is an absolute path. */
if (FileExists(font_name)) {
convert_to_fs(font_name, fontPath);
} 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()) {
convert_to_fs(font_name, fontPath);
}
}
if (fontPath[0] != 0) {
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
/* Try a nice little undocumented function first for getting the internal font name.
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
static LibraryLoader _gdi32("gdi32.dll");
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
if (GetFontResourceInfo != nullptr) {
/* Try to query an array of LOGFONTs that describe the file. */
DWORD len = 0;
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
LOGFONT *buf = (LOGFONT *)new uint8_t[len];
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
logfont = *buf; // Just use first entry.
}
delete[](uint8_t *)buf;
} }
delete[](uint8_t *)buf; }
/* No dice yet. Use the file name as the font face name, hoping it matches. */
if (logfont.lfFaceName[0] == 0) {
wchar_t fname[_MAX_FNAME];
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
logfont.lfWeight = StrContainsIgnoreCase(font_name, " bold") || StrContainsIgnoreCase(font_name, "-bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
} }
} }
/* No dice yet. Use the file name as the font face name, hoping it matches. */
if (logfont.lfFaceName[0] == 0) {
wchar_t fname[_MAX_FNAME];
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
logfont.lfWeight = StrContainsIgnoreCase(font_name, " bold") || StrContainsIgnoreCase(font_name, "-bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
}
} }
return logfont.lfFaceName[0] != 0;
} }
};
return logfont.lfFaceName[0] != 0; static Win32FontCacheFactory s_win32_fontcache_factory;
}
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);
}
/**
* 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);
}