mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Use ProviderManager interface to register FontCache factories.
parent
6a1625f2d0
commit
ddb128f10d
|
@ -12,7 +12,6 @@
|
|||
#include "fontdetection.h"
|
||||
#include "blitter/factory.hpp"
|
||||
#include "gfx_layout.h"
|
||||
#include "fontcache/spritefontcache.h"
|
||||
#include "openttd.h"
|
||||
#include "settings_func.h"
|
||||
#include "strings_func.h"
|
||||
|
@ -28,6 +27,18 @@ static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
|
|||
|
||||
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.
|
||||
* @param fs The size of the font.
|
||||
|
@ -85,7 +96,7 @@ int GetCharacterHeight(FontSize size)
|
|||
/* static */ void FontCache::InitializeFontCaches()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
#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.
|
||||
* @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);
|
||||
if (fc->HasParent()) delete fc;
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
LoadFreeTypeFont(fs);
|
||||
#elif defined(_WIN32)
|
||||
LoadWin32Font(fs);
|
||||
#elif defined(WITH_COCOA)
|
||||
LoadCoreTextFont(fs);
|
||||
#endif
|
||||
FontProviderManager::LoadFont(fs, FontType::TrueType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,10 +238,6 @@ void UninitFontCache()
|
|||
FontCache *fc = FontCache::Get(fs);
|
||||
if (fc->HasParent()) delete fc;
|
||||
}
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
UninitFreeType();
|
||||
#endif /* WITH_FREETYPE */
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef FONTCACHE_H
|
||||
#define FONTCACHE_H
|
||||
|
||||
#include "provider_manager.h"
|
||||
#include "string_type.h"
|
||||
#include "spritecache.h"
|
||||
|
||||
|
@ -208,6 +209,33 @@ void UninitFontCache();
|
|||
bool GetFontAAState();
|
||||
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 */
|
||||
void InitializeUnicodeGlyphMap();
|
||||
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);
|
||||
|
|
|
@ -46,9 +46,6 @@ public:
|
|||
const void *GetOSHandle() override { return &face; }
|
||||
};
|
||||
|
||||
FT_Library _ft_library = nullptr;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new FreeTypeFontCache.
|
||||
* @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.
|
||||
*/
|
||||
|
@ -296,14 +206,110 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
|
|||
return glyph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free everything allocated w.r.t. freetype.
|
||||
*/
|
||||
void UninitFreeType()
|
||||
{
|
||||
FT_Done_FreeType(_ft_library);
|
||||
_ft_library = nullptr;
|
||||
}
|
||||
FT_Library _ft_library = nullptr;
|
||||
|
||||
class FreeTypeFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
FreeTypeFontCacheFactory() : FontCacheFactory("freetype", "FreeType font provider") {}
|
||||
|
||||
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)
|
||||
|
||||
|
|
|
@ -91,6 +91,20 @@ bool SpriteFontCache::GetDrawGlyphShadow()
|
|||
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.
|
||||
* @param fs Font size to set.
|
||||
|
|
|
@ -287,88 +287,98 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
|
|||
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
|
||||
}
|
||||
|
||||
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
||||
{
|
||||
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
||||
class CoreTextFontCacheFactory : public FontCacheFactory {
|
||||
public:
|
||||
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;
|
||||
/**
|
||||
* Loads the TrueType 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.
|
||||
* @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. */
|
||||
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));
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return;
|
||||
|
||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||
|
||||
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) {
|
||||
/* 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;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
if (!font_ref) {
|
||||
CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
|
||||
|
||||
/**
|
||||
* Loads the TrueType 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.
|
||||
* @param fs The font size to load.
|
||||
*/
|
||||
void LoadCoreTextFont(FontSize fs)
|
||||
{
|
||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||
/* 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()));
|
||||
|
||||
std::string font = GetFontCacheFontName(fs);
|
||||
if (font.empty()) return;
|
||||
|
||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||
|
||||
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());
|
||||
/* 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) {
|
||||
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
||||
return;
|
||||
}
|
||||
private:
|
||||
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -293,99 +293,109 @@ void Win32FontCache::ClearFontCache()
|
|||
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)
|
||||
{
|
||||
wchar_t fontPath[MAX_PATH] = {};
|
||||
/**
|
||||
* 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 LoadFont(FontSize fs, FontType fonttype) override
|
||||
{
|
||||
if (fonttype != FontType::TrueType) return;
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
private:
|
||||
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);
|
||||
|
||||
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.
|
||||
new Win32FontCache(fs, logfont, size);
|
||||
}
|
||||
|
||||
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
||||
{
|
||||
wchar_t fontPath[MAX_PATH] = {};
|
||||
|
||||
/* 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 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);
|
||||
}
|
||||
static Win32FontCacheFactory s_win32_fontcache_factory;
|
||||
|
|
Loading…
Reference in New Issue