]> git.lizzy.rs Git - minetest.git/blobdiff - src/client/fontengine.cpp
fontengine: Fix crash loading PNG/XML fonts from paths without dot
[minetest.git] / src / client / fontengine.cpp
index a55420846a74c576150ba3f19d2d200009f63b18..f64315db476a9f3355f17cc7ebd8a1ca9689b28e 100644 (file)
@@ -42,8 +42,7 @@ static void font_setting_changed(const std::string &name, void *userdata)
 }
 
 /******************************************************************************/
-FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
-       m_settings(main_settings),
+FontEngine::FontEngine(gui::IGUIEnvironment* env) :
        m_env(env)
 {
 
@@ -51,34 +50,29 @@ FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
                i = (FontMode) FONT_SIZE_UNSPECIFIED;
        }
 
-       assert(m_settings != NULL); // pre-condition
+       assert(g_settings != NULL); // pre-condition
        assert(m_env != NULL); // pre-condition
        assert(m_env->getSkin() != NULL); // pre-condition
 
        readSettings();
 
-       if (m_currentMode == FM_Standard) {
-               m_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_bold", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_italic", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_path", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_path_bold", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_path_italic", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL);
-       }
-       else if (m_currentMode == FM_Fallback) {
-               m_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL);
-               m_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL);
+       if (m_currentMode != FM_Simple) {
+               g_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_bold", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_italic", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_path", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_path_bold", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_path_italic", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL);
+               g_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
        }
 
-       m_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
-       m_settings->registerChangedCallback("mono_font_size", font_setting_changed, NULL);
-       m_settings->registerChangedCallback("screen_dpi", font_setting_changed, NULL);
-       m_settings->registerChangedCallback("gui_scaling", font_setting_changed, NULL);
+       g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
+       g_settings->registerChangedCallback("mono_font_size", font_setting_changed, NULL);
+       g_settings->registerChangedCallback("screen_dpi", font_setting_changed, NULL);
+       g_settings->registerChangedCallback("gui_scaling", font_setting_changed, NULL);
 }
 
 /******************************************************************************/
@@ -102,6 +96,11 @@ void FontEngine::cleanCache()
 
 /******************************************************************************/
 irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
