From 2dfdc0061d400ffad39f974d7fe9348204af0d08 Mon Sep 17 00:00:00 2001 From: Iris Morelle Date: Wed, 10 Mar 2021 16:39:29 -0300 Subject: [PATCH] Remove SDL_ttf wrapper API This removes the build-time dependencies on SDL_ttf and FriBidi, alongside the SDL_ttf wrappers, the SDL_ttf text surface class, the SDL_ttf render cache, and the SDL_ttf (de)initialization code. --- CMakeLists.txt | 13 - SConstruct | 5 - source_lists/libwesnoth | 3 - src/CMakeLists.txt | 10 - src/display.cpp | 1 - src/font/font_config.cpp | 2 - src/font/font_config.hpp | 9 +- src/font/font_id.hpp | 86 ----- src/font/sdl_ttf.cpp | 566 ----------------------------- src/font/sdl_ttf.hpp | 84 ----- src/font/text_cache.cpp | 57 --- src/font/text_cache.hpp | 38 -- src/font/text_surface.cpp | 200 ---------- src/font/text_surface.hpp | 66 ---- src/gui/widgets/text_box.cpp | 1 - src/help/help_impl.hpp | 4 +- src/help/help_text_area.cpp | 1 + src/help/help_topic_generators.cpp | 1 - src/show_dialog.cpp | 1 - src/widgets/button.cpp | 1 - src/widgets/menu.cpp | 2 +- src/widgets/textbox.cpp | 1 - 22 files changed, 6 insertions(+), 1146 deletions(-) delete mode 100644 src/font/font_id.hpp delete mode 100644 src/font/sdl_ttf.cpp delete mode 100644 src/font/sdl_ttf.hpp delete mode 100644 src/font/text_cache.cpp delete mode 100644 src/font/text_cache.hpp delete mode 100644 src/font/text_surface.cpp delete mode 100644 src/font/text_surface.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 10514f0a0d6..169a647579a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,9 +40,6 @@ set(LOCALEDIR "translations" CACHE STRING "change the name of the locale data di set(PREFERENCES_DIR "" CACHE STRING "Use a non-default preferences directory (.wesnoth on unix)") set(DEFAULT_PREFS_FILE "" CACHE STRING "Set system wide preferences file") -#Game options -option(ENABLE_FRIBIDI "Enable FriBIDi support" ON) - #server options set(SERVER_UID "" CACHE STRING "User id of the user who runs wesnothd") set(SERVER_GID "" CACHE STRING "Group id of the user who runs wesnothd") @@ -521,7 +518,6 @@ if(ENABLE_GAME OR ENABLE_TESTS) find_package(SDL2 2.0.4 REQUIRED) find_package(SDL2_image 2.0.2 REQUIRED) find_package(SDL2_mixer 2.0.0 REQUIRED) - find_package(SDL2_ttf 2.0.12 REQUIRED) find_package(VorbisFile REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(CAIRO REQUIRED cairo>=1.10) @@ -535,15 +531,6 @@ if(ENABLE_TESTS) endif(ENABLE_TESTS) if(ENABLE_GAME) - if(ENABLE_FRIBIDI) - PKG_CHECK_MODULES(FRIBIDI fribidi>=0.10.9) - if(FRIBIDI_FOUND) - add_definitions(-DHAVE_FRIBIDI) - elseif(NOT FRIBIDI_FOUND) - message("Could not find FriBiDi. Disabling FriBiDi support.") - endif(FRIBIDI_FOUND) - endif(ENABLE_FRIBIDI) - if(ENABLE_NOTIFICATIONS) pkg_check_modules(LIBDBUS dbus-1) if(LIBDBUS_FOUND) diff --git a/SConstruct b/SConstruct index 711fdc60985..ab234107a02 100755 --- a/SConstruct +++ b/SConstruct @@ -65,7 +65,6 @@ opts.AddVariables( ('cachedir', 'Directory that contains a cache of derived files.', ''), PathVariable('datadir', 'read-only architecture-independent game data', "$datarootdir/$datadirname", PathVariable.PathAccept), PathVariable('fifodir', 'directory for the wesnothd fifo socket file', "/var/run/wesnothd", PathVariable.PathAccept), - BoolVariable('fribidi','Clear to disable bidirectional-language support', True), BoolVariable('desktop_entry','Clear to disable desktop-entry', True), BoolVariable('appdata_file','Clear to not install appdata file', True), BoolVariable('systemd','Install systemd unit file for wesnothd', bool(WhereIs("systemd"))), @@ -363,7 +362,6 @@ if env["prereqs"]: def have_sdl_other(): return \ conf.CheckSDL(require_version = '2.0.4') & \ - conf.CheckSDL("SDL2_ttf", header_file = "SDL_ttf") & \ conf.CheckSDL("SDL2_mixer", header_file = "SDL_mixer") & \ conf.CheckSDL("SDL2_image", header_file = "SDL_image") @@ -418,7 +416,6 @@ if env["prereqs"]: have_X = conf.CheckLib('X11') env["notifications"] = env["notifications"] and conf.CheckPKG("dbus-1") - client_env['fribidi'] = client_env['fribidi'] and (conf.CheckPKG('fribidi >= 0.10.9') or Warning("Can't find FriBiDi, disabling FriBiDi support.")) env["history"] = env["history"] and (conf.CheckLib("history") or Warning("Can't find GNU history, disabling history support.")) client_env = conf.Finish() @@ -426,8 +423,6 @@ if env["prereqs"]: # We set those outside of Configure() section because SCons doesn't merge CPPPATH var properly in conf.Finish() if env["notifications"]: client_env.Append(CPPDEFINES = ["HAVE_LIBDBUS"]) - if client_env['fribidi']: - client_env.Append(CPPDEFINES = ["HAVE_FRIBIDI"]) if env["history"]: client_env.Append(CPPDEFINES = ["HAVE_HISTORY"]) diff --git a/source_lists/libwesnoth b/source_lists/libwesnoth index cce9b9ca69a..64d296b422f 100644 --- a/source_lists/libwesnoth +++ b/source_lists/libwesnoth @@ -8,13 +8,10 @@ events.cpp floating_label.cpp font/font_config.cpp font/marked-up_text.cpp -font/sdl_ttf.cpp font/sdl_ttf_compat.cpp font/standard_colors.cpp font/text.cpp -font/text_cache.cpp font/text_formatting.cpp -font/text_surface.cpp format_time_summary.cpp formula/string_utils.cpp game_end_exceptions.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d8a5ae0b98..f7a0fae2d7a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,10 +32,6 @@ if(SDL2MIXER_INCLUDE_DIR) include_directories(SYSTEM ${SDL2MIXER_INCLUDE_DIR} ) set(sdl_mixer-lib ${SDL2_MIXER_LIBRARY}) endif() -if(SDL2TTF_INCLUDE_DIR) - include_directories(SYSTEM ${SDL2TTF_INCLUDE_DIR} ) - set(sdl_ttf-lib ${SDL2_TTF_LIBRARY}) -endif() if(ZLIB_INCLUDE_DIR) include_directories(SYSTEM ${ZLIB_INCLUDE_DIR} ) @@ -77,7 +73,6 @@ set(game-external-libs ${Boost_THREAD_LIBRARY} ${sdl_image-lib} ${sdl_mixer-lib} - ${sdl_ttf-lib} ${PANGOCAIRO_LIBRARIES} ${FONTCONFIG_LIBRARIES} ${LIBDBUS_LIBRARIES} @@ -103,11 +98,6 @@ set(server-external-libs -lpthread ) -if(ENABLE_FRIBIDI AND FRIBIDI_FOUND) - set(game-external-libs ${game-external-libs} ${FRIBIDI_LIBRARIES}) - include_directories(SYSTEM ${FRIBIDI_INCLUDE_DIRS} ) -endif(ENABLE_FRIBIDI AND FRIBIDI_FOUND) - if(APPLE) set(game-external-libs ${game-external-libs} "-framework IOKit") endif(APPLE) diff --git a/src/display.cpp b/src/display.cpp index 3f59b09e4c9..89c7081cded 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -21,7 +21,6 @@ #include "cursor.hpp" #include "display.hpp" #include "fake_unit_manager.hpp" -#include "font/sdl_ttf.hpp" #include "font/sdl_ttf_compat.hpp" #include "font/text.hpp" #include "preferences/game.hpp" diff --git a/src/font/font_config.cpp b/src/font/font_config.cpp index 7364f62f62d..3a81410c859 100644 --- a/src/font/font_config.cpp +++ b/src/font/font_config.cpp @@ -15,7 +15,6 @@ #include "font/font_config.hpp" #include "font/font_description.hpp" #include "font/error.hpp" -#include "font/sdl_ttf.hpp" #include "config.hpp" #include "log.hpp" @@ -192,7 +191,6 @@ bool load_font_config() if(fontlist.empty()) return false; - sdl_ttf::set_font_list(fontlist); return true; } diff --git a/src/font/font_config.hpp b/src/font/font_config.hpp index 36a690ac378..0e8b4de1618 100644 --- a/src/font/font_config.hpp +++ b/src/font/font_config.hpp @@ -16,12 +16,10 @@ /*** * The font::manager initializes cairo and font_config in order to figure out - * what local fonts to use. It also asks SDL_TTF to initialize itself, via the - * sdl_ttf raii object. + * what local fonts to use. */ #include "font_options.hpp" -#include "sdl_ttf.hpp" class t_string; @@ -41,11 +39,6 @@ struct manager { manager(const manager &) = delete; manager & operator = (const manager &) = delete; - -private: - - /** Initialize sdl_ttf concurrent with font::manager lifetime */ - sdl_ttf sdl_ttf_initializer_; }; /*** diff --git a/src/font/font_id.hpp b/src/font/font_id.hpp deleted file mode 100644 index 5d958258061..00000000000 --- a/src/font/font_id.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by Chris Beck - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -/*** - * Note: Specific to SDL_TTF code path - */ - -#pragma once - -#include -#include - -#include - -/*** - * Note: This is specific to SDL_TTF code path - */ - -namespace font -{ -/** - * Font family, acts an an enumeration with each font loaded by stl_ttf::set_font_list getting an - * individual value. The values do not necessarily correspond to the order of the list passed to - * stl_ttf::set_font_list, all positive values should be treated as opaque data. - * - * Negative values are returned by sdl_ttf::split_text to denote chunks which can't be handled with - * the available fonts. - */ -typedef int subset_id; - -// Used as a key in requests to the functions in sdl_text.hpp (and the font table in sdl_text.cpp's implementation) -struct font_id -{ - explicit font_id(subset_id subset, int size) : subset(subset), size(size), style(TTF_STYLE_NORMAL) {} - explicit font_id(subset_id subset, int size, int style) : subset(subset), size(size), style(style) {} - - bool operator==(const font_id& o) const - { - return subset == o.subset && size == o.size && style == o.style; - } - bool operator<(const font_id& o) const - { - return std::tie(subset, size, style) < std::tie(o.subset, o.size, o.style); - } - - subset_id subset; - int size; - /** - * Bitmask of the values TTF_STYLE_BOLD, TTF_STYLE_ITALIC. - */ - int style; -}; - -/** - * A string that should be rendered with a single font. Longer texts that need - * characters from multiple fonts are cut into these sub-strings. - * - * Text chunk is used by text_surfaces and these are cached sometimes. - */ -struct text_chunk -{ - text_chunk(subset_id subset, std::string&& text) - : subset(subset) - , text(std::move(text)) - { - } - - bool operator==(const text_chunk& t) const { return subset == t.subset && text == t.text; } - bool operator!=(const text_chunk& t) const { return !operator==(t); } - - subset_id subset; - std::string text; -}; - -} // end namespace font diff --git a/src/font/sdl_ttf.cpp b/src/font/sdl_ttf.cpp deleted file mode 100644 index c7eddd43262..00000000000 --- a/src/font/sdl_ttf.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by Chris Beck - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#include "font/sdl_ttf.hpp" - -#include "font/error.hpp" -#include "font/font_config.hpp" -#include "font/font_id.hpp" -#include "font/text_cache.hpp" -#include "font/text_surface.hpp" - -#include "filesystem.hpp" -#include "font/marked-up_text.hpp" -#include "game_config.hpp" -#include "log.hpp" -#include "preferences/general.hpp" -#include "tooltips.hpp" - -#include "sdl/rect.hpp" -#include "sdl/surface.hpp" -#include "serialization/unicode.hpp" - -#include - -#include -#include -#include - -static lg::log_domain log_font("font"); -#define DBG_FT LOG_STREAM(debug, log_font) -#define LOG_FT LOG_STREAM(info, log_font) -#define WRN_FT LOG_STREAM(warn, log_font) -#define ERR_FT LOG_STREAM(err, log_font) - -namespace font -{ -namespace -{ -// Record stored in the font table. -// If the record for font_id (FOO, Bold + Underline) is a record (BAR, Bold), -// it means that BAR is a Bold-styled version of FOO which we shipped with the -// game, and now SDL_TTF should be used to style BAR as underline for the final results. -struct ttf_record -{ - std::shared_ptr font; - int style; -}; -static std::map font_table; - -// The indices in these vectors correspond to the font_id.subset values in font_table. -static std::vector font_names; -static std::vector bold_names; -static std::vector italic_names; - -struct family_record -{ - std::shared_ptr font; - subset_id subset; - std::string name; -}; -/** - * Used for implementing find_font_containing, the elements are in the same order as the arguments - * to set_font_list(). The fonts here are a subset of those in font_table, because - * find_font_containing doesn't need size-specific instances of a font. - * - * In most locales, the subset_ids will match the indices into this vector. This is only a - * coincidence, and it won't be true (at the time of writing) in Chinese. - * - * \todo Are all variants of a font guaranteed to have exactly the same glyphs? For example, might - * an italic variant only contain the glyphs which are major improvements on an automatic skew of - * the non-italic version? - */ -std::vector family_table; - -const auto no_font_found = family_record{nullptr, -1, ""}; -/** - * Given a unicode code point, returns the first (using the order passed to set_font_list) font - * that includes that code point. Returns no_font_found if none of the known fonts contain this value. - */ -const family_record& find_font_containing(int ch) -{ - for(const auto& i : family_table) { - if(TTF_GlyphIsProvided(i.font.get(), ch)) { - return i; - } - } - LOG_FT << "Glyph " << ch << " not provided by any font\n"; - return no_font_found; -} - -// cache sizes of small text -typedef std::map line_size_cache_map; - -// map of styles -> sizes -> cache -static std::map> line_size_cache; - -/** - * Destructor for using std::unique_ptr or std::shared_ptr as an RAII holder for a TTF_Font. - */ -struct font_deleter -{ - void operator()(TTF_Font* font) - { - if(font != nullptr) - TTF_CloseFont(font); - } -}; - -std::shared_ptr open_font(const std::string& fname, int size) -{ - std::string name; - if(!game_config::path.empty()) { - name = game_config::path + "/fonts/" + fname; - if(!filesystem::file_exists(name)) { - name = "fonts/" + fname; - if(!filesystem::file_exists(name)) { - name = fname; - if(!filesystem::file_exists(name)) { - ERR_FT << "Failed opening font: '" << name << "': No such file or directory" << std::endl; - return nullptr; - } - } - } - - } else { - name = "fonts/" + fname; - if(!filesystem::file_exists(name)) { - if(!filesystem::file_exists(fname)) { - ERR_FT << "Failed opening font: '" << name << "': No such file or directory" << std::endl; - return nullptr; - } - name = fname; - } - } - - filesystem::rwops_ptr rwops = filesystem::make_read_RWops(name); - std::unique_ptr font; - font.reset(TTF_OpenFontRW(rwops.release(), true, size)); // SDL takes ownership of rwops - if(font == nullptr) { - ERR_FT << "Failed opening font: '" << fname << "'\n"; - ERR_FT << "TTF_OpenFont: " << TTF_GetError() << std::endl; - return nullptr; - } - - DBG_FT << "Opened a font: " << fname << ", in size " << size << std::endl; - - return font; -} - -} // anonymous namespace - -// Gets an appropriately configured TTF Font, for this font size and style. -// Loads fonts if necessary. For styled fonts, we search for a ``shipped'' -// version of the font which is prestyled. If this fails we find the closest -// thing which we did ship, and store a record of this, which allows to -// rapidly correct the remaining styling using SDL_TTF. -// -// Uses the font table for caching. -std::shared_ptr sdl_ttf::get_font(font_id id) -{ - const auto it = font_table.find(id); - if(it != font_table.end() && it->second.font != nullptr) { - return it->second.font; - } - - // There's no record, so we need to try to find a solution for this font - // and make a record of it. If the indices are out of bounds don't bother though. - if(id.subset < 0 || std::size_t(id.subset) >= font_names.size()) { - return nullptr; - } - - // Favor to use the shipped Italic font over bold if both are present and are needed. - if((id.style & TTF_STYLE_ITALIC) && italic_names[id.subset].size()) { - if(auto font = open_font(italic_names[id.subset], id.size)) { - ttf_record rec{font, TTF_STYLE_ITALIC}; - // The next line adds bold if needed - TTF_SetFontStyle(font.get(), id.style ^ TTF_STYLE_ITALIC); - font_table.emplace(id, rec); - return font; - } - } - - // Now see if the shipped Bold font is useful and available. - if((id.style & TTF_STYLE_BOLD) && bold_names[id.subset].size()) { - if(auto font = open_font(bold_names[id.subset], id.size)) { - ttf_record rec{font, TTF_STYLE_BOLD}; - // The next line adds italic if needed - TTF_SetFontStyle(font.get(), id.style ^ TTF_STYLE_BOLD); - font_table.emplace(id, rec); - return font; - } - } - - // Try just to use the basic version of the font then. - if(font_names[id.subset].size()) { - if(auto font = open_font(font_names[id.subset], id.size)) { - ttf_record rec{font, TTF_STYLE_NORMAL}; - TTF_SetFontStyle(font.get(), id.style); - font_table.emplace(id, rec); - return font; - } - } - - // Failed to find a font. - ttf_record rec{nullptr, TTF_STYLE_NORMAL}; - font_table.emplace(id, rec); - return nullptr; -} - -/*** - * Interface to SDL_TTF - */ - -static surface render_text(const std::string& text, int fontsize, const color_t& color, int style) -{ - // we keep blank lines and spaces (may be wanted for indentation) - const std::vector lines = utils::split(text, '\n', 0); - std::vector> surfaces; - surfaces.reserve(lines.size()); - std::size_t width = 0, height = 0; - - for(std::vector< std::string >::const_iterator ln = lines.begin(), ln_end = lines.end(); ln != ln_end; ++ln) { - - int sz = fontsize; - int text_style = style; - - text_surface txt_surf(sz, color, text_style); - - txt_surf.set_text(*ln); - - const text_surface& cached_surf = text_cache::find(txt_surf); - const std::vector&res = cached_surf.get_surfaces(); - - if (!res.empty()) { - surfaces.push_back(res); - width = std::max(cached_surf.width(), width); - height += cached_surf.height(); - } - } - - if (surfaces.empty()) { - return surface(); - } else if (surfaces.size() == 1 && surfaces.front().size() == 1) { - surface surf = surfaces.front().front(); - return surf; - } else { - surface res(width,height); - if (!res) - return res; - - std::size_t ypos = 0; - for(std::vector< std::vector>::iterator i = surfaces.begin(), - i_end = surfaces.end(); i != i_end; ++i) { - std::size_t xpos = 0; - height = 0; - - for(std::vector::iterator j = i->begin(), - j_end = i->end(); j != j_end; ++j) { - SDL_Rect dstrect = sdl::create_rect(xpos, ypos, 0, 0); - blit_surface(*j, nullptr, res, &dstrect); - xpos += (*j)->w; - height = std::max((*j)->h, height); - } - ypos += height; - } - - return res; - } -} - - -surface get_rendered_text(const std::string& str, int size, const color_t& color, int style) -{ - return render_text(str, size, color, style); -} - -SDL_Rect draw_text_line(surface& gui_surface, const SDL_Rect& area, int size, - const color_t& color, const std::string& text, - int x, int y, bool use_tooltips, int style) -{ - size = preferences::font_scaled(size); - if (!gui_surface) { - const text_surface& u = text_cache::find(text_surface(text, size, color, style)); - return sdl::create_rect(0, 0, u.width(), u.height()); - } - - if(area.w == 0) { // no place to draw - return {0, 0, 0, 0}; - } - - const std::string etext = make_text_ellipsis(text, size, area.w); - - surface surface(render_text(etext,size,color,style)); - if(surface == nullptr) { - return {0, 0, 0, 0}; - } - - SDL_Rect dest; - if(x!=-1) { - dest.x = x; -#ifdef HAVE_FRIBIDI - // Oron -- Conditional, until all draw_text_line calls have fixed area parameter - if(getenv("NO_RTL") == nullptr) { - bool is_rtl = text_cache::find(text_surface(text, size, color, style)).is_rtl(); - if(is_rtl) - dest.x = area.x + area.w - surface->w - (x - area.x); - } -#endif - } else - dest.x = (area.w/2)-(surface->w/2); - if(y!=-1) - dest.y = y; - else - dest.y = (area.h/2)-(surface->h/2); - dest.w = surface->w; - dest.h = surface->h; - - if(line_width(text, size) > area.w) { - tooltips::add_tooltip(dest,text); - } - - if(dest.x + dest.w > area.x + area.w) { - dest.w = area.x + area.w - dest.x; - } - - if(dest.y + dest.h > area.y + area.h) { - dest.h = area.y + area.h - dest.y; - } - - if(gui_surface != nullptr) { - SDL_Rect src = dest; - src.x = 0; - src.y = 0; - sdl_blit(surface,&src,gui_surface,&dest); - } - - if(use_tooltips) { - tooltips::add_tooltip(dest,text); - } - - return dest; -} - -int line_width(const std::string& line, int font_size, int style) -{ - return line_size(line,font_size,style).w; -} - -SDL_Rect line_size(const std::string& line, int font_size, int style) -{ - line_size_cache_map& cache = line_size_cache[style][font_size]; - - const line_size_cache_map::const_iterator i = cache.find(line); - if(i != cache.end()) { - return i->second; - } - - SDL_Rect res; - - const color_t col { 0, 0, 0, 0 }; - text_surface s(line, font_size, col, style); - - res.w = s.width(); - res.h = s.height(); - res.x = res.y = 0; - - cache.emplace(line,res); - return res; -} - -std::string make_text_ellipsis(const std::string &text, int font_size, - int max_width, int style) -{ - if (line_width(text, font_size, style) <= max_width) - return text; - if(line_width(ellipsis, font_size, style) > max_width) - return ""; - - std::string current_substring; - - try { - utf8::iterator itor(text); - for(; itor != utf8::iterator::end(text); ++itor) { - std::string tmp = current_substring; - tmp.append(itor.substr().first, itor.substr().second); - - if (line_width(tmp + ellipsis, font_size, style) > max_width) { - return current_substring + ellipsis; - } - - current_substring.append(itor.substr().first, itor.substr().second); - } - } - catch(utf8::invalid_utf8_exception&) { - WRN_FT << "Invalid UTF-8 string: \"" << text << "\"" << std::endl; - return ""; - } - - return text; // Should not happen -} - -/*** - * Initialize and destruction - */ - -sdl_ttf::sdl_ttf() -{ - const int res = TTF_Init(); - if(res == -1) { - ERR_FT << "Could not initialize SDL_TTF" << std::endl; - throw font::error("SDL_TTF could not initialize, TTF_INIT returned: " + std::to_string(res)); - } else { - LOG_FT << "Initialized true type fonts\n"; - } -} - -static void clear_fonts() -{ - // Ensure that the shared_ptrs' destructors run before TTF_Quit(). - font_table.clear(); - family_table.clear(); - - font_names.clear(); - bold_names.clear(); - italic_names.clear(); - - line_size_cache.clear(); -} - -sdl_ttf::~sdl_ttf() -{ - clear_fonts(); - TTF_Quit(); -} - -// sets the font list to be used. -void sdl_ttf::set_font_list(const std::vector& fontlist) -{ - // Wesnoth's startup sequence usually loads the same set of fonts twice. - // See if we can use the already-loaded fonts. - if(!font_names.empty()) { - std::vector reordered_family_table; - bool found_all_fonts = true; - for(const auto& f : fontlist) { - // Ignore fonts if the font file doesn't exist - this matches the behavior of when we - // can't reuse the already-loaded fonts. - if(!check_font_file(f.name)) - continue; - const auto& old_record = std::find_if( - family_table.cbegin(), family_table.cend(), [&f](family_record x) { return f.name == x.name; }); - if(old_record == family_table.cend()) { - found_all_fonts = false; - break; - } - reordered_family_table.emplace_back(*old_record); - } - if(found_all_fonts) { - std::swap(family_table, reordered_family_table); - DBG_FT << "Reordered the font list, the order is now:\n"; - for(const auto& x : family_table) { - DBG_FT << "[" << x.subset << "]:\t\tbase:\t'" << x.name << "'\n"; - } - return; - } - } - - // The existing fonts weren't sufficient, or this is the first time that this function has been - // called. Load all the fonts from scratch. - clear_fonts(); - - // To access TTF_GlyphIsProvided, we need to create instances of each font. Choose a size that - // the GUI will want to use. - const auto default_size = preferences::font_scaled(font::SIZE_NORMAL); - - for(const auto& f : fontlist) { - if(!check_font_file(f.name)) - continue; - // Insert fonts only if the font file exists - const subset_id subset = font_names.size(); - font_names.push_back(f.name); - - if(f.bold_name && check_font_file(*f.bold_name)) { - bold_names.push_back(*f.bold_name); - } else { - bold_names.emplace_back(); - } - - if(f.italic_name && check_font_file(*f.italic_name)) { - italic_names.push_back(*f.italic_name); - } else { - italic_names.emplace_back(); - } - - auto font = sdl_ttf::get_font(font_id{subset, default_size}); - family_table.push_back(family_record{std::move(font), subset, f.name}); - } - - assert(font_names.size() == bold_names.size()); - assert(font_names.size() == italic_names.size()); - - DBG_FT << "Set the font list. The styled font families are:\n"; - - for(std::size_t i = 0; i < font_names.size(); ++i) { - DBG_FT << "[" << i << "]:\t\tbase:\t'" << font_names[i] << "'\tbold:\t'" << bold_names[i] << "'\titalic:\t'" - << italic_names[i] << "'\n"; - } -} - -/** - * Splits the UTF-8 text into text_chunks using the same font. - * - * This uses a greedy-match - once we've found the start of a chunk, - * include as many characters as we can in the same chunk. - * - * If we've got a fallback font that contains all characters, and a - * preferred font that will only contains some of them, this means that - * we minimize the number of times that we switch from one font to the - * other - once we've had to use the fallback, keep using it. - * - * This also means that combining characters such as U+308 or U+FE00 are - * kept with the character that they should be modifying. - */ -std::vector sdl_ttf::split_text(const std::string& utf8_text) -{ - std::vector chunks; - - if(utf8_text.empty()) - return chunks; - - try { - const auto end = utf8::iterator::end(utf8_text); - auto chunk_start = utf8::iterator(utf8_text); - while(chunk_start != end) { - auto& family = find_font_containing(*chunk_start); - if(family.subset >= 0) { - auto ch = chunk_start; - auto last_in_chunk = chunk_start; - while(ch != end && TTF_GlyphIsProvided(family.font.get(), *ch)) { - last_in_chunk = ch; - ++ch; - } - chunks.emplace_back( - family.subset, std::string{chunk_start.substr().first, last_in_chunk.substr().second}); - chunk_start = ch; - } else { - ++chunk_start; - } - } - } catch(utf8::invalid_utf8_exception&) { - WRN_FT << "Invalid UTF-8 string: \"" << utf8_text << "\"" << std::endl; - } - return chunks; -} - -} // end namespace font diff --git a/src/font/sdl_ttf.hpp b/src/font/sdl_ttf.hpp deleted file mode 100644 index 5d15c04220a..00000000000 --- a/src/font/sdl_ttf.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright (C) 2003 - 2018 by David White - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#pragma once - -#include "constants.hpp" -#include "font_id.hpp" -#include "font_description.hpp" -#include "color.hpp" - -#include -#include - -#include - -class surface; - -namespace font { - -// Returns a SDL surface containing the text rendered in a given color. -surface get_rendered_text(const std::string& text, int size, const color_t& color, int style=0); - -SDL_Rect draw_text_line(surface& gui_surface, const SDL_Rect& area, int size, - const color_t& color, const std::string& text, - int x, int y, bool use_tooltips, int style); - -/** - * Determine the width of a line of text given a certain font size. - * The font type used is the default wesnoth font type. - */ -int line_width(const std::string& line, int font_size, int style=TTF_STYLE_NORMAL); - -/** - * Determine the size of a line of text given a certain font size. Similar to - * line_width, but for both coordinates. - */ -SDL_Rect line_size(const std::string& line, int font_size, int style=TTF_STYLE_NORMAL); - -/** - * If the text exceeds the specified max width, end it with an ellipsis (...) - */ -std::string make_text_ellipsis(const std::string& text, int font_size, int max_width, - int style = TTF_STYLE_NORMAL); - -/*** - * Object which initializes and destroys SDL_TTF, and manages caches of open fonts. - * - * This isn't properly self-contained, the .cpp file (and the implementations - * of the other functions in this .hpp file) expect that there will be exactly - * one instance of this object. - */ -struct sdl_ttf -{ - sdl_ttf(); - ~sdl_ttf(); - - sdl_ttf(const sdl_ttf&) = delete; - sdl_ttf& operator=(const sdl_ttf&) = delete; - - // Load a font - static std::shared_ptr get_font(font_id); - - /** - * Set the list of fonts. The order denotes the priority - if text could be rendered with more than one of these - * fonts, the one given earlier will be used. - */ - static void set_font_list(const std::vector& fontlist); - - // Split a utf8 string into text_chunks - static std::vector split_text(const std::string& utf8_text); -}; - -} // end namespace font diff --git a/src/font/text_cache.cpp b/src/font/text_cache.cpp deleted file mode 100644 index abf4b74e7a0..00000000000 --- a/src/font/text_cache.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by Chris Beck - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#include "font/text_cache.hpp" -#include "sdl/surface.hpp" - -#include - -namespace font { - -text_cache::text_list text_cache::cache_; - -unsigned int text_cache::max_size_ = 50; - -void text_cache::resize(unsigned int size) -{ - // DBG_FT << "Text cache: resize from: " << max_size_ << " to: " - // << size << " items in cache: " << cache_.size() << '\n'; - - while(size < cache_.size()) { - cache_.pop_back(); - } - max_size_ = size; -} - -text_surface &text_cache::find(const text_surface& t) -{ - static std::size_t lookup_ = 0, hit_ = 0; - text_list::iterator it_bgn = cache_.begin(), it_end = cache_.end(); - text_list::iterator it = std::find(it_bgn, it_end, t); - if (it != it_end) { - cache_.splice(it_bgn, cache_, it); - ++hit_; - } else { - if (cache_.size() >= max_size_) - cache_.pop_back(); - cache_.push_front(t); - } - if (++lookup_ % 1000 == 0) { - // DBG_FT << "Text cache: " << lookup_ << " lookups, " << (hit_ / 10) << "% hits\n"; - hit_ = 0; - } - return cache_.front(); -} - -} // end namespace font diff --git a/src/font/text_cache.hpp b/src/font/text_cache.hpp deleted file mode 100644 index bed066e4c8c..00000000000 --- a/src/font/text_cache.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by Chris Beck - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -/** - * Note: Specific to sdl_ttf - */ - -#pragma once - -#include "text_surface.hpp" - -#include - -namespace font { - -class text_cache -{ -public: - static text_surface &find(const text_surface& t); - static void resize(unsigned int size); -private: - typedef std::list< text_surface > text_list; - static text_list cache_; - static unsigned int max_size_; -}; - -} // end namespace font diff --git a/src/font/text_surface.cpp b/src/font/text_surface.cpp deleted file mode 100644 index e41f5eb2b50..00000000000 --- a/src/font/text_surface.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by Chris Beck - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#include "font/text_surface.hpp" - -#include "font/sdl_ttf.hpp" - -#include "sdl/surface.hpp" - -#include "log.hpp" - -#include - -#include -#include - -#ifdef HAVE_FRIBIDI -#include -#endif - -static lg::log_domain log_font("font"); -#define DBG_FT LOG_STREAM(debug, log_font) -#define LOG_FT LOG_STREAM(info, log_font) -#define WRN_FT LOG_STREAM(warn, log_font) -#define ERR_FT LOG_STREAM(err, log_font) - -namespace font { - -#ifdef HAVE_FRIBIDI -void text_surface::bidi_cvt() -{ - char *c_str = const_cast(str_.c_str()); // fribidi forgot const... - FriBidiStrIndex len = str_.length(); - FriBidiChar *bidi_logical = new FriBidiChar[len + 2]; - FriBidiChar *bidi_visual = new FriBidiChar[len + 2]; - char *utf8str = new char[4*len + 1]; //assume worst case here (all 4 Byte characters) - FriBidiCharType base_dir = FRIBIDI_TYPE_ON; - FriBidiStrIndex n; - - - n = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, c_str, len, bidi_logical); - #ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-result" - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - #endif - fribidi_log2vis(bidi_logical, n, &base_dir, bidi_visual, nullptr, nullptr, nullptr); - #ifdef __GNUC__ - #pragma GCC diagnostic pop - #endif - - fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, bidi_visual, n, utf8str); - is_rtl_ = base_dir == FRIBIDI_TYPE_RTL; - str_ = std::string(utf8str); - delete[] bidi_logical; - delete[] bidi_visual; - delete[] utf8str; -} -#endif - -text_surface::text_surface(const std::string& str, int size, - color_t color, int style) - : hash_(0) - , font_size_(size) - , color_(color) - , style_(style) - , w_(-1) - , h_(-1) - , str_(str) - , initialized_(false) - , chunks_() - , surfs_() -#ifdef HAVE_FRIBIDI - , is_rtl_(false) -#endif -{ -#ifdef HAVE_FRIBIDI - bidi_cvt(); -#endif - hash(); -} - -text_surface::text_surface(int size, color_t color, int style) : - hash_(0), - font_size_(size), - color_(color), - style_(style), - w_(-1), - h_(-1), - str_(), - initialized_(false), - chunks_(), - surfs_() -#ifdef HAVE_FRIBIDI - ,is_rtl_(false) -#endif -{ -} - -void text_surface::set_text(const std::string& str) -{ - initialized_ = false; - w_ = -1; - h_ = -1; - str_ = str; -#ifdef HAVE_FRIBIDI - bidi_cvt(); -#endif - hash(); -} - -void text_surface::hash() -{ - unsigned int h = 0; - for(const char c : str_) { - h = ((h << 9) | (h >> (sizeof(int) * 8 - 9))) ^ (c); - } - hash_ = h; -} - -void text_surface::measure() const -{ - w_ = 0; - h_ = 0; - - for(const text_chunk& chunk : chunks_) - { - auto ttfont = sdl_ttf::get_font(font_id(chunk.subset, font_size_, style_)); - if(ttfont == nullptr) { - continue; - } - - int w, h; - TTF_SizeUTF8(ttfont.get(), chunk.text.c_str(), &w, &h); - w_ += w; - h_ = std::max(h_, h); - } -} - -std::size_t text_surface::width() const -{ - if (w_ == -1) { - if(chunks_.empty()) - chunks_ = sdl_ttf::split_text(str_); - measure(); - } - return w_; -} - -std::size_t text_surface::height() const -{ - if (h_ == -1) { - if(chunks_.empty()) - chunks_ = sdl_ttf::split_text(str_); - measure(); - } - return h_; -} - -const std::vector& text_surface::get_surfaces() const -{ - if(initialized_) - return surfs_; - - initialized_ = true; - - // Impose a maximal number of characters for a text line. Do now draw - // any text longer that that, to prevent a SDL buffer overflow - if(width() > max_text_line_width) - return surfs_; - - for(const text_chunk& chunk : chunks_) - { - auto ttfont = sdl_ttf::get_font(font_id(chunk.subset, font_size_, style_)); - - surface s = surface(TTF_RenderUTF8_Blended(ttfont.get(), chunk.text.c_str(), color_.to_sdl())); - if(s) - surfs_.push_back(s); - } - - return surfs_; -} - -bool text_surface::operator==(const text_surface& t) const { - return hash_ == t.hash_ && font_size_ == t.font_size_ - && color_ == t.color_ && style_ == t.style_ && str_ == t.str_; -} - -} // end namespace font diff --git a/src/font/text_surface.hpp b/src/font/text_surface.hpp deleted file mode 100644 index 81bc8a305ba..00000000000 --- a/src/font/text_surface.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by Chris Beck - Part of the Battle for Wesnoth Project https://www.wesnoth.org/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY. - - See the COPYING file for more details. -*/ - -#pragma once - -#include "font_id.hpp" // for text_chunk -#include "color.hpp" - -#include - -#include -#include - -/*** - * Note: This is specific to the SDL_TTF codepath. - */ -class surface; - -namespace font { - -class text_surface -{ -public: - text_surface(const std::string& str, int size, color_t color, int style); - text_surface(int size, color_t color, int style); - void set_text(const std::string& str); - - void measure() const; - std::size_t width() const; - std::size_t height() const; -#ifdef HAVE_FRIBIDI - bool is_rtl() const { return is_rtl_; } // Right-To-Left alignment -#endif - const std::vector& get_surfaces() const; - - bool operator==(const text_surface& t) const; - bool operator!=(const text_surface& t) const { return !operator==(t); } -private: - int hash_; - int font_size_; - color_t color_; - int style_; - mutable int w_, h_; - std::string str_; - mutable bool initialized_; - mutable std::vector chunks_; - mutable std::vector surfs_; -#ifdef HAVE_FRIBIDI - bool is_rtl_; - void bidi_cvt(); -#endif - void hash(); -}; - -} // end namespace font diff --git a/src/gui/widgets/text_box.cpp b/src/gui/widgets/text_box.cpp index eff643fd615..e22c66b298c 100644 --- a/src/gui/widgets/text_box.cpp +++ b/src/gui/widgets/text_box.cpp @@ -16,7 +16,6 @@ #include "gui/widgets/text_box.hpp" -#include "font/sdl_ttf.hpp" #include "gui/core/log.hpp" #include "gui/core/register_widget.hpp" #include "gui/widgets/settings.hpp" diff --git a/src/help/help_impl.hpp b/src/help/help_impl.hpp index 8327a629c41..966d80a4c0e 100644 --- a/src/help/help_impl.hpp +++ b/src/help/help_impl.hpp @@ -31,14 +31,16 @@ #pragma once +#include "color.hpp" #include "exceptions.hpp" // for error -#include "font/sdl_ttf.hpp" // for line_width, relative_size +#include "font/constants.hpp" #include "gettext.hpp" #include #include #include // for list #include #include // for operator<<, stringstream, etc +#include #include // for string, allocator, etc #include // for pair, make_pair #include // for vector, etc diff --git a/src/help/help_text_area.cpp b/src/help/help_text_area.cpp index 4224b4a7d62..d858754770a 100644 --- a/src/help/help_text_area.cpp +++ b/src/help/help_text_area.cpp @@ -18,6 +18,7 @@ #include "game_config.hpp" // for debug #include "font/sdl_ttf_compat.hpp" #include "help/help_impl.hpp" // for parse_error, box_width, etc +#include "lexical_cast.hpp" #include "picture.hpp" // for get_image #include "log.hpp" // for LOG_STREAM, log_domain, etc #include "preferences/general.hpp" // for font_scaled diff --git a/src/help/help_topic_generators.cpp b/src/help/help_topic_generators.cpp index 684be4ffa3b..cd126bc9b17 100644 --- a/src/help/help_topic_generators.cpp +++ b/src/help/help_topic_generators.cpp @@ -16,7 +16,6 @@ #include "help/help_topic_generators.hpp" -#include "font/sdl_ttf.hpp" // for line_width #include "font/sdl_ttf_compat.hpp" #include "game_config.hpp" // for debug, menu_contract, etc #include "preferences/game.hpp" // for encountered_terrains, etc diff --git a/src/show_dialog.cpp b/src/show_dialog.cpp index ba21c00d910..3ec99dee7ef 100644 --- a/src/show_dialog.cpp +++ b/src/show_dialog.cpp @@ -17,7 +17,6 @@ #include "show_dialog.hpp" #include "floating_label.hpp" -#include "font/sdl_ttf.hpp" #include "picture.hpp" #include "gettext.hpp" #include "gui/core/event/handler.hpp" diff --git a/src/widgets/button.cpp b/src/widgets/button.cpp index 1d03e081b91..2ef78461c02 100644 --- a/src/widgets/button.cpp +++ b/src/widgets/button.cpp @@ -17,7 +17,6 @@ #include "widgets/button.hpp" #include "filesystem.hpp" -#include "font/sdl_ttf.hpp" #include "game_config.hpp" #include "game_errors.hpp" #include "picture.hpp" diff --git a/src/widgets/menu.cpp b/src/widgets/menu.cpp index cc331fa14ee..f5aac2c09a0 100644 --- a/src/widgets/menu.cpp +++ b/src/widgets/menu.cpp @@ -17,9 +17,9 @@ #include "widgets/menu.hpp" #include "game_config.hpp" -#include "font/sdl_ttf.hpp" #include "font/standard_colors.hpp" #include "language.hpp" +#include "lexical_cast.hpp" #include "picture.hpp" #include "font/marked-up_text.hpp" #include "font/sdl_ttf_compat.hpp" diff --git a/src/widgets/textbox.cpp b/src/widgets/textbox.cpp index 7e73d15b53e..a3602ae8310 100644 --- a/src/widgets/textbox.cpp +++ b/src/widgets/textbox.cpp @@ -18,7 +18,6 @@ #include "cursor.hpp" #include "desktop/clipboard.hpp" -#include "font/sdl_ttf.hpp" #include "font/sdl_ttf_compat.hpp" #include "log.hpp" #include "sdl/rect.hpp"