Skip to content

Commit

Permalink
Clean up font caching, fix bitmap fonts
Browse files Browse the repository at this point in the history
  • Loading branch information
SmallJoker committed Nov 3, 2019
1 parent 72416a6 commit 388ea73
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 107 deletions.
117 changes: 50 additions & 67 deletions src/client/fontengine.cpp
Expand Up @@ -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),
Expand Down Expand Up @@ -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 ||
FM_SimpleMono : FM_Simple; spec.mode == FM_SimpleMono) ?
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);
const auto &cache = m_font_cache[cache_index]; if (it != cache.end())

return it->second;
if (cache.find(font_size) == cache.end()) {
if (mode == FM_Simple || mode == FM_SimpleMono) // Font does not yet exist
initSimpleFont(font_size, mode); gui::IGUIFont *font = nullptr;
else if (spec.mode == FM_Simple || spec.mode == FM_SimpleMono)
initFont(font_size, mode, bold, italic); font = initSimpleFont(spec);
} else
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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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" };
Expand Down Expand Up @@ -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;
} }
68 changes: 40 additions & 28 deletions src/client/fontengine.h
Expand Up @@ -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,
Expand All @@ -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:
Expand All @@ -47,62 +65,60 @@ class FontEngine


~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 */
Expand All @@ -119,14 +135,10 @@ class FontEngine
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();
Expand All @@ -147,8 +159,8 @@ class FontEngine
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;
Expand Down
17 changes: 9 additions & 8 deletions src/gui/guiHyperText.cpp
Expand Up @@ -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",
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -666,7 +667,7 @@ ParsedText::Element *TextDrawer::getElementAt(core::position2d<s32> pos)
It may be called each time width changes and resulting height can be It may be called each time width changes and resulting height can be
retrieved using getHeight. See GUIHyperText constructor, it uses it once to retrieved using getHeight. See GUIHyperText constructor, it uses it once to
test if text fits in window and eventually another time if width is reduced test if text fits in window and eventually another time if width is reduced
m_floatingbecause of scrollbar added. m_floating because of scrollbar added.
*/ */
void TextDrawer::place(const core::rect<s32> &dest_rect) void TextDrawer::place(const core::rect<s32> &dest_rect)
{ {
Expand Down

0 comments on commit 388ea73

Please sign in to comment.