From: SmallJoker Date: Tue, 6 Aug 2019 19:33:13 +0000 (+0200) Subject: Clean up and fix freetype=false crashes (#8641) X-Git-Tag: 5.1.0~131 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=233cb86e864affe3dee8f60503584f1eb7e36287;p=oweals%2Fminetest.git Clean up and fix freetype=false crashes (#8641) A IGUIFont of type bitmap/vector cannot be converted to CGUITTFont Fixes various segfaults in gameplay Shorter font cache code, cleaned up (?) --- diff --git a/src/client/fontengine.cpp b/src/client/fontengine.cpp index 59e5bedee..93c3460d7 100644 --- a/src/client/fontengine.cpp +++ b/src/client/fontengine.cpp @@ -55,36 +55,7 @@ FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) : assert(m_env != NULL); // pre-condition assert(m_env->getSkin() != NULL); // pre-condition - m_currentMode = FM_Simple; - -#if USE_FREETYPE - if (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"); - - if (is_yes(gettext("needs_fallback_font"))) { - m_currentMode = FM_Fallback; - } - else { - m_currentMode = FM_Standard; - } - } - - // having freetype but not using it is quite a strange case so we need to do - // special handling for it - if (m_currentMode == FM_Simple) { - std::stringstream fontsize; - fontsize << DEFAULT_FONT_SIZE; - m_settings->setDefault("font_size", fontsize.str()); - m_settings->setDefault("mono_font_size", fontsize.str()); - } -#endif - - m_default_size[FM_Simple] = m_settings->getU16("font_size"); - m_default_size[FM_SimpleMono] = m_settings->getU16("mono_font_size"); - - updateSkin(); + readSettings(); if (m_currentMode == FM_Standard) { m_settings->registerChangedCallback("font_size", font_setting_changed, NULL); @@ -129,32 +100,26 @@ irr::gui::IGUIFont* FontEngine::getFont(unsigned int font_size, FontMode mode) { if (mode == FM_Unspecified) { mode = m_currentMode; - } - else if ((mode == FM_Mono) && (m_currentMode == FM_Simple)) { - mode = FM_SimpleMono; + } else if (m_currentMode == FM_Simple) { + // Freetype disabled -> Force simple mode + mode = (mode == FM_Mono || mode == FM_SimpleMono) ? + FM_SimpleMono : FM_Simple; } - if (font_size == FONT_SIZE_UNSPECIFIED) { + // Fallback to default size + if (font_size == FONT_SIZE_UNSPECIFIED) font_size = m_default_size[mode]; - } - - if ((font_size == m_lastSize) && (mode == m_lastMode)) { - return m_lastFont; - } - if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) { - initFont(font_size, mode); + const auto &cache = m_font_cache[mode]; + if (cache.find(font_size) == cache.end()) { + if (mode == FM_Simple || mode == FM_SimpleMono) + initSimpleFont(font_size, mode); + else + initFont(font_size, mode); } - if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) { - return NULL; - } - - m_lastSize = font_size; - m_lastMode = mode; - m_lastFont = m_font_cache[mode][font_size]; - - return m_font_cache[mode][font_size]; + const auto &font = cache.find(font_size); + return font != cache.end() ? font->second : nullptr; } /******************************************************************************/ @@ -211,20 +176,17 @@ unsigned int FontEngine::getDefaultFontSize() /******************************************************************************/ void FontEngine::readSettings() { -#if USE_FREETYPE - if (g_settings->getBool("freetype")) { + 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"); - if (is_yes(gettext("needs_fallback_font"))) { - m_currentMode = FM_Fallback; - } - else { - m_currentMode = FM_Standard; - } + m_currentMode = is_yes(gettext("needs_fallback_font")) ? + FM_Fallback : FM_Standard; + } else { + m_currentMode = FM_Simple; } -#endif + m_default_size[FM_Simple] = m_settings->getU16("font_size"); m_default_size[FM_SimpleMono] = m_settings->getU16("mono_font_size"); @@ -260,176 +222,100 @@ void FontEngine::updateFontCache() { /* the only font to be initialized is default one, * all others are re-initialized on demand */ - initFont(m_default_size[m_currentMode], m_currentMode); - - /* reset font quick access */ - m_lastMode = FM_Unspecified; - m_lastSize = 0; - m_lastFont = NULL; + getFont(FONT_SIZE_UNSPECIFIED, FM_Unspecified); } /******************************************************************************/ void FontEngine::initFont(unsigned int basesize, FontMode mode) { + assert(mode != FM_Unspecified); + assert(basesize != FONT_SIZE_UNSPECIFIED); - std::string font_config_prefix; - - if (mode == FM_Unspecified) { - mode = m_currentMode; - } + if (m_font_cache[mode].find(basesize) != m_font_cache[mode].end()) + return; - switch (mode) { - case FM_Standard: - font_config_prefix = ""; - break; + std::string setting_prefix = ""; + switch (mode) { case FM_Fallback: - font_config_prefix = "fallback_"; + setting_prefix = "fallback_"; break; - case FM_Mono: - font_config_prefix = "mono_"; - if (m_currentMode == FM_Simple) - mode = FM_SimpleMono; + case FM_SimpleMono: + setting_prefix = "mono_"; break; - - case FM_Simple: /* Fallthrough */ - case FM_SimpleMono: /* Fallthrough */ default: - font_config_prefix = ""; - + break; } - if (m_font_cache[mode].find(basesize) != m_font_cache[mode].end()) - return; - - if ((mode == FM_Simple) || (mode == FM_SimpleMono)) { - initSimpleFont(basesize, mode); - return; + u32 size = std::floor(RenderingEngine::getDisplayDensity() * + m_settings->getFloat("gui_scaling") * basesize); + if (size == 0) { + errorstream << "FontEngine: attempt to use font size 0" << std::endl; + errorstream << " display density: " << RenderingEngine::getDisplayDensity() << std::endl; + abort(); } -#if USE_FREETYPE - else { - if (!is_yes(m_settings->get("freetype"))) { - return; - } - u32 size = std::floor(RenderingEngine::getDisplayDensity() * - m_settings->getFloat("gui_scaling") * basesize); - if (size == 0) { - errorstream << "FontEngine: attempt to use font size 0" << std::endl; - errorstream << " display density: " << RenderingEngine::getDisplayDensity() << std::endl; - abort(); - } - u32 font_shadow = 0; - u32 font_shadow_alpha = 0; - try { - font_shadow = - g_settings->getU16(font_config_prefix + "font_shadow"); - } catch (SettingNotFoundException&) {} - try { - font_shadow_alpha = - g_settings->getU16(font_config_prefix + "font_shadow_alpha"); - } catch (SettingNotFoundException&) {} + u16 font_shadow = 0; + u16 font_shadow_alpha = 0; + g_settings->getU16NoEx(setting_prefix + "font_shadow", font_shadow); + g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha", font_shadow_alpha); - std::string font_path = g_settings->get(font_config_prefix + "font_path"); + std::string fallback_settings[] = { + m_settings->get(setting_prefix + "font_path"), + m_settings->get("fallback_font_path"), + m_settings->getDefault(setting_prefix + "font_path") + }; - irr::gui::IGUIFont* font = gui::CGUITTFont::createTTFont(m_env, +#if USE_FREETYPE + for (const std::string &font_path : fallback_settings) { + irr::gui::IGUIFont *font = gui::CGUITTFont::createTTFont(m_env, font_path.c_str(), size, true, true, font_shadow, font_shadow_alpha); if (font) { + font->grab(); m_font_cache[mode][basesize] = font; return; } - if (font_config_prefix == "mono_") { - const std::string &mono_font_path = m_settings->getDefault("mono_font_path"); - - if (font_path != mono_font_path) { - // try original mono font - errorstream << "FontEngine: failed to load custom mono " - "font: " << font_path << ", trying to fall back to " - "original mono font" << std::endl; - - font = gui::CGUITTFont::createTTFont(m_env, - mono_font_path.c_str(), size, true, true, - font_shadow, font_shadow_alpha); - - if (font) { - m_font_cache[mode][basesize] = font; - return; - } - } - } else { - // try fallback font - errorstream << "FontEngine: failed to load: " << font_path << - ", trying to fall back to fallback font" << std::endl; - - font_path = g_settings->get(font_config_prefix + "fallback_font_path"); - - font = gui::CGUITTFont::createTTFont(m_env, - font_path.c_str(), size, true, true, font_shadow, - font_shadow_alpha); - - if (font) { - m_font_cache[mode][basesize] = font; - return; - } - - const std::string &fallback_font_path = m_settings->getDefault("fallback_font_path"); - - if (font_path != fallback_font_path) { - // try original fallback font - errorstream << "FontEngine: failed to load custom fallback " - "font: " << font_path << ", trying to fall back to " - "original fallback font" << std::endl; - - font = gui::CGUITTFont::createTTFont(m_env, - fallback_font_path.c_str(), size, true, true, - font_shadow, font_shadow_alpha); + errorstream << "FontEngine: Cannot load '" << font_path << + "'. Trying to fall back to another path." << std::endl; + } - if (font) { - m_font_cache[mode][basesize] = font; - return; - } - } - } - // give up - errorstream << "FontEngine: failed to load freetype font: " - << font_path << std::endl; - 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; - abort(); - } + // 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; +#else + errorstream << "FontEngine: Tried to load freetype fonts but Minetest was" + " not compiled with that library." << std::endl; #endif + abort(); } /** initialize a font without freetype */ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode) { - assert(mode == FM_Simple || mode == FM_SimpleMono); // pre-condition + assert(mode == FM_Simple || mode == FM_SimpleMono); - std::string font_path; - if (mode == FM_Simple) { - font_path = m_settings->get("font_path"); - } else { - font_path = m_settings->get("mono_font_path"); - } + const std::string &font_path = m_settings->get( + (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 = font_path.substr(font_path.length() -4); + std::string ending = lowercase(font_path.substr(pos_dot)); if (ending == ".ttf") { - errorstream << "FontEngine: Not trying to open \"" << font_path - << "\" which seems to be a truetype font." << std::endl; + errorstream << "FontEngine: Found font \"" << font_path + << "\" but freetype is not available." << std::endl; return; } - if ((ending == ".xml") || (ending == ".png")) { - basename = font_path.substr(0,font_path.length()-4); - } + if (ending == ".xml" || ending == ".png") + basename = font_path.substr(0, pos_dot); if (basesize == FONT_SIZE_UNSPECIFIED) basesize = DEFAULT_FONT_SIZE; @@ -439,59 +325,35 @@ void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode) m_settings->getFloat("gui_scaling") * basesize); - irr::gui::IGUIFont* font = NULL; - - for(unsigned int offset = 0; offset < MAX_FONT_SIZE_OFFSET; offset++) { - - // try opening positive offset - std::stringstream fontsize_plus_png; - fontsize_plus_png << basename << "_" << (size + offset) << ".png"; - - if (fs::PathExists(fontsize_plus_png.str())) { - font = m_env->getFont(fontsize_plus_png.str().c_str()); - - if (font) { - verbosestream << "FontEngine: found font: " << fontsize_plus_png.str() << std::endl; - break; - } - } + irr::gui::IGUIFont *font = nullptr; + std::string font_extensions[] = { ".png", ".xml" }; - std::stringstream fontsize_plus_xml; - fontsize_plus_xml << basename << "_" << (size + offset) << ".xml"; + // Find nearest matching font scale + // Does a "zig-zag motion" (positibe/negative), from 0 to MAX_FONT_SIZE_OFFSET + for (s32 zoffset = 0; zoffset < MAX_FONT_SIZE_OFFSET * 2; zoffset++) { + std::stringstream path; - if (fs::PathExists(fontsize_plus_xml.str())) { - font = m_env->getFont(fontsize_plus_xml.str().c_str()); + // LSB to sign + s32 sign = (zoffset & 1) ? -1 : 1; + s32 offset = zoffset >> 1; - if (font) { - verbosestream << "FontEngine: found font: " << fontsize_plus_xml.str() << std::endl; - break; - } - } + for (const std::string &ext : font_extensions) { + path.str(""); // Clear + path << basename << "_" << (size + offset * sign) << ext; - // try negative offset - std::stringstream fontsize_minus_png; - fontsize_minus_png << basename << "_" << (size - offset) << ".png"; + if (!fs::PathExists(path.str())) + continue; - if (fs::PathExists(fontsize_minus_png.str())) { - font = m_env->getFont(fontsize_minus_png.str().c_str()); + font = m_env->getFont(path.str().c_str()); if (font) { - verbosestream << "FontEngine: found font: " << fontsize_minus_png.str() << std::endl; + verbosestream << "FontEngine: found font: " << path.str() << std::endl; break; } } - std::stringstream fontsize_minus_xml; - fontsize_minus_xml << basename << "_" << (size - offset) << ".xml"; - - if (fs::PathExists(fontsize_minus_xml.str())) { - font = m_env->getFont(fontsize_minus_xml.str().c_str()); - - if (font) { - verbosestream << "FontEngine: found font: " << fontsize_minus_xml.str() << std::endl; - break; - } - } + if (font) + break; } // try name direct diff --git a/src/client/fontengine.h b/src/client/fontengine.h index a75618f86..62aa71897 100644 --- a/src/client/fontengine.h +++ b/src/client/fontengine.h @@ -112,15 +112,6 @@ private: /** current font engine mode */ FontMode m_currentMode = FM_Standard; - /** font mode of last request */ - FontMode m_lastMode; - - /** size of last request */ - unsigned int m_lastSize = 0; - - /** last font returned */ - irr::gui::IGUIFont* m_lastFont = nullptr; - DISABLE_CLASS_COPY(FontEngine); }; diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp index 42348beb3..e67fae3c6 100644 --- a/src/gui/guiChatConsole.cpp +++ b/src/gui/guiChatConsole.cpp @@ -77,7 +77,7 @@ GUIChatConsole::GUIChatConsole( m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, FM_Mono); if (!m_font) { - errorstream << "GUIChatConsole: Unable to load mono font "; + errorstream << "GUIChatConsole: Unable to load mono font" << std::endl; } else { core::dimension2d dim = m_font->getDimension(L"M"); m_fontsize = v2u32(dim.Width, dim.Height); @@ -322,9 +322,9 @@ void GUIChatConsole::drawText() core::rect destrect( x, y, x + m_fontsize.X * fragment.text.size(), y + m_fontsize.Y); - - #if USE_FREETYPE - // Draw colored text if FreeType is enabled +#if USE_FREETYPE + if (m_font->getType() == irr::gui::EGFT_CUSTOM) { + // Draw colored text if FreeType is enabled irr::gui::CGUITTFont *tmp = dynamic_cast(m_font); tmp->draw( fragment.text, @@ -333,8 +333,10 @@ void GUIChatConsole::drawText() false, false, &AbsoluteClippingRect); - #else - // Otherwise use standard text + } else +#endif + { + // Otherwise use standard text m_font->draw( fragment.text.c_str(), destrect, @@ -342,7 +344,7 @@ void GUIChatConsole::drawText() false, false, &AbsoluteClippingRect); - #endif + } } } } diff --git a/src/irrlicht_changes/static_text.cpp b/src/irrlicht_changes/static_text.cpp index ed1655e0a..5a0f82673 100644 --- a/src/irrlicht_changes/static_text.cpp +++ b/src/irrlicht_changes/static_text.cpp @@ -109,10 +109,22 @@ void StaticText::draw() font->getDimension(cText.c_str()).Width; } - irr::gui::CGUITTFont *tmp = static_cast(font); - tmp->draw(cText, frameRect, - OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), - HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, (RestrainTextInside ? &AbsoluteClippingRect : NULL)); +#if USE_FREETYPE + if (font->getType() == irr::gui::EGFT_CUSTOM) { + irr::gui::CGUITTFont *tmp = static_cast(font); + tmp->draw(cText, frameRect, + OverrideColorEnabled ? OverrideColor : + skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), + HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, + (RestrainTextInside ? &AbsoluteClippingRect : NULL)); + } else +#endif + { + font->draw(Text.c_str(), frameRect, + skin->getColor(EGDC_BUTTON_TEXT), + HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER, + (RestrainTextInside ? &AbsoluteClippingRect : NULL)); + } } else { @@ -140,18 +152,29 @@ void StaticText::draw() font->getDimension(BrokenText[i].c_str()).Width; } - //std::vector colors; - //std::wstring str; EnrichedString str = BrokenText[i]; //str = colorizeText(BrokenText[i].c_str(), colors, previous_color); //if (!colors.empty()) // previous_color = colors[colors.size() - 1]; - irr::gui::CGUITTFont *tmp = static_cast(font); - tmp->draw(str, r, - previous_color, // FIXME - HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL)); +#if USE_FREETYPE + if (font->getType() == irr::gui::EGFT_CUSTOM) { + irr::gui::CGUITTFont *tmp = static_cast(font); + tmp->draw(str, + r, previous_color, // FIXME + HAlign == EGUIA_CENTER, false, + (RestrainTextInside ? &AbsoluteClippingRect : NULL)); + } else +#endif + { + // Draw non-colored text + font->draw(str.c_str(), + r, skin->getColor(EGDC_BUTTON_TEXT), + HAlign == EGUIA_CENTER, false, + (RestrainTextInside ? &AbsoluteClippingRect : NULL)); + } + r.LowerRightCorner.Y += height; r.UpperLeftCorner.Y += height;