Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: Support side-by-side fallback FontCaches instead of hierarchi… #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions src/console_cmds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2273,17 +2273,20 @@ DEF_CONSOLE_CMD(ConFont)
SetFont(argfs, font, size);
}

int i = 0;
IConsolePrint(CC_INFO, "Configured fonts:");
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
FontCache *fc = FontCache::Get(fs);
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
/* Make sure all non sprite fonts are loaded. */
if (!setting->font.empty() && !fc->HasParent()) {
InitFontCache(fs == FS_MONO);
fc = FontCache::Get(fs);
}
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
IConsolePrint(CC_DEFAULT, "Currently active: \"{}\", size {}", fc->GetFontName(), fc->GetFontSize());
IConsolePrint(CC_DEFAULT, "Requested: \"{}\", size {}", setting->font, setting->size);
const FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
IConsolePrint(CC_DEFAULT, "{}) {} font: \"{}\", size {}", i, FontSizeToName(fs), setting->font, setting->size);
++i;
}

i = 0;
IConsolePrint(CC_INFO, "Currently active fonts:");
for (const auto &fc : FontCache::Get()) {
if (fc == nullptr) continue;
IConsolePrint(CC_DEFAULT, "{}) {} font: \"{}\" size {}", i, FontSizeToName(fc->GetSize()), fc->GetFontName(), fc->GetFontSize());
++i;
}

return true;
Expand Down
149 changes: 98 additions & 51 deletions src/fontcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "window_func.h"
#include "fileio_func.h"

#include <regex>

#include "safeguards.h"

/** Default heights for the different sizes of fonts. */
Expand All @@ -32,19 +34,26 @@
* Create a new font cache.
* @param fs The size of the font.
*/
FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs), height(_default_font_height[fs]),
FontCache::FontCache(FontSize fs) : fs(fs), height(_default_font_height[fs]),
ascender(_default_font_ascender[fs]), descender(_default_font_ascender[fs] - _default_font_height[fs])
{
assert(this->parent == nullptr || this->fs == this->parent->fs);
FontCache::caches[this->fs] = this;
/* Find an empty font cache slot. */
auto it = std::find(std::begin(FontCache::caches), std::end(FontCache::caches), nullptr);
if (it == std::end(FontCache::caches)) it = FontCache::caches.insert(it, nullptr);

/* Register this font cache in the slot. */
it->reset(this);

/* Set up our font index and make us the default font cache for this font size. */
this->font_index = static_cast<FontIndex>(std::distance(std::begin(FontCache::caches), it));
FontCache::default_font_index[fs] = this->font_index;

Layouter::ResetFontCache(this->fs);
}

/** Clean everything up. */
FontCache::~FontCache()
{
assert(this->fs == this->parent->fs);
FontCache::caches[this->fs] = this->parent;
Layouter::ResetFontCache(this->fs);
}

Expand All @@ -53,40 +62,33 @@
return _default_font_height[fs];
}

/**
* Get the font name of a given font size.
* @param fs The font size to look up.
* @return The font name.
*/
std::string FontCache::GetName(FontSize fs)
/* static */ void FontCache::UpdateCharacterHeight(FontSize fs)
{
FontCache *fc = FontCache::Get(fs);
if (fc != nullptr) {
return fc->GetFontName();
} else {
return "[NULL]";
FontCache::max_height[fs] = 0;
for (const auto &fc : FontCache::caches) {
if (fc == nullptr || fc->fs != fs) continue;
FontCache::max_height[fs] = std::max(FontCache::max_height[fs], fc->height);
}
}


/**
* Get height of a character for a given font size.
* @param size Font size to get height of
* @return Height of characters in the given font (pixels)
*/
int GetCharacterHeight(FontSize size)
{
return FontCache::Get(size)->GetHeight();
return FontCache::GetCharacterHeight(size);
}


/* static */ FontCache *FontCache::caches[FS_END];
/* static */ FontCache::FontCaches FontCache::caches;
/* static */ std::array<int, FS_END> FontCache::max_height{};
/* static */ std::array<std::unordered_map<char32_t, FontIndex>, FS_END> FontCache::character_to_fontcache;
/* static */ std::array<FontIndex, FS_END> FontCache::sprite_font_index{};
/* static */ std::array<FontIndex, FS_END> FontCache::default_font_index{};

/* 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. */
}
}

/* Check if a glyph should be rendered with anti-aliasing. */
Expand Down Expand Up @@ -116,15 +118,8 @@
if (!changed) return;

if (fontsize != FS_MONO) {
/* Try to reload only the modified font. */
FontCacheSettings backup = _fcsettings;
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
if (fs == fontsize) continue;
FontCache *fc = FontCache::Get(fs);
GetFontCacheSubSetting(fs)->font = fc->HasParent() ? fc->GetFontName() : "";
}
/* Check if fallback fonts are needed. */
CheckForMissingGlyphs();
_fcsettings = backup;
} else {
InitFontCache(true);
}
Expand All @@ -137,12 +132,12 @@
}

