Clean up font caching, fix bitmap fonts

This commit is contained in:
SmallJoker 2019-10-17 20:40:50 +02:00 committed by SmallJoker
parent 72416a6a1f
commit 388ea737f5
4 changed files with 97 additions and 105 deletions

@ -41,11 +41,6 @@ static void font_setting_changed(const std::string &name, void *userdata)
g_fontengine->readSettings(); g_fontengine->readSettings();
} }
unsigned int get_font_cache_index(FontMode mode, bool bold = false, bool italic = false)
{
return (mode << 2) | (bold << 1) | italic;
}
/******************************************************************************/ /******************************************************************************/
FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) : FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
m_settings(main_settings), m_settings(main_settings),
@ -106,45 +101,45 @@ void FontEngine::cleanCache()
} }
/******************************************************************************/ /******************************************************************************/
irr::gui::IGUIFont *FontEngine::getFont(unsigned int font_size, FontMode mode, irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
bool bold, bool italic)
{ {
if (mode == FM_Unspecified) { if (spec.mode == FM_Unspecified) {
mode = m_currentMode; spec.mode = m_currentMode;
} else if (m_currentMode == FM_Simple) { } else if (m_currentMode == FM_Simple) {
// Freetype disabled -> Force simple mode // Freetype disabled -> Force simple mode
mode = (mode == FM_Mono || mode == FM_SimpleMono) ? spec.mode = (spec.mode == FM_Mono ||
spec.mode == FM_SimpleMono) ?
FM_SimpleMono : FM_Simple; FM_SimpleMono : FM_Simple;
// Support for those could be added, but who cares?
spec.bold = false;
spec.italic = false;
} }
// Fallback to default size // Fallback to default size
if (font_size == FONT_SIZE_UNSPECIFIED) if (spec.size == FONT_SIZE_UNSPECIFIED)
font_size = m_default_size[mode]; spec.size = m_default_size[spec.mode];
unsigned int cache_index = get_font_cache_index(mode, bold, italic); const auto &cache = m_font_cache[spec.getHash()];
auto it = cache.find(spec.size);
if (it != cache.end())
return it->second;
const auto &cache = m_font_cache[cache_index]; // Font does not yet exist
gui::IGUIFont *font = nullptr;
if (cache.find(font_size) == cache.end()) { if (spec.mode == FM_Simple || spec.mode == FM_SimpleMono)
if (mode == FM_Simple || mode == FM_SimpleMono) font = initSimpleFont(spec);
initSimpleFont(font_size, mode);
else else
initFont(font_size, mode, bold, italic); font = initFont(spec);
}
if (m_font_cache[cache_index].find(font_size) == m_font_cache[spec.getHash()][spec.size] = font;
m_font_cache[cache_index].end())
initFont(font_size, mode, bold, italic);
const auto &font = cache.find(font_size); return font;
return font != cache.end() ? font->second : nullptr;
} }
/******************************************************************************/ /******************************************************************************/
unsigned int FontEngine::getTextHeight(unsigned int font_size, FontMode mode, unsigned int FontEngine::getTextHeight(const FontSpec &spec)
bool bold, bool italic)
{ {
irr::gui::IGUIFont *font = getFont(font_size, mode, bold, italic); irr::gui::IGUIFont *font = getFont(spec);
// use current skin font as fallback // use current skin font as fallback
if (font == NULL) { if (font == NULL) {
@ -156,10 +151,9 @@ unsigned int FontEngine::getTextHeight(unsigned int font_size, FontMode mode,
} }
/******************************************************************************/ /******************************************************************************/
unsigned int FontEngine::getTextWidth(const std::wstring& text, unsigned int FontEngine::getTextWidth(const std::wstring &text, const FontSpec &spec)
unsigned int font_size, FontMode mode, bool bold, bool italic)
{ {
irr::gui::IGUIFont *font = getFont(font_size, mode, bold, italic); irr::gui::IGUIFont *font = getFont(spec);
// use current skin font as fallback // use current skin font as fallback
if (font == NULL) { if (font == NULL) {
@ -172,10 +166,9 @@ unsigned int FontEngine::getTextWidth(const std::wstring& text,
/** get line height for a specific font (including empty room between lines) */ /** get line height for a specific font (including empty room between lines) */
unsigned int FontEngine::getLineHeight(unsigned int font_size, FontMode mode, unsigned int FontEngine::getLineHeight(const FontSpec &spec)
bool bold, bool italic)
{ {
irr::gui::IGUIFont *font = getFont(font_size, mode, bold, italic); irr::gui::IGUIFont *font = getFont(spec);
// use current skin font as fallback // use current skin font as fallback
if (font == NULL) { if (font == NULL) {
@ -250,21 +243,14 @@ void FontEngine::updateFontCache()
} }
/******************************************************************************/ /******************************************************************************/
void FontEngine::initFont(unsigned int basesize, FontMode mode, gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
bool bold, bool italic)
{ {
assert(mode != FM_Unspecified); assert(spec.mode != FM_Unspecified);
assert(basesize != FONT_SIZE_UNSPECIFIED); assert(spec.size != FONT_SIZE_UNSPECIFIED);
int cache_index = get_font_cache_index(mode, bold, italic);
if (m_font_cache[cache_index].find(basesize) !=
m_font_cache[cache_index].end())
return;
std::string setting_prefix = ""; std::string setting_prefix = "";
switch (mode) { switch (spec.mode) {
case FM_Fallback: case FM_Fallback:
setting_prefix = "fallback_"; setting_prefix = "fallback_";
break; break;
@ -276,12 +262,14 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode,
break; break;
} }
std::string setting_suffix = (bold) ? std::string setting_suffix = "";
((italic) ? "_bold_italic" : "_bold") : if (spec.bold)
((italic) ? "_italic" : ""); setting_suffix.append("_bold");
if (spec.italic)
setting_suffix.append("_italic");
u32 size = std::floor(RenderingEngine::getDisplayDensity() * u32 size = std::floor(RenderingEngine::getDisplayDensity() *
m_settings->getFloat("gui_scaling") * basesize); m_settings->getFloat("gui_scaling") * spec.size);
if (size == 0) { if (size == 0) {
errorstream << "FontEngine: attempt to use font size 0" << std::endl; errorstream << "FontEngine: attempt to use font size 0" << std::endl;
@ -310,10 +298,8 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode,
font_path.c_str(), size, true, true, font_shadow, font_path.c_str(), size, true, true, font_shadow,
font_shadow_alpha); font_shadow_alpha);
if (font) { if (font)
m_font_cache[cache_index][basesize] = font; return font;
return;
}
errorstream << "FontEngine: Cannot load '" << font_path << errorstream << "FontEngine: Cannot load '" << font_path <<
"'. Trying to fall back to another path." << std::endl; "'. Trying to fall back to another path." << std::endl;
@ -332,12 +318,13 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode,
} }
/** initialize a font without freetype */ /** initialize a font without freetype */
void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode) gui::IGUIFont *FontEngine::initSimpleFont(const FontSpec &spec)
{ {
assert(mode == FM_Simple || mode == FM_SimpleMono); assert(spec.mode == FM_Simple || spec.mode == FM_SimpleMono);
assert(spec.size != FONT_SIZE_UNSPECIFIED);
const std::string &font_path = m_settings->get( const std::string &font_path = m_settings->get(
(mode == FM_SimpleMono) ? "mono_font_path" : "font_path"); (spec.mode == FM_SimpleMono) ? "mono_font_path" : "font_path");
size_t pos_dot = font_path.find_last_of('.'); size_t pos_dot = font_path.find_last_of('.');
std::string basename = font_path; std::string basename = font_path;
@ -346,19 +333,16 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
if (ending == ".ttf") { if (ending == ".ttf") {
errorstream << "FontEngine: Found font \"" << font_path errorstream << "FontEngine: Found font \"" << font_path
<< "\" but freetype is not available." << std::endl; << "\" but freetype is not available." << std::endl;
return; return nullptr;
} }
if (ending == ".xml" || ending == ".png") if (ending == ".xml" || ending == ".png")
basename = font_path.substr(0, pos_dot); basename = font_path.substr(0, pos_dot);
if (basesize == FONT_SIZE_UNSPECIFIED)
basesize = DEFAULT_FONT_SIZE;
u32 size = std::floor( u32 size = std::floor(
RenderingEngine::getDisplayDensity() * RenderingEngine::getDisplayDensity() *
m_settings->getFloat("gui_scaling") * m_settings->getFloat("gui_scaling") *
basesize); spec.size);
irr::gui::IGUIFont *font = nullptr; irr::gui::IGUIFont *font = nullptr;
std::string font_extensions[] = { ".png", ".xml" }; std::string font_extensions[] = { ".png", ".xml" };
@ -400,6 +384,5 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
} }
} }
if (font) return font;
m_font_cache[get_font_cache_index(mode)][basesize] = font;
} }

@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define FONT_SIZE_UNSPECIFIED 0xFFFFFFFF #define FONT_SIZE_UNSPECIFIED 0xFFFFFFFF
enum FontMode { enum FontMode : u8 {
FM_Standard = 0, FM_Standard = 0,
FM_Mono, FM_Mono,
FM_Fallback, FM_Fallback,
@ -39,6 +39,24 @@ enum FontMode {
FM_Unspecified FM_Unspecified
}; };
struct FontSpec {
FontSpec(unsigned int font_size, FontMode mode, bool bold, bool italic) :
size(font_size),
mode(mode),
bold(bold),
italic(italic) {}
u16 getHash()
{
return (mode << 2) | (bold << 1) | italic;
}
unsigned int size;
FontMode mode;
bool bold;
bool italic;
};
class FontEngine class FontEngine
{ {
public: public:
@ -47,62 +65,60 @@ public:
~FontEngine(); ~FontEngine();
/** get Font */ // Get best possible font specified by FontSpec
irr::gui::IGUIFont *getFont(unsigned int font_size, FontMode mode, irr::gui::IGUIFont *getFont(FontSpec spec);
bool bold, bool italic);
irr::gui::IGUIFont *getFont(unsigned int font_size=FONT_SIZE_UNSPECIFIED, irr::gui::IGUIFont *getFont(unsigned int font_size=FONT_SIZE_UNSPECIFIED,
FontMode mode=FM_Unspecified) FontMode mode=FM_Unspecified)
{ {
return getFont(font_size, mode, m_default_bold, m_default_italic); FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
return getFont(spec);
} }
/** get text height for a specific font */ /** get text height for a specific font */
unsigned int getTextHeight(unsigned int font_size, FontMode mode, unsigned int getTextHeight(const FontSpec &spec);
bool bold, bool italic);
/** get text width if a text for a specific font */ /** get text width if a text for a specific font */
unsigned int getTextHeight( unsigned int getTextHeight(
unsigned int font_size=FONT_SIZE_UNSPECIFIED, unsigned int font_size=FONT_SIZE_UNSPECIFIED,
FontMode mode=FM_Unspecified) FontMode mode=FM_Unspecified)
{ {
return getTextHeight(font_size, mode, m_default_bold, m_default_italic); FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
return getTextHeight(spec);
} }
unsigned int getTextWidth(const std::wstring& text, unsigned int getTextWidth(const std::wstring &text, const FontSpec &spec);
unsigned int font_size, FontMode mode, bool bold, bool italic);
/** get text width if a text for a specific font */ /** get text width if a text for a specific font */
unsigned int getTextWidth(const std::wstring& text, unsigned int getTextWidth(const std::wstring& text,
unsigned int font_size=FONT_SIZE_UNSPECIFIED, unsigned int font_size=FONT_SIZE_UNSPECIFIED,
FontMode mode=FM_Unspecified) FontMode mode=FM_Unspecified)
{ {
return getTextWidth(text, font_size, mode, m_default_bold, FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
m_default_italic); return getTextWidth(text, spec);
} }
unsigned int getTextWidth(const std::string& text, unsigned int getTextWidth(const std::string &text, const FontSpec &spec)
unsigned int font_size, FontMode mode, bool bold, bool italic)
{ {
return getTextWidth(utf8_to_wide(text), font_size, mode, bold, italic); return getTextWidth(utf8_to_wide(text), spec);
} }
unsigned int getTextWidth(const std::string& text, unsigned int getTextWidth(const std::string& text,
unsigned int font_size=FONT_SIZE_UNSPECIFIED, unsigned int font_size=FONT_SIZE_UNSPECIFIED,
FontMode mode=FM_Unspecified) FontMode mode=FM_Unspecified)
{ {
return getTextWidth(utf8_to_wide(text), font_size, mode, m_default_bold, FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
m_default_italic); return getTextWidth(utf8_to_wide(text), spec);
} }
/** get line height for a specific font (including empty room between lines) */ /** get line height for a specific font (including empty room between lines) */
unsigned int getLineHeight(unsigned int font_size, FontMode mode, bool bold, unsigned int getLineHeight(const FontSpec &spec);
bool italic);
unsigned int getLineHeight(unsigned int font_size=FONT_SIZE_UNSPECIFIED, unsigned int getLineHeight(unsigned int font_size=FONT_SIZE_UNSPECIFIED,
FontMode mode=FM_Unspecified) FontMode mode=FM_Unspecified)
{ {
return getLineHeight(font_size, mode, m_default_bold, m_default_italic); FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
return getLineHeight(spec);
} }
/** get default font size */ /** get default font size */
@ -119,14 +135,10 @@ private:
void updateFontCache(); void updateFontCache();
/** initialize a new font */ /** initialize a new font */
void initFont( gui::IGUIFont *initFont(const FontSpec &spec);
unsigned int basesize,
FontMode mode,
bool bold,
bool italic);
/** initialize a font without freetype */ /** initialize a font without freetype */
void initSimpleFont(unsigned int basesize, FontMode mode); gui::IGUIFont *initSimpleFont(const FontSpec &spec);
/** update current minetest skin with font changes */ /** update current minetest skin with font changes */
void updateSkin(); void updateSkin();
@ -147,8 +159,8 @@ private:
unsigned int m_default_size[FM_MaxMode]; unsigned int m_default_size[FM_MaxMode];
/** default bold and italic */ /** default bold and italic */
bool m_default_bold; bool m_default_bold = false;
bool m_default_italic; bool m_default_italic = false;
/** current font engine mode */ /** current font engine mode */
FontMode m_currentMode = FM_Standard; FontMode m_currentMode = FM_Standard;

@ -71,14 +71,12 @@ void ParsedText::Element::setStyle(StyleList &style)
if (style["fontstyle"] == "mono") if (style["fontstyle"] == "mono")
font_mode = FM_Mono; font_mode = FM_Mono;
FontSpec spec(font_size, font_mode,
is_yes(style["bold"]), is_yes(style["italic"]));
// TODO: find a way to check font validity // TODO: find a way to check font validity
// Build a new fontengine ? // Build a new fontengine ?
this->font = this->font = g_fontengine->getFont(spec);
#if USE_FREETYPE
(gui::CGUITTFont *)
#endif
g_fontengine->getFont(font_size, font_mode,
is_yes(style["bold"]), is_yes(style["italic"]));
if (!this->font) if (!this->font)
printf("No font found ! Size=%d, mode=%d, bold=%s, italic=%s\n", printf("No font found ! Size=%d, mode=%d, bold=%s, italic=%s\n",
@ -606,7 +604,10 @@ TextDrawer::TextDrawer(const wchar_t *text, Client *client,
e.dim.Width = e.font->getDimension(e.text.c_str()).Width; e.dim.Width = e.font->getDimension(e.text.c_str()).Width;
e.dim.Height = e.font->getDimension(L"Yy").Height; e.dim.Height = e.font->getDimension(L"Yy").Height;
#if USE_FREETYPE #if USE_FREETYPE
e.baseline = e.dim.Height - 1 - e.font->getAscender()/64; if (e.font->getType() == irr::gui::EGFT_CUSTOM) {
e.baseline = e.dim.Height - 1 -
((irr::gui::CGUITTFont *)e.font)->getAscender() / 64;
}
#endif #endif
} else { } else {
e.dim = {0, 0}; e.dim = {0, 0};

@ -96,11 +96,7 @@ public:
ValignType valign; ValignType valign;
#if USE_FREETYPE
gui::CGUITTFont *font;
#else
gui::IGUIFont *font; gui::IGUIFont *font;
#endif
irr::video::SColor color; irr::video::SColor color;
irr::video::SColor hovercolor; irr::video::SColor hovercolor;