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.
This commit is contained in:
parent
8a9e861eb3
commit
2dfdc0061d
22 changed files with 6 additions and 1146 deletions
|
@ -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)
|
||||
|
|
|
@ -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"])
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
/***
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
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 <string>
|
||||
#include <tuple>
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
/***
|
||||
* 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
|
|
@ -1,566 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
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 <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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<TTF_Font> font;
|
||||
int style;
|
||||
};
|
||||
static std::map<font_id, ttf_record> font_table;
|
||||
|
||||
// The indices in these vectors correspond to the font_id.subset values in font_table.
|
||||
static std::vector<std::string> font_names;
|
||||
static std::vector<std::string> bold_names;
|
||||
static std::vector<std::string> italic_names;
|
||||
|
||||
struct family_record
|
||||
{
|
||||
std::shared_ptr<const TTF_Font> 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_record> 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<std::string, SDL_Rect> line_size_cache_map;
|
||||
|
||||
// map of styles -> sizes -> cache
|
||||
static std::map<int, std::map<int, line_size_cache_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<TTF_Font> 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<TTF_Font, font_deleter> 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<TTF_Font> 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<std::string> lines = utils::split(text, '\n', 0);
|
||||
std::vector<std::vector<surface>> 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<surface>&res = cached_surf.get_surfaces();
|
||||
|
||||
if (!res.empty()) {
|
||||
surfaces.push_back(res);
|
||||
width = std::max<std::size_t>(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<surface>>::iterator i = surfaces.begin(),
|
||||
i_end = surfaces.end(); i != i_end; ++i) {
|
||||
std::size_t xpos = 0;
|
||||
height = 0;
|
||||
|
||||
for(std::vector<surface>::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<std::size_t>((*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_ptr<TTF_Font>s' 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<subset_descriptor>& 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<family_record> 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<text_chunk> sdl_ttf::split_text(const std::string& utf8_text)
|
||||
{
|
||||
std::vector<text_chunk> 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
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
|
||||
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 <memory>
|
||||
#include <string>
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
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<TTF_Font> 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<subset_descriptor>& fontlist);
|
||||
|
||||
// Split a utf8 string into text_chunks
|
||||
static std::vector<text_chunk> split_text(const std::string& utf8_text);
|
||||
};
|
||||
|
||||
} // end namespace font
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
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 <algorithm>
|
||||
|
||||
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
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
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 <list>
|
||||
|
||||
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
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
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 <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAVE_FRIBIDI
|
||||
#include <fribidi.h>
|
||||
#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<char *>(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<int>(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<surface>& 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
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
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 <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/***
|
||||
* 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<surface>& 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<text_chunk> chunks_;
|
||||
mutable std::vector<surface> surfs_;
|
||||
#ifdef HAVE_FRIBIDI
|
||||
bool is_rtl_;
|
||||
void bidi_cvt();
|
||||
#endif
|
||||
void hash();
|
||||
};
|
||||
|
||||
} // end namespace font
|
|
@ -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"
|
||||
|
|
|
@ -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 <optional>
|
||||
#include <cstring>
|
||||
#include <list> // for list
|
||||
#include <memory>
|
||||
#include <ostream> // for operator<<, stringstream, etc
|
||||
#include <sstream>
|
||||
#include <string> // for string, allocator, etc
|
||||
#include <utility> // for pair, make_pair
|
||||
#include <vector> // for vector, etc
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue