LCOV - code coverage report
Current view: top level - src - fontengine.cpp (source / functions) Hit Total Coverage
Test: report Lines: 105 218 48.2 %
Date: 2015-07-11 18:23:49 Functions: 11 16 68.8 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2014 sapier <sapier at gmx dot net>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : #include "fontengine.h"
      20             : #include "log.h"
      21             : #include "config.h"
      22             : #include "porting.h"
      23             : #include "constants.h"
      24             : #include "filesys.h"
      25             : 
      26             : #if USE_FREETYPE
      27             : #include "gettext.h"
      28             : #include "xCGUITTFont.h"
      29             : #endif
      30             : 
      31             : /** maximum size distance for getting a "similar" font size */
      32             : #define MAX_FONT_SIZE_OFFSET 10
      33             : 
      34             : /** reference to access font engine, has to be initialized by main */
      35             : FontEngine* g_fontengine = NULL;
      36             : 
      37             : /** callback to be used on change of font size setting */
      38           0 : static void font_setting_changed(const std::string, void *userdata) {
      39           0 :         g_fontengine->readSettings();
      40           0 : }
      41             : 
      42             : /******************************************************************************/
      43           1 : FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
      44             :         m_settings(main_settings),
      45             :         m_env(env),
      46             :         m_font_cache(),
      47             :         m_currentMode(FM_Standard),
      48             :         m_lastMode(),
      49             :         m_lastSize(0),
      50           1 :         m_lastFont(NULL)
      51             : {
      52             : 
      53           6 :         for (unsigned int i = 0; i < FM_MaxMode; i++) {
      54           5 :                 m_default_size[i] = (FontMode) FONT_SIZE_UNSPECIFIED;
      55             :         }
      56             : 
      57             :         assert(m_settings != NULL); // pre-condition
      58             :         assert(m_env != NULL); // pre-condition
      59             :         assert(m_env->getSkin() != NULL); // pre-condition
      60             : 
      61           1 :         m_currentMode = FM_Simple;
      62             : 
      63             : #if USE_FREETYPE
      64           1 :         if (g_settings->getBool("freetype")) {
      65           1 :                 m_default_size[FM_Standard] = m_settings->getU16("font_size");
      66           1 :                 m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
      67           1 :                 m_default_size[FM_Mono]     = m_settings->getU16("mono_font_size");
      68             : 
      69           1 :                 if (is_yes(gettext("needs_fallback_font"))) {
      70           0 :                         m_currentMode = FM_Fallback;
      71             :                 }
      72             :                 else {
      73           1 :                         m_currentMode = FM_Standard;
      74             :                 }
      75             :         }
      76             : 
      77             :         // having freetype but not using it is quite a strange case so we need to do
      78             :         // special handling for it
      79           1 :         if (m_currentMode == FM_Simple) {
      80           0 :                 std::stringstream fontsize;
      81           0 :                 fontsize << DEFAULT_FONT_SIZE;
      82           0 :                 m_settings->setDefault("font_size", fontsize.str());
      83           0 :                 m_settings->setDefault("mono_font_size", fontsize.str());
      84             :         }
      85             : #endif
      86             : 
      87           1 :         m_default_size[FM_Simple]       = m_settings->getU16("font_size");
      88           1 :         m_default_size[FM_SimpleMono]   = m_settings->getU16("mono_font_size");
      89             : 
      90           1 :         updateSkin();
      91             : 
      92           1 :         if (m_currentMode == FM_Standard) {
      93           1 :                 m_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
      94           1 :                 m_settings->registerChangedCallback("font_path", font_setting_changed, NULL);
      95           1 :                 m_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL);
      96           1 :                 m_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL);
      97             :         }
      98           0 :         else if (m_currentMode == FM_Fallback) {
      99           0 :                 m_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL);
     100           0 :                 m_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
     101           0 :                 m_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL);
     102           0 :                 m_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL);
     103             :         }
     104             : 
     105           1 :         m_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
     106           1 :         m_settings->registerChangedCallback("mono_font_size", font_setting_changed, NULL);
     107           1 :         m_settings->registerChangedCallback("screen_dpi", font_setting_changed, NULL);
     108           1 :         m_settings->registerChangedCallback("gui_scaling", font_setting_changed, NULL);
     109           1 : }
     110             : 
     111             : /******************************************************************************/
     112           2 : FontEngine::~FontEngine()
     113             : {
     114           1 :         cleanCache();
     115           1 : }
     116             : 
     117             : /******************************************************************************/
     118           1 : void FontEngine::cleanCache()
     119             : {
     120           6 :         for ( unsigned int i = 0; i < FM_MaxMode; i++) {
     121             : 
     122          16 :                 for (std::map<unsigned int, irr::gui::IGUIFont*>::iterator iter
     123           5 :                                 = m_font_cache[i].begin();
     124          14 :                                 iter != m_font_cache[i].end(); iter++) {
     125           2 :                         iter->second->drop();
     126           2 :                         iter->second = NULL;
     127             :                 }
     128           5 :                 m_font_cache[i].clear();
     129             :         }
     130           1 : }
     131             : 
     132             : /******************************************************************************/
     133       15487 : irr::gui::IGUIFont* FontEngine::getFont(unsigned int font_size, FontMode mode)
     134             : {
     135       15487 :         if (mode == FM_Unspecified) {
     136       15486 :                 mode = m_currentMode;
     137             :         }
     138           1 :         else if ((mode == FM_Mono) && (m_currentMode == FM_Simple)) {
     139           0 :                 mode = FM_SimpleMono;
     140             :         }
     141             : 
     142       15487 :         if (font_size == FONT_SIZE_UNSPECIFIED) {
     143       15487 :                 font_size = m_default_size[mode];
     144             :         }
     145             : 
     146       15487 :         if ((font_size == m_lastSize) && (mode == m_lastMode)) {
     147       15484 :                 return m_lastFont;
     148             :         }
     149             : 
     150           3 :         if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) {
     151           2 :                 initFont(font_size, mode);
     152             :         }
     153             : 
     154           3 :         if (m_font_cache[mode].find(font_size) == m_font_cache[mode].end()) {
     155           0 :                 return NULL;
     156             :         }
     157             : 
     158           3 :         m_lastSize = font_size;
     159           3 :         m_lastMode = mode;
     160           3 :         m_lastFont = m_font_cache[mode][font_size];
     161             : 
     162           3 :         return m_font_cache[mode][font_size];
     163             : }
     164             : 
     165             : /******************************************************************************/
     166        2502 : unsigned int FontEngine::getTextHeight(unsigned int font_size, FontMode mode)
     167             : {
     168        2502 :         irr::gui::IGUIFont* font = getFont(font_size, mode);
     169             : 
     170             :         // use current skin font as fallback
     171        2502 :         if (font == NULL) {
     172           0 :                 font = m_env->getSkin()->getFont();
     173             :         }
     174        2502 :         FATAL_ERROR_IF(font == NULL, "Could not get skin font");
     175             : 
     176        2502 :         return font->getDimension(L"Some unimportant example String").Height;
     177             : }
     178             : 
     179             : /******************************************************************************/
     180        1243 : unsigned int FontEngine::getTextWidth(const std::wstring& text,
     181             :                 unsigned int font_size, FontMode mode)
     182             : {
     183        1243 :         irr::gui::IGUIFont* font = getFont(font_size, mode);
     184             : 
     185             :         // use current skin font as fallback
     186        1243 :         if (font == NULL) {
     187           0 :                 font = m_env->getSkin()->getFont();
     188             :         }
     189        1243 :         FATAL_ERROR_IF(font == NULL, "Could not get font");
     190             : 
     191        1243 :         return font->getDimension(text.c_str()).Width;
     192             : }
     193             : 
     194             : 
     195             : /** get line height for a specific font (including empty room between lines) */
     196        1241 : unsigned int FontEngine::getLineHeight(unsigned int font_size, FontMode mode)
     197             : {
     198        1241 :         irr::gui::IGUIFont* font = getFont(font_size, mode);
     199             : 
     200             :         // use current skin font as fallback
     201        1241 :         if (font == NULL) {
     202           0 :                 font = m_env->getSkin()->getFont();
     203             :         }
     204        1241 :         FATAL_ERROR_IF(font == NULL, "Could not get font");
     205             : 
     206        1241 :         return font->getDimension(L"Some unimportant example String").Height
     207        1241 :                         + font->getKerningHeight();
     208             : }
     209             : 
     210             : /******************************************************************************/
     211           0 : unsigned int FontEngine::getDefaultFontSize()
     212             : {
     213           0 :         return m_default_size[m_currentMode];
     214             : }
     215             : 
     216             : /******************************************************************************/
     217           0 : void FontEngine::readSettings()
     218             : {
     219             : #if USE_FREETYPE
     220           0 :         if (g_settings->getBool("freetype")) {
     221           0 :                 m_default_size[FM_Standard] = m_settings->getU16("font_size");
     222           0 :                 m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
     223           0 :                 m_default_size[FM_Mono]     = m_settings->getU16("mono_font_size");
     224             : 
     225           0 :                 if (is_yes(gettext("needs_fallback_font"))) {
     226           0 :                         m_currentMode = FM_Fallback;
     227             :                 }
     228             :                 else {
     229           0 :                         m_currentMode = FM_Standard;
     230             :                 }
     231             :         }
     232             : #endif
     233           0 :         m_default_size[FM_Simple]       = m_settings->getU16("font_size");
     234           0 :         m_default_size[FM_SimpleMono]   = m_settings->getU16("mono_font_size");
     235             : 
     236           0 :         cleanCache();
     237           0 :         updateFontCache();
     238           0 :         updateSkin();
     239           0 : }
     240             : 
     241             : /******************************************************************************/
     242           1 : void FontEngine::updateSkin()
     243             : {
     244           1 :         gui::IGUIFont *font = getFont();
     245             : 
     246           1 :         if (font)
     247           1 :                 m_env->getSkin()->setFont(font);
     248             :         else
     249           0 :                 errorstream << "FontEngine: Default font file: " <<
     250           0 :                                 "\n\t\"" << m_settings->get("font_path") << "\"" <<
     251           0 :                                 "\n\trequired for current screen configuration was not found" <<
     252           0 :                                 " or was invalid file format." <<
     253           0 :                                 "\n\tUsing irrlicht default font." << std::endl;
     254             : 
     255             :         // If we did fail to create a font our own make irrlicht find a default one
     256           1 :         font = m_env->getSkin()->getFont();
     257           1 :         FATAL_ERROR_IF(font == NULL, "Could not create/get font");
     258             : 
     259           1 :         u32 text_height = font->getDimension(L"Hello, world!").Height;
     260           1 :         infostream << "text_height=" << text_height << std::endl;
     261           1 : }
     262             : 
     263             : /******************************************************************************/
     264           0 : void FontEngine::updateFontCache()
     265             : {
     266             :         /* the only font to be initialized is default one,
     267             :          * all others are re-initialized on demand */
     268           0 :         initFont(m_default_size[m_currentMode], m_currentMode);
     269             : 
     270             :         /* reset font quick access */
     271           0 :         m_lastMode = FM_Unspecified;
     272           0 :         m_lastSize = 0;
     273           0 :         m_lastFont = NULL;
     274           0 : }
     275             : 
     276             : /******************************************************************************/
     277           2 : void FontEngine::initFont(unsigned int basesize, FontMode mode)
     278             : {
     279             : 
     280           4 :         std::string font_config_prefix;
     281             : 
     282           2 :         if (mode == FM_Unspecified) {
     283           0 :                 mode = m_currentMode;
     284             :         }
     285             : 
     286           2 :         switch (mode) {
     287             : 
     288             :                 case FM_Standard:
     289           1 :                         font_config_prefix = "";
     290           1 :                         break;
     291             : 
     292             :                 case FM_Fallback:
     293           0 :                         font_config_prefix = "fallback_";
     294           0 :                         break;
     295             : 
     296             :                 case FM_Mono:
     297           1 :                         font_config_prefix = "mono_";
     298           1 :                         if (m_currentMode == FM_Simple)
     299           0 :                                 mode = FM_SimpleMono;
     300           1 :                         break;
     301             : 
     302             :                 case FM_Simple: /* Fallthrough */
     303             :                 case FM_SimpleMono: /* Fallthrough */
     304             :                 default:
     305           0 :                         font_config_prefix = "";
     306             : 
     307             :         }
     308             : 
     309           2 :         if (m_font_cache[mode].find(basesize) != m_font_cache[mode].end())
     310           0 :                 return;
     311             : 
     312           2 :         if ((mode == FM_Simple) || (mode == FM_SimpleMono)) {
     313           0 :                 initSimpleFont(basesize, mode);
     314           0 :                 return;
     315             :         }
     316             : #if USE_FREETYPE
     317             :         else {
     318           2 :                 if (! is_yes(m_settings->get("freetype"))) {
     319           0 :                         return;
     320             :                 }
     321           2 :                 unsigned int size = floor(
     322           4 :                                 porting::getDisplayDensity() *
     323           6 :                                 m_settings->getFloat("gui_scaling") *
     324           2 :                                 basesize);
     325           2 :                 u32 font_shadow       = 0;
     326           2 :                 u32 font_shadow_alpha = 0;
     327             : 
     328             :                 try {
     329             :                         font_shadow =
     330           3 :                                         g_settings->getU16(font_config_prefix + "font_shadow");
     331           1 :                 } catch (SettingNotFoundException&) {}
     332             :                 try {
     333             :                         font_shadow_alpha =
     334           3 :                                         g_settings->getU16(font_config_prefix + "font_shadow_alpha");
     335           1 :                 } catch (SettingNotFoundException&) {}
     336             : 
     337           4 :                 std::string font_path = g_settings->get(font_config_prefix + "font_path");
     338             : 
     339           4 :                 irr::gui::IGUIFont* font = gui::CGUITTFont::createTTFont(m_env,
     340             :                                 font_path.c_str(), size, true, true, font_shadow,
     341           2 :                                 font_shadow_alpha);
     342             : 
     343           2 :                 if (font != NULL) {
     344           2 :                         m_font_cache[mode][basesize] = font;
     345             :                 }
     346             :                 else {
     347           0 :                         errorstream << "FontEngine: failed to load freetype font: "
     348           0 :                                         << font_path << std::endl;
     349             :                 }
     350             :         }
     351             : #endif
     352             : }
     353             : 
     354             : /** initialize a font without freetype */
     355           0 : void FontEngine::initSimpleFont(unsigned int basesize, FontMode mode)
     356             : {
     357             :         assert(mode == FM_Simple || mode == FM_SimpleMono); // pre-condition
     358             : 
     359           0 :         std::string font_path = "";
     360           0 :         if (mode == FM_Simple) {
     361           0 :                 font_path = m_settings->get("font_path");
     362             :         } else {
     363           0 :                 font_path = m_settings->get("mono_font_path");
     364             :         }
     365           0 :         std::string basename = font_path;
     366           0 :         std::string ending = font_path.substr(font_path.length() -4);
     367             : 
     368           0 :         if (ending == ".ttf") {
     369           0 :                 errorstream << "FontEngine: Not trying to open \"" << font_path
     370           0 :                                 << "\" which seems to be a truetype font." << std::endl;
     371           0 :                 return;
     372             :         }
     373             : 
     374           0 :         if ((ending == ".xml") || (ending == ".png")) {
     375           0 :                 basename = font_path.substr(0,font_path.length()-4);
     376             :         }
     377             : 
     378           0 :         if (basesize == FONT_SIZE_UNSPECIFIED)
     379           0 :                 basesize = DEFAULT_FONT_SIZE;
     380             : 
     381           0 :         unsigned int size = floor(
     382           0 :                         porting::getDisplayDensity() *
     383           0 :                         m_settings->getFloat("gui_scaling") *
     384           0 :                         basesize);
     385             : 
     386           0 :         irr::gui::IGUIFont* font = NULL;
     387             : 
     388           0 :         for(unsigned int offset = 0; offset < MAX_FONT_SIZE_OFFSET; offset++) {
     389             : 
     390             :                 // try opening positive offset
     391           0 :                 std::stringstream fontsize_plus_png;
     392           0 :                 fontsize_plus_png << basename << "_" << (size + offset) << ".png";
     393             : 
     394           0 :                 if (fs::PathExists(fontsize_plus_png.str())) {
     395           0 :                         font = m_env->getFont(fontsize_plus_png.str().c_str());
     396             : 
     397           0 :                         if (font) {
     398           0 :                                 verbosestream << "FontEngine: found font: " << fontsize_plus_png.str() << std::endl;
     399           0 :                                 break;
     400             :                         }
     401             :                 }
     402             : 
     403           0 :                 std::stringstream fontsize_plus_xml;
     404           0 :                 fontsize_plus_xml << basename << "_" << (size + offset) << ".xml";
     405             : 
     406           0 :                 if (fs::PathExists(fontsize_plus_xml.str())) {
     407           0 :                         font = m_env->getFont(fontsize_plus_xml.str().c_str());
     408             : 
     409           0 :                         if (font) {
     410           0 :                                 verbosestream << "FontEngine: found font: " << fontsize_plus_xml.str() << std::endl;
     411           0 :                                 break;
     412             :                         }
     413             :                 }
     414             : 
     415             :                 // try negative offset
     416           0 :                 std::stringstream fontsize_minus_png;
     417           0 :                 fontsize_minus_png << basename << "_" << (size - offset) << ".png";
     418             : 
     419           0 :                 if (fs::PathExists(fontsize_minus_png.str())) {
     420           0 :                         font = m_env->getFont(fontsize_minus_png.str().c_str());
     421             : 
     422           0 :                         if (font) {
     423           0 :                                 verbosestream << "FontEngine: found font: " << fontsize_minus_png.str() << std::endl;
     424           0 :                                 break;
     425             :                         }
     426             :                 }
     427             : 
     428           0 :                 std::stringstream fontsize_minus_xml;
     429           0 :                 fontsize_minus_xml << basename << "_" << (size - offset) << ".xml";
     430             : 
     431           0 :                 if (fs::PathExists(fontsize_minus_xml.str())) {
     432           0 :                         font = m_env->getFont(fontsize_minus_xml.str().c_str());
     433             : 
     434           0 :                         if (font) {
     435           0 :                                 verbosestream << "FontEngine: found font: " << fontsize_minus_xml.str() << std::endl;
     436           0 :                                 break;
     437             :                         }
     438             :                 }
     439             :         }
     440             : 
     441             :         // try name direct
     442           0 :         if (font == NULL) {
     443           0 :                 if (fs::PathExists(font_path)) {
     444           0 :                         font = m_env->getFont(font_path.c_str());
     445           0 :                         if (font)
     446           0 :                                 verbosestream << "FontEngine: found font: " << font_path << std::endl;
     447             :                 }
     448             :         }
     449             : 
     450           0 :         if (font != NULL) {
     451           0 :                 font->grab();
     452           0 :                 m_font_cache[mode][basesize] = font;
     453             :         }
     454           3 : }

Generated by: LCOV version 1.11