+{
+       return getFont(spec, false);
+}
+
+irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec, bool may_fail)
 {
        if (spec.mode == FM_Unspecified) {
                spec.mode = m_currentMode;
@@ -113,6 +112,10 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
                // Support for those could be added, but who cares?
                spec.bold = false;
                spec.italic = false;
+       } else if (spec.mode == _FM_Fallback) {
+               // Fallback font doesn't support these either
+               spec.bold = false;
+               spec.italic = false;
        }
 
        // Fallback to default size
@@ -131,6 +134,13 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
        else
                font = initFont(spec);
 
+       if (!font && !may_fail) {
+               errorstream << "Minetest cannot continue without a valid font. "
+                       "Please correct the 'font_path' setting or install the font "
+                       "file in the proper location." << std::endl;
+               abort();
+       }
+
        m_font_cache[spec.getHash()][spec.size] = font;
 
        return font;
@@ -205,30 +215,19 @@ unsigned int FontEngine::getFontSize(FontMode mode)
 void FontEngine::readSettings()
 {
        if (USE_FREETYPE && g_settings->getBool("freetype")) {
-               m_default_size[FM_Standard] = m_settings->getU16("font_size");
-               m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
-               m_default_size[FM_Mono]     = m_settings->getU16("mono_font_size");
-
-               /*~ DO NOT TRANSLATE THIS LITERALLY!
-               This is a special string. Put either "no" or "yes"
-               into the translation field (literally).
-               Choose "yes" if the language requires use of the fallback
-               font, "no" otherwise.
-               The fallback font is (normally) required for languages with
-               non-Latin script, like Chinese.
-               When in doubt, test your translation. */
-               m_currentMode = is_yes(gettext("needs_fallback_font")) ?
-                               FM_Fallback : FM_Standard;
-
-               m_default_bold = m_settings->getBool("font_bold");
-               m_default_italic = m_settings->getBool("font_italic");
+               m_default_size[FM_Standard]  = g_settings->getU16("font_size");
+               m_default_size[_FM_Fallback] = g_settings->getU16("font_size");
+               m_default_size[FM_Mono]      = g_settings->getU16("mono_font_size");
+
+               m_default_bold = g_settings->getBool("font_bold");
+               m_default_italic = g_settings->getBool("font_italic");
 
        } else {
                m_currentMode = FM_Simple;
        }
 
-       m_default_size[FM_Simple]       = m_settings->getU16("font_size");
-       m_default_size[FM_SimpleMono]   = m_settings->getU16("mono_font_size");
+       m_default_size[FM_Simple]       = g_settings->getU16("font_size");
+       m_default_size[FM_SimpleMono]   = g_settings->getU16("mono_font_size");
 
        cleanCache();
        updateFontCache();
@@ -244,7 +243,7 @@ void FontEngine::updateSkin()
                m_env->getSkin()->setFont(font);
        else
                errorstream << "FontEngine: Default font file: " <<
-                               "\n\t\"" << m_settings->get("font_path") << "\"" <<
+                               "\n\t\"" << g_settings->get("font_path") << "\"" <<
                                "\n\trequired for current screen configuration was not found" <<
                                " or was invalid file format." <<
                                "\n\tUsing irrlicht default font." << std::endl;
@@ -272,18 +271,8 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
        assert(spec.size != FONT_SIZE_UNSPECIFIED);
 
        std::string setting_prefix = "";
-
-       switch (spec.mode) {
-               case FM_Fallback:
-                       setting_prefix = "fallback_";
-                       break;
-               case FM_Mono:
-               case FM_SimpleMono:
-                       setting_prefix = "mono_";
-                       break;
-               default:
-                       break;
-       }
+       if (spec.mode == FM_Mono)
+               setting_prefix = "mono_";
 
        std::string setting_suffix = "";
        if (spec.bold)
@@ -292,7 +281,7 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
                setting_suffix.append("_italic");
 
        u32 size = std::floor(RenderingEngine::getDisplayDensity() *
-                       m_settings->getFloat("gui_scaling") * spec.size);
+                       g_settings->getFloat("gui_scaling") * spec.size);
 
        if (size == 0) {
                errorstream << "FontEngine: attempt to use font size 0" << std::endl;
@@ -306,38 +295,41 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
        g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha",
                        font_shadow_alpha);
 
-       std::string wanted_font_path;
-       wanted_font_path = g_settings->get(setting_prefix + "font_path" + setting_suffix);
+       std::string path_setting;
+       if (spec.mode == _FM_Fallback)
+               path_setting = "fallback_font_path";
+       else
+               path_setting = setting_prefix + "font_path" + setting_suffix;
 
        std::string fallback_settings[] = {
-               wanted_font_path,
-               m_settings->get("fallback_font_path"),
-               m_settings->getDefault(setting_prefix + "font_path")
+               g_settings->get(path_setting),
+               Settings::getLayer(SL_DEFAULTS)->get(path_setting)
        };
 
 #if USE_FREETYPE
        for (const std::string &font_path : fallback_settings) {
-               irr::gui::IGUIFont *font = gui::CGUITTFont::createTTFont(m_env,
+               gui::CGUITTFont *font = gui::CGUITTFont::createTTFont(m_env,
                                font_path.c_str(), size, true, true, font_shadow,
                                font_shadow_alpha);
 
-               if (font)
-                       return font;
-
-               errorstream << "FontEngine: Cannot load '" << font_path <<
+               if (!font) {
+                       errorstream << "FontEngine: Cannot load '" << font_path <<
                                "'. Trying to fall back to another path." << std::endl;
-       }
-
+                       continue;
+               }
 
-       // give up
-       errorstream << "minetest can not continue without a valid font. "
-                       "Please correct the 'font_path' setting or install the font "
-                       "file in the proper location" << std::endl;
+               if (spec.mode != _FM_Fallback) {
+                       FontSpec spec2(spec);
+                       spec2.mode = _FM_Fallback;
+                       font->setFallback(getFont(spec2, true));
+               }
+               return font;
+       }
 #else
-       errorstream << "FontEngine: Tried to load freetype fonts but Minetest was"
-                       " not compiled with that library." << std::endl;
+       errorstream << "FontEngine: Tried to load TTF font but Minetest was"
+                       " compiled without Freetype." << std::endl;
 #endif
-       abort();
+       return nullptr;
 }
 
 /** initialize a font without freetype */
@@ -346,12 +338,13 @@ gui::IGUIFont *FontEngine::initSimpleFont(const FontSpec &spec)
        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 = g_settings->get(
                        (spec.mode == FM_SimpleMono) ? "mono_font_path" : "font_path");
 
        size_t pos_dot = font_path.find_last_of('.');
-       std::string basename = font_path;
-       std::string ending = lowercase(font_path.substr(pos_dot));
+       std::string basename = font_path, ending;
+       if (pos_dot != std::string::npos)
+               ending = lowercase(font_path.substr(pos_dot));
 
        if (ending == ".ttf") {
                errorstream << "FontEngine: Found font \"" << font_path
@@ -364,7 +357,7 @@ gui::IGUIFont *FontEngine::initSimpleFont(const FontSpec &spec)
 
        u32 size = std::floor(
                        RenderingEngine::getDisplayDensity() *
-                       m_settings->getFloat("gui_scaling") *
+                       g_settings->getFloat("gui_scaling") *
                        spec.size);
 
        irr::gui::IGUIFont *font = nullptr;