aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsfan5 <sfan5@live.de>2021-03-29 19:55:24 +0200
committerGitHub <noreply@github.com>2021-03-29 19:55:24 +0200
commit8d89f5f0cc1db47542bd355babad06b6bda54f51 (patch)
tree50cab3ca26b0c6e3f8f6435fb0ffcc47f6b50e1c /src
parent5f4c78a77d99834887a714944899df92a4ebb573 (diff)
downloadminetest-8d89f5f0cc1db47542bd355babad06b6bda54f51.tar.gz
minetest-8d89f5f0cc1db47542bd355babad06b6bda54f51.tar.bz2
minetest-8d89f5f0cc1db47542bd355babad06b6bda54f51.zip
Replace fallback font nonsense with automatic per-glyph fallback (#11084)
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/client/fontengine.cpp95
-rw-r--r--src/client/fontengine.h8
-rw-r--r--src/defaultsettings.cpp5
-rw-r--r--src/irrlicht_changes/CGUITTFont.cpp64
-rw-r--r--src/irrlicht_changes/CGUITTFont.h7
6 files changed, 117 insertions, 65 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8a6eabccc..4bb6877d9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -668,7 +668,10 @@ endif(BUILD_SERVER)
# see issue #4638
set(GETTEXT_BLACKLISTED_LOCALES
ar
+ dv
he
+ hi
+ kn
ky
ms_Arab
th
diff --git a/src/client/fontengine.cpp b/src/client/fontengine.cpp
index 47218c0d9..0382c2f18 100644
--- a/src/client/fontengine.cpp
+++ b/src/client/fontengine.cpp
@@ -56,7 +56,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
readSettings();
- if (m_currentMode == FM_Standard) {
+ 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);
@@ -66,12 +66,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
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);
- }
- else if (m_currentMode == FM_Fallback) {
- g_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL);
g_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
- g_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL);
- g_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL);
}
g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
@@ -102,6 +97,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;
} else if (m_currentMode == FM_Simple) {
@@ -112,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
@@ -130,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;
@@ -204,20 +215,9 @@ unsigned int FontEngine::getFontSize(FontMode mode)
void FontEngine::readSettings()
{
if (USE_FREETYPE && g_settings->getBool("freetype")) {
- m_default_size[FM_Standard] = g_settings->getU16("font_size");
- m_default_size[FM_Fallback] = g_settings->getU16("fallback_font_size");
- m_default_size[FM_Mono] = g_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_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");
@@ -271,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)
@@ -305,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,
- g_settings->get("fallback_font_path"),
- Settings::getLayer(SL_DEFAULTS)->get(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 */
diff --git a/src/client/fontengine.h b/src/client/fontengine.h
index e27ef60e9..3d389ea48 100644
--- a/src/client/fontengine.h
+++ b/src/client/fontengine.h
@@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
enum FontMode : u8 {
FM_Standard = 0,
FM_Mono,
- FM_Fallback,
+ _FM_Fallback, // do not use directly
FM_Simple,
FM_SimpleMono,
FM_MaxMode,
@@ -47,7 +47,7 @@ struct FontSpec {
bold(bold),
italic(italic) {}
- u16 getHash()
+ u16 getHash() const
{
return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic);
}
@@ -132,10 +132,12 @@ public:
void readSettings();
private:
+ irr::gui::IGUIFont *getFont(FontSpec spec, bool may_fail);
+
/** update content of font cache in case of a setting change made it invalid */
void updateFontCache();
- /** initialize a new font */
+ /** initialize a new TTF font */
gui::IGUIFont *initFont(const FontSpec &spec);
/** initialize a font without freetype */
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 9d155f76c..a0d4e9d14 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -304,12 +304,7 @@ void set_default_settings()
settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-BoldItalic.ttf"));
settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
- settings->setDefault("fallback_font_shadow", "1");
- settings->setDefault("fallback_font_shadow_alpha", "128");
-
std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE);
-
- settings->setDefault("fallback_font_size", font_size_str);
#else
settings->setDefault("freetype", "false");
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans"));
diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp
index 960b2320a..8b01e88ae 100644
--- a/src/irrlicht_changes/CGUITTFont.cpp
+++ b/src/irrlicht_changes/CGUITTFont.cpp
@@ -275,7 +275,8 @@ CGUITTFont* CGUITTFont::create(IrrlichtDevice *device, const io::path& filename,
//! Constructor.
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
-batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
+batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0),
+shadow_offset(0), shadow_alpha(0), fallback(0)
{
#ifdef _DEBUG
setDebugName("CGUITTFont");
@@ -640,7 +641,30 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
if (current_color < colors.size())
applied_colors.push_back(colors[current_color]);
}
- offset.X += getWidthFromCharacter(currentChar);
+ if (n > 0)
+ {
+ offset.X += getWidthFromCharacter(currentChar);
+ }
+ else if (fallback != 0)
+ {
+ // Let the fallback font draw it, this isn't super efficient but hopefully that doesn't matter
+ wchar_t l1[] = { (wchar_t) currentChar, 0 }, l2 = (wchar_t) previousChar;
+
+ if (visible)
+ {
+ // Apply kerning.
+ offset.X += fallback->getKerningWidth(l1, &l2);
+ offset.Y += fallback->getKerningHeight();
+
+ u32 current_color = iter.getPos();
+ fallback->draw(core::stringw(l1),
+ core::rect<s32>({offset.X-1, offset.Y-1}, position.LowerRightCorner), // ???
+ current_color < colors.size() ? colors[current_color] : video::SColor(255, 255, 255, 255),
+ false, false, clip);
+ }
+
+ offset.X += fallback->getDimension(l1).Width;
+ }
previousChar = currentChar;
++iter;
@@ -766,6 +790,12 @@ inline u32 CGUITTFont::getWidthFromCharacter(uchar32_t c) const
int w = Glyphs[n-1].advance.x / 64;
return w;
}
+ if (fallback != 0)
+ {
+ wchar_t s[] = { (wchar_t) c, 0 };
+ return fallback->getDimension(s).Width;
+ }
+
if (c >= 0x2000)
return (font_metrics.ascender / 64);
else return (font_metrics.ascender / 64) / 2;
@@ -789,6 +819,12 @@ inline u32 CGUITTFont::getHeightFromCharacter(uchar32_t c) const
s32 height = (font_metrics.ascender / 64) - Glyphs[n-1].offset.Y + Glyphs[n-1].source_rect.getHeight();
return height;
}
+ if (fallback != 0)
+ {
+ wchar_t s[] = { (wchar_t) c, 0 };
+ return fallback->getDimension(s).Height;
+ }
+
if (c >= 0x2000)
return (font_metrics.ascender / 64);
else return (font_metrics.ascender / 64) / 2;
@@ -804,9 +840,9 @@ u32 CGUITTFont::getGlyphIndexByChar(uchar32_t c) const
// Get the glyph.
u32 glyph = FT_Get_Char_Index(tt_face, c);
- // Check for a valid glyph. If it is invalid, attempt to use the replacement character.
+ // Check for a valid glyph.
if (glyph == 0)
- glyph = FT_Get_Char_Index(tt_face, core::unicode::UTF_REPLACEMENT_CHARACTER);
+ return 0;
// If our glyph is already loaded, don't bother doing any batch loading code.
if (glyph != 0 && Glyphs[glyph - 1].isLoaded)
@@ -922,13 +958,26 @@ core::vector2di CGUITTFont::getKerning(const uchar32_t thisLetter, const uchar32
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
+ u32 n = getGlyphIndexByChar(thisLetter);
+
+ // If we don't have this glyph, ask fallback font
+ if (n == 0)
+ {
+ if (fallback != 0) {
+ wchar_t l1 = (wchar_t) thisLetter, l2 = (wchar_t) previousLetter;
+ ret.X = fallback->getKerningWidth(&l1, &l2);
+ ret.Y = fallback->getKerningHeight();
+ }
+ return ret;
+ }
+
// If we don't have kerning, no point in continuing.
if (!FT_HAS_KERNING(tt_face))
return ret;
// Get the kerning information.
FT_Vector v;
- FT_Get_Kerning(tt_face, getGlyphIndexByChar(previousLetter), getGlyphIndexByChar(thisLetter), FT_KERNING_DEFAULT, &v);
+ FT_Get_Kerning(tt_face, getGlyphIndexByChar(previousLetter), n, FT_KERNING_DEFAULT, &v);
// If we have a scalable font, the return value will be in font points.
if (FT_IS_SCALABLE(tt_face))
@@ -960,6 +1009,9 @@ void CGUITTFont::setInvisibleCharacters(const core::ustring& s)
video::IImage* CGUITTFont::createTextureFromChar(const uchar32_t& ch)
{
u32 n = getGlyphIndexByChar(ch);
+ if (n == 0)
+ n = getGlyphIndexByChar((uchar32_t) core::unicode::UTF_REPLACEMENT_CHARACTER);
+
const SGUITTGlyph& glyph = Glyphs[n-1];
CGUITTGlyphPage* page = Glyph_Pages[glyph.glyph_page];
@@ -1147,6 +1199,8 @@ core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text
container.push_back(current_node);
}
offset.X += getWidthFromCharacter(current_char);
+ // Note that fallback font handling is missing here (Minetest never uses this)
+
previous_char = current_char;
++text;
}
diff --git a/src/irrlicht_changes/CGUITTFont.h b/src/irrlicht_changes/CGUITTFont.h
index 310f74f67..a26a1db76 100644
--- a/src/irrlicht_changes/CGUITTFont.h
+++ b/src/irrlicht_changes/CGUITTFont.h
@@ -269,7 +269,7 @@ namespace gui
video::SColor color, bool hcenter=false, bool vcenter=false,
const core::rect<s32>* clip=0);
- virtual void draw(const EnrichedString& text, const core::rect<s32>& position,
+ void draw(const EnrichedString& text, const core::rect<s32>& position,
video::SColor color, bool hcenter=false, bool vcenter=false,
const core::rect<s32>* clip=0);
@@ -313,6 +313,9 @@ namespace gui
//! Get the last glyph page's index.
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
+ //! Set font that should be used for glyphs not present in ours
+ void setFallback(gui::IGUIFont* font) { fallback = font; }
+
//! Create corresponding character's software image copy from the font,
//! so you can use this data just like any ordinary video::IImage.
//! \param ch The character you need
@@ -387,6 +390,8 @@ namespace gui
core::ustring Invisible;
u32 shadow_offset;
u32 shadow_alpha;
+
+ gui::IGUIFont* fallback;
};
} // end namespace gui