Clean up font caching, fix bitmap fonts
authorSmallJoker <mk939@ymail.com>
Thu, 17 Oct 2019 18:40:50 +0000 (20:40 +0200)
committerSmallJoker <SmallJoker@users.noreply.github.com>
Sun, 3 Nov 2019 10:45:33 +0000 (11:45 +0100)
src/client/fontengine.cpp
src/client/fontengine.h
src/gui/guiHyperText.cpp
src/gui/guiHyperText.h

index 8120f82df4d926c59c7e4f8b5c5b0779fdea3cf3..26ceda4c5bb8222ccc321d9e79081e714ca9a79d 100644 (file)
@@ -41,11 +41,6 @@ static void font_setting_changed(const std::string &name, void *userdata)
        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) :
        m_settings(main_settings),
@@ -106,45 +101,45 @@ void FontEngine::cleanCache()
 }
 
 /******************************************************************************/
-irr::gui::IGUIFont *FontEngine::getFont(unsigned int font_size, FontMode mode,
-       bool bold, bool italic)
+irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
 {
-       if (mode == FM_Unspecified) {
-               mode = m_currentMode;
+       if (spec.mode == FM_Unspecified) {
+               spec.mode = m_currentMode;
        } else if (m_currentMode == FM_Simple) {
                // Freetype disabled -> Force simple mode
-               mode = (mode == FM_Mono || mode == FM_SimpleMono) ?
-                                FM_SimpleMono : FM_Simple;
+               spec.mode = (spec.mode == FM_Mono ||
+                               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
-       if (font_size == FONT_SIZE_UNSPECIFIED)
-               font_size = m_default_size[mode];
-
-       unsigned int cache_index = get_font_cache_index(mode, bold, italic);
-
-       const auto &cache = m_font_cache[cache_index];
-
-       if (cache.find(font_size) == cache.end()) {
-               if (mode == FM_Simple || mode == FM_SimpleMono)
-                       initSimpleFont(font_size, mode);
-               else
-                       initFont(font_size, mode, bold, italic);
-       }
+       if (spec.size == FONT_SIZE_UNSPECIFIED)
+               spec.size = m_default_size[spec.mode];
+
+       const auto &cache = m_font_cache[spec.getHash()];
+       auto it = cache.find(spec.size);
+       if (it != cache.end())
+               return it->second;
+
+       // Font does not yet exist
+       gui::IGUIFont *font = nullptr;
+       if (spec.mode == FM_Simple || spec.mode == FM_SimpleMono)
+               font = initSimpleFont(spec);
+       else
+               font = initFont(spec);
 
-       if (m_font_cache[cache_index].find(font_size) ==
-                       m_font_cache[cache_index].end())
-               initFont(font_size, mode, bold, italic);
+       m_font_cache[spec.getHash()][spec.size] = font;
 
-       const auto &font = cache.find(font_size);
-       return font != cache.end() ? font->second : nullptr;
+       return font;
 }
 
 /******************************************************************************/
-unsigned int FontEngine::getTextHeight(unsigned int font_size, FontMode mode,
-       bool bold, bool italic)
+unsigned int FontEngine::getTextHeight(const FontSpec &spec)
 {
-       irr::gui::IGUIFont *font = getFont(font_size, mode, bold, italic);
+       irr::gui::IGUIFont *font = getFont(spec);
 
        // use current skin font as fallback
        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 font_size, FontMode mode, bool bold, bool italic)
+unsigned int FontEngine::getTextWidth(const std::wstring &text, const FontSpec &spec)
 {
-       irr::gui::IGUIFont *font = getFont(font_size, mode, bold, italic);
+       irr::gui::IGUIFont *font = getFont(spec);
 
        // use current skin font as fallback
        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) */
-unsigned int FontEngine::getLineHeight(unsigned int font_size, FontMode mode,
-       bool bold, bool italic)
+unsigned int FontEngine::getLineHeight(const FontSpec &spec)
 {
-       irr::gui::IGUIFont *font = getFont(font_size, mode, bold, italic);
+       irr::gui::IGUIFont *font = getFont(spec);
 
        // use current skin font as fallback
        if (font == NULL) {
@@ -250,21 +243,14 @@ void FontEngine::updateFontCache()
 }
 
 /******************************************************************************/
-void FontEngine::initFont(unsigned int basesize, FontMode mode,
-       bool bold, bool italic)
+gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
 {
-       assert(mode != FM_Unspecified);
-       assert(basesize != 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;
+       assert(spec.mode != FM_Unspecified);
+       assert(spec.size != FONT_SIZE_UNSPECIFIED);
 
        std::string setting_prefix = "";
 
-       switch (mode) {
+       switch (spec.mode) {
                case FM_Fallback:
                        setting_prefix = "fallback_";
                        break;
@@ -276,12 +262,14 @@ void FontEngine::initFont(unsigned int basesize, FontMode mode,
                        break;
        }
 
-       std::string setting_suffix = (bold) ?
-                       ((italic) ? "_bold_italic" : "_bold") :
-                       ((italic) ? "_italic" : "");
+       std::string setting_suffix = "";
+       if (spec.bold)
+               setting_suffix.append("_bold");
+       if (spec.italic)
+               setting_suffix.append("_italic");
 
        u32 size = std::floor(RenderingEngine::getDisplayDensity() *
-                       m_settings->getFloat("gui_scaling") * basesize);
+                       m_settings->getFloat("gui_scaling") * spec.size);
 
        if (size == 0) {
                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_shadow_alpha);
 
-               if (font) {
-                       m_font_cache[cache_index][basesize] = font;
-                       return;
-               }
+               if (font)
+                       return font;
 
                errorstream << "FontEngine: Cannot load '" << font_path <<
                                "'. 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 */
-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(
-                       (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('.');
        std::string basename = font_path;
@@ -346,19 +333,16 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
        if (ending == ".ttf") {
                errorstream << "FontEngine: Found font \"" << font_path
                                << "\" but freetype is not available." << std::endl;
-               return;
+               return nullptr;
        }
 
        if (ending == ".xml" || ending == ".png")
                basename = font_path.substr(0, pos_dot);
 
-       if (basesize == FONT_SIZE_UNSPECIFIED)
-               basesize = DEFAULT_FONT_SIZE;
-
        u32 size = std::floor(
                        RenderingEngine::getDisplayDensity() *
                        m_settings->getFloat("gui_scaling") *
-                       basesize);
+                       spec.size);
 
        irr::gui::IGUIFont *font = nullptr;
        std::string font_extensions[] = { ".png", ".xml" };
@@ -400,6 +384,5 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
                }
        }
 
-       if (font)
-               m_font_cache[get_font_cache_index(mode)][basesize] = font;
+       return font;
 }
index ecffc7660854e881fc16df60d03839fd5cee8d53..53f14c45f76577febcf8e797c4313f4dd45a3744 100644 (file)
@@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #define FONT_SIZE_UNSPECIFIED 0xFFFFFFFF
 
-enum FontMode {
+enum FontMode : u8 {
        FM_Standard = 0,
        FM_Mono,
        FM_Fallback,
@@ -39,6 +39,24 @@ enum FontMode {
        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
 {
 public:
@@ -47,62 +65,60 @@ public:
 
        ~FontEngine();
 
-       /** get Font */
-       irr::gui::IGUIFont *getFont(unsigned int font_size, FontMode mode,
-                       bool bold, bool italic);
+       // Get best possible font specified by FontSpec
+       irr::gui::IGUIFont *getFont(FontSpec spec);
 
        irr::gui::IGUIFont *getFont(unsigned int font_size=FONT_SIZE_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 */
-       unsigned int getTextHeight(unsigned int font_size, FontMode mode,
-                       bool bold, bool italic);
+       unsigned int getTextHeight(const FontSpec &spec);
 
        /** get text width if a text for a specific font */
        unsigned int getTextHeight(
                        unsigned int font_size=FONT_SIZE_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 font_size, FontMode mode, bool bold, bool italic);
+       unsigned int getTextWidth(const std::wstring &text, const FontSpec &spec);
 
        /** get text width if a text for a specific font */
        unsigned int getTextWidth(const std::wstring& text,
                        unsigned int font_size=FONT_SIZE_UNSPECIFIED,
                        FontMode mode=FM_Unspecified)
        {
-               return getTextWidth(text, font_size, mode, m_default_bold,
-                               m_default_italic);
+               FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
+               return getTextWidth(text, spec);
        }
 
-       unsigned int getTextWidth(const std::string& text,
-                       unsigned int font_size, FontMode mode, bool bold, bool italic)
+       unsigned int getTextWidth(const std::string &text, const FontSpec &spec)
        {
-               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 font_size=FONT_SIZE_UNSPECIFIED,
                        FontMode mode=FM_Unspecified)
        {
-               return getTextWidth(utf8_to_wide(text), font_size, mode, m_default_bold,
-                               m_default_italic);
+               FontSpec spec(font_size, mode, m_default_bold, m_default_italic);
+               return getTextWidth(utf8_to_wide(text), spec);
        }
 
        /** get line height for a specific font (including empty room between lines) */
-       unsigned int getLineHeight(unsigned int font_size, FontMode mode, bool bold,
-                       bool italic);
+       unsigned int getLineHeight(const FontSpec &spec);
 
        unsigned int getLineHeight(unsigned int font_size=FONT_SIZE_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 */
@@ -119,14 +135,10 @@ private:
        void updateFontCache();
 
        /** initialize a new font */
-       void initFont(
-               unsigned int basesize,
-               FontMode mode,
-               bool bold,
-               bool italic);
+       gui::IGUIFont *initFont(const FontSpec &spec);
 
        /** 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 */
        void updateSkin();
@@ -147,8 +159,8 @@ private:
        unsigned int m_default_size[FM_MaxMode];
 
        /** default bold and italic */
-       bool m_default_bold;
-       bool m_default_italic;
+       bool m_default_bold = false;
+       bool m_default_italic = false;
 
        /** current font engine mode */
        FontMode m_currentMode = FM_Standard;
index 024e4de090a4127b82295936df7524f55d853c63..e5f9457892efe96ac8250d41ef2291e579842973 100644 (file)
@@ -71,14 +71,12 @@ void ParsedText::Element::setStyle(StyleList &style)
        if (style["fontstyle"] == "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
        // Build a new fontengine ?
-       this->font =
-#if USE_FREETYPE
-                       (gui::CGUITTFont *)
-#endif
-                                       g_fontengine->getFont(font_size, font_mode,
-                                                       is_yes(style["bold"]), is_yes(style["italic"]));
+       this->font = g_fontengine->getFont(spec);
 
        if (!this->font)
                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.Height = e.font->getDimension(L"Yy").Height;
 #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
                                } else {
                                        e.dim = {0, 0};
@@ -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
    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
-   m_floatingbecause of scrollbar added.
+   m_floating because of scrollbar added.
 */
 void TextDrawer::place(const core::rect<s32> &dest_rect)
 {
index e3ad0e74740d597d27f9c85ef8bbef2acbac3e8a..3ea8732cd01f4d5bfe1876f109a4ba6f6913c5d6 100644 (file)
@@ -96,11 +96,7 @@ public:
 
                ValignType valign;
 
-#if USE_FREETYPE
-               gui::CGUITTFont *font;
-#else
                gui::IGUIFont *font;
-#endif
 
                irr::video::SColor color;
                irr::video::SColor hovercolor;