#ifdef WITH_FREETYPE
extern void LoadFreeTypeFont(FontSize fs);
extern void LoadFreeTypeFont(FontSize fs, bool search, const std::string &font_name, std::span<const uint8_t> os_handle);
extern void UninitFreeType();
#elif defined(_WIN32)
extern void LoadWin32Font(FontSize fs);
extern void LoadWin32Font(FontSize fs, bool search, const std::string &font_name, std::span<const uint8_t> os_handle);
#elif defined(WITH_COCOA)
extern void LoadCoreTextFont(FontSize fs);
extern void LoadCoreTextFont(FontSize fs, bool search, const std::string &font_name, std::span<const uint8_t> os_handle);
#endif

/**
Expand All @@ -151,7 +146,7 @@
*/
static bool IsDefaultFont(const FontCacheSubSetting &setting)
{
return setting.font.empty() && setting.os_handle == nullptr;
return setting.font.empty();
}

/**
Expand Down Expand Up @@ -188,7 +183,7 @@
* @param fs Font size.
* @return Full path of default font file.
*/
static std::string GetDefaultTruetypeFontFile([[maybe_unused]] FontSize fs)
std::string GetDefaultTruetypeFontFile([[maybe_unused]] FontSize fs)
{
#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
/* Find font file. */
Expand All @@ -198,6 +193,29 @@
#endif /* defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) */
}

/**
* Load a font for any platform.
* @param fs FontSize of font.
* @param load_type Type of font (for debug only)
* @param search Whether to search for the font.
* @param font Font name, or filename, or path to a font.
* @param os_handle OS-specific data.
*/
static void LoadFont(FontSize fs, std::string_view load_type, bool search, const std::string &font, [[maybe_unused]] std::span<uint8_t> os_handle)

Check warning on line 204 in src/fontcache.cpp

View workflow job for this annotation

GitHub Actions / Emscripten / CI

unused parameter 'search' [-Wunused-parameter]

Check warning on line 204 in src/fontcache.cpp

View workflow job for this annotation

GitHub Actions / Linux (GCC - Dedicated) / CI

unused parameter ‘search’ [-Wunused-parameter]
{
if (font.empty()) return;

Debug(fontcache, 2, "InitFontCache: Adding '{}' as {} for {} font", font, load_type, FontSizeToName(fs));

#ifdef WITH_FREETYPE
LoadFreeTypeFont(fs, search, font, os_handle);
#elif defined(_WIN32)
LoadWin32Font(fs, search, font, os_handle);
#elif defined(WITH_COCOA)
LoadCoreTextFont(fs, search, font, os_handle);
#endif
}

/**
* Get font to use for a given font size.
* @param fs Font size.
Expand All @@ -217,21 +235,53 @@
*/
void InitFontCache(bool monospace)
{
FontCache::InitializeFontCaches();
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
if (monospace != (fs == FS_MONO)) continue;

Layouter::ResetFontCache(fs);
FontCache::character_to_fontcache[fs].clear();
FontCache::sprite_font_index[fs] = INVALID_FONT_INDEX;
FontCache::default_font_index[fs] = INVALID_FONT_INDEX;
}

/* Remove all existing FontCaches. */
for (auto it = std::begin(FontCache::caches); it != std::end(FontCache::caches); ++it) {
if (*it == nullptr) continue;
if (monospace != ((*it)->fs == FS_MONO)) continue;
it->reset();
}

std::regex re("([^;]+)");

for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
if (monospace != (fs == FS_MONO)) continue;

FontCache *fc = FontCache::Get(fs);
if (fc->HasParent()) delete fc;
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);

#ifdef WITH_FREETYPE
LoadFreeTypeFont(fs);
#elif defined(_WIN32)
LoadWin32Font(fs);
#elif defined(WITH_COCOA)
LoadCoreTextFont(fs);
#endif
for (auto &fallback : setting->fallback_fonts) {
LoadFont(fs, "fallback", false, fallback.first, fallback.second);
}

using re_iterator = std::regex_iterator<std::string::const_iterator>;
re_iterator rit(setting->font.begin(), setting->font.end(), re);
re_iterator rend;
std::vector<std::string> result;
std::transform(rit, rend, std::back_inserter(result), [](const auto &it) { return it[1]; });

if (std::find(result.begin(), result.end(), "default") == result.end()) result.push_back("default");

for (auto it = result.rbegin(); it != result.rend(); ++it) {
std::string &f = *it;
StrTrimInPlace(f);
if (f == "default") {
new SpriteFontCache(fs);
if (!_fcsettings.prefer_sprite) {
LoadFont(fs, "default", false, GetDefaultTruetypeFontFile(fs), {});
}
} else {
LoadFont(fs, "configured", true, f, {});
}
}
}
}

Expand All @@ -240,10 +290,7 @@
*/
void UninitFontCache()
{
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
FontCache *fc = FontCache::Get(fs);
if (fc->HasParent()) delete fc;
}
FontCache::caches.clear();

#ifdef WITH_FREETYPE
UninitFreeType();
Expand All @@ -252,5 +299,5 @@

#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)

bool SetFallbackFont(FontCacheSettings *, const std::string &, int, MissingGlyphSearcher *) { return false; }
bool SetFallbackFont(const std::string &, int, MissingGlyphSearcher *) { return false; }
#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */
Loading
Loading