Removed the SDL_TTF and GUI1 font rendering API and associated functions
This removes all functions related to: * GUI1 font formatting * GUI1 font rendering * Manual text surface size calculations * The font description interface. While it wasn't exclusive to the TTF rendering system, it was unused by Pango/Cairo rendering. A huge chunk of the help browser code was commented out since we don't have font::line_width anymore. Likewise, a hack was added to the GUI2 text box since we don't have have get_max_height anymore. font::is_cjk_char was retained (as well as some related helpers) since they might be useful later. I'll leave it to someone else to update the CMake/Scons files to remove TTF as a build dependency.
This commit is contained in:
parent
ab67b402d1
commit
c198be1fa8
25 changed files with 27 additions and 1768 deletions
File diff suppressed because one or more lines are too long
|
@ -177,7 +177,7 @@
|
|||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
</ProjectReference>
|
||||
<Link>
|
||||
<AdditionalDependencies>SDL2main.lib;SDL2.lib;SDL2_image.lib;SDL2_ttf.lib;SDL2_mixer.lib;libcrypto.lib;cairo.lib;winmm.lib;ws2_32.lib;pango-1.0.lib;pangocairo-1.0.lib;gobject-2.0.lib;glib-2.0.lib;libpng.lib;$(IntDir)liblua.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>SDL2main.lib;SDL2.lib;SDL2_image.lib;SDL2_mixer.lib;libcrypto.lib;cairo.lib;winmm.lib;ws2_32.lib;pango-1.0.lib;pangocairo-1.0.lib;gobject-2.0.lib;glib-2.0.lib;libpng.lib;$(IntDir)liblua.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\external\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -1010,13 +1010,6 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\sdl_ttf.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\standard_colors.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
|
@ -1031,13 +1024,6 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text_cache.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text_formatting.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
|
@ -1045,13 +1031,6 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text_surface.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Font\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\format_time_summary.cpp" />
|
||||
<ClCompile Include="..\..\src\formula\callable_objects.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Formula\</ObjectFileName>
|
||||
|
@ -3597,20 +3576,15 @@
|
|||
<ClInclude Include="..\..\src\floating_label.hpp" />
|
||||
<ClInclude Include="..\..\src\font\error.hpp" />
|
||||
<ClInclude Include="..\..\src\font\font_config.hpp" />
|
||||
<ClInclude Include="..\..\src\font\font_description.hpp" />
|
||||
<ClInclude Include="..\..\src\font\font_id.hpp" />
|
||||
<ClInclude Include="..\..\src\font\font_options.hpp" />
|
||||
<ClInclude Include="..\..\src\font\marked-up_text.hpp" />
|
||||
<ClInclude Include="..\..\src\font\pango\escape.hpp" />
|
||||
<ClInclude Include="..\..\src\font\pango\font.hpp" />
|
||||
<ClInclude Include="..\..\src\font\pango\hyperlink.hpp" />
|
||||
<ClInclude Include="..\..\src\font\pango\stream_ops.hpp" />
|
||||
<ClInclude Include="..\..\src\font\sdl_ttf.hpp" />
|
||||
<ClInclude Include="..\..\src\font\standard_colors.hpp" />
|
||||
<ClInclude Include="..\..\src\font\text.hpp" />
|
||||
<ClInclude Include="..\..\src\font\text_cache.hpp" />
|
||||
<ClInclude Include="..\..\src\font\text_formatting.hpp" />
|
||||
<ClInclude Include="..\..\src\font\text_surface.hpp" />
|
||||
<ClInclude Include="..\..\src\formatter.hpp" />
|
||||
<ClInclude Include="..\..\src\format_time_summary.hpp" />
|
||||
<ClInclude Include="..\..\src\formula\callable.hpp" />
|
||||
|
|
|
@ -1503,24 +1503,15 @@
|
|||
<ClCompile Include="..\..\src\font\marked-up_text.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\sdl_ttf.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\standard_colors.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text_cache.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text_formatting.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\font\text_surface.cpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ogl\context.cpp">
|
||||
<Filter>OGL</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2934,36 +2925,21 @@
|
|||
<ClInclude Include="..\..\src\font\font_config.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\font_description.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\font_id.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\font_options.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\marked-up_text.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\sdl_ttf.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\standard_colors.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\text.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\text_cache.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\text_formatting.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\text_surface.hpp">
|
||||
<Filter>Font</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\font\pango\escape.hpp">
|
||||
<Filter>Font\Pango</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -8,12 +8,9 @@ events.cpp
|
|||
floating_label.cpp
|
||||
font/font_config.cpp
|
||||
font/marked-up_text.cpp
|
||||
font/sdl_ttf.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
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
#include <SDL_mixer.h>
|
||||
#include <SDL_ttf.h>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
|
@ -206,20 +205,6 @@ version_table_manager::version_table_manager()
|
|||
|
||||
names[LIB_SDL_MIXER] = "SDL_mixer";
|
||||
|
||||
//
|
||||
// SDL_ttf
|
||||
//
|
||||
|
||||
SDL_TTF_VERSION(&sdl_version);
|
||||
compiled[LIB_SDL_TTF] = format_version(sdl_version);
|
||||
|
||||
sdl_rt_version = TTF_Linked_Version();
|
||||
if(sdl_rt_version) {
|
||||
linked[LIB_SDL_TTF] = format_version(*sdl_rt_version);
|
||||
}
|
||||
|
||||
names[LIB_SDL_TTF] = "SDL_ttf";
|
||||
|
||||
//
|
||||
// Boost
|
||||
//
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "fake_unit_manager.hpp"
|
||||
#include "floating_label.hpp"
|
||||
#include "font/marked-up_text.hpp"
|
||||
#include "font/sdl_ttf.hpp"
|
||||
#include "font/text.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/dialogs/loading_screen.hpp"
|
||||
|
|
|
@ -103,7 +103,7 @@ void display_chat_manager::add_chat_message(const time_t& time, const std::strin
|
|||
try {
|
||||
// We've had a joker who send an invalid utf-8 message to crash clients
|
||||
// so now catch the exception and ignore the message.
|
||||
msg = my_disp_.video().faked() ? "" : font::word_wrap_text(msg,font::SIZE_NORMAL,my_disp_.map_outside_area().w*3/4);
|
||||
//msg = my_disp_.video().faked() ? "" : font::word_wrap_text(msg,font::SIZE_NORMAL,my_disp_.map_outside_area().w*3/4);
|
||||
} catch (utf8::invalid_utf8_exception&) {
|
||||
ERR_NG << "Invalid utf-8 found, chat message is ignored." << std::endl;
|
||||
return;
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
if (state_.selected) {
|
||||
sdl::draw_rectangle(location(), {255, 255, 255, 255});
|
||||
}
|
||||
font::draw_text(&video(), location(), 16, font::NORMAL_COLOR, desc_.empty() ? id_ : desc_, location().x + 2, location().y, 0);
|
||||
//font::draw_text(&video(), location(), 16, font::NORMAL_COLOR, desc_.empty() ? id_ : desc_, location().x + 2, location().y, 0);
|
||||
}
|
||||
|
||||
//TODO move to widget
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
*/
|
||||
|
||||
#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"
|
||||
|
@ -83,20 +81,6 @@ bool check_font_file(std::string name) {
|
|||
|
||||
namespace
|
||||
{
|
||||
bool add_font_to_fontlist(const config &fonts_config,
|
||||
std::vector<font::subset_descriptor>& fontlist, const std::string& name)
|
||||
{
|
||||
const config &font = fonts_config.find_child("font", "name", name);
|
||||
if (!font) {
|
||||
return false;
|
||||
}
|
||||
//DBG_FT << "Adding a font record: " << font.debug() << std::endl;
|
||||
|
||||
fontlist.push_back(font::subset_descriptor(font));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_WIN32_FONT
|
||||
bool is_valid_font_file(const std::string& file)
|
||||
{
|
||||
|
@ -149,17 +133,6 @@ bool load_font_config()
|
|||
if (!fonts_config)
|
||||
return false;
|
||||
|
||||
std::set<std::string> known_fonts;
|
||||
for (const config &font : fonts_config.child_range("font")) {
|
||||
known_fonts.insert(font["name"]);
|
||||
if (font.has_attribute("bold_name")) {
|
||||
known_fonts.insert(font["bold_name"]);
|
||||
}
|
||||
if (font.has_attribute("italic_name")) {
|
||||
known_fonts.insert(font["italic_name"]);
|
||||
}
|
||||
}
|
||||
|
||||
family_order_sans = fonts_config["family_order"];
|
||||
family_order_mono = fonts_config["family_order_monospace"];
|
||||
family_order_light = fonts_config["family_order_light"];
|
||||
|
@ -180,21 +153,6 @@ bool load_font_config()
|
|||
family_order_script = family_order_sans;
|
||||
}
|
||||
|
||||
std::vector<font::subset_descriptor> fontlist;
|
||||
|
||||
for(auto font : utils::split(fonts_config["order"])) {
|
||||
add_font_to_fontlist(fonts_config, fontlist, font);
|
||||
known_fonts.erase(font);
|
||||
}
|
||||
|
||||
for(auto kfont : known_fonts) {
|
||||
add_font_to_fontlist(fonts_config, fontlist, kfont);
|
||||
}
|
||||
|
||||
if(fontlist.empty())
|
||||
return false;
|
||||
|
||||
sdl_ttf::set_font_list(fontlist);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
|
||||
#include "font_options.hpp"
|
||||
#include "sdl_ttf.hpp"
|
||||
|
||||
class t_string;
|
||||
|
||||
|
@ -43,9 +42,6 @@ struct manager {
|
|||
manager & operator = (const manager &) = delete;
|
||||
|
||||
private:
|
||||
|
||||
/** Initialize sdl_ttf concurrent with font::manager lifetime */
|
||||
sdl_ttf sdl_ttf_initializer_;
|
||||
};
|
||||
|
||||
/***
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2015 - 2018 by Chris Beck<render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://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 "config.hpp"
|
||||
#include "lexical_cast.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace font {
|
||||
|
||||
// structure used to describe a font, and the subset of the Unicode character
|
||||
// set it covers.
|
||||
//
|
||||
// used by font_config interface (not specific to sdl_ttf or pango)
|
||||
struct subset_descriptor
|
||||
{
|
||||
subset_descriptor()
|
||||
: name()
|
||||
, bold_name()
|
||||
, italic_name()
|
||||
, present_codepoints()
|
||||
{
|
||||
}
|
||||
|
||||
explicit subset_descriptor(const config & font)
|
||||
: name(font["name"].str())
|
||||
, bold_name()
|
||||
, italic_name()
|
||||
, present_codepoints()
|
||||
{
|
||||
if (font.has_attribute("bold_name")) {
|
||||
bold_name = font["bold_name"].str();
|
||||
}
|
||||
|
||||
if (font.has_attribute("italic_name")) {
|
||||
italic_name = font["italic_name"].str();
|
||||
}
|
||||
|
||||
std::vector<std::string> ranges = utils::split(font["codepoints"]);
|
||||
|
||||
for (const std::string & i : ranges) {
|
||||
std::vector<std::string> r = utils::split(i, '-');
|
||||
if(r.size() == 1) {
|
||||
std::size_t r1 = lexical_cast_default<std::size_t>(r[0], 0);
|
||||
present_codepoints.emplace_back(r1, r1);
|
||||
} else if(r.size() == 2) {
|
||||
std::size_t r1 = lexical_cast_default<std::size_t>(r[0], 0);
|
||||
std::size_t r2 = lexical_cast_default<std::size_t>(r[1], 0);
|
||||
|
||||
present_codepoints.emplace_back(r1, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
boost::optional<std::string> bold_name; //If we are using another font for styled characters in this font, rather than SDL TTF method
|
||||
boost::optional<std::string> italic_name;
|
||||
|
||||
typedef std::pair<int, int> range;
|
||||
std::vector<range> present_codepoints;
|
||||
};
|
||||
|
||||
} // end namespace font
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://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 <SDL_ttf.h>
|
||||
|
||||
/***
|
||||
* Note: This is specific to SDL_TTF code path
|
||||
*/
|
||||
|
||||
namespace font {
|
||||
|
||||
// Signed int. Negative values mean "no subset".
|
||||
typedef int subset_id;
|
||||
|
||||
// Used as a key in the font table, which caches the get_font results.
|
||||
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;
|
||||
int style;
|
||||
};
|
||||
|
||||
/***
|
||||
* Text chunk is used by text_surfaces and these are cached sometimes.
|
||||
*/
|
||||
struct text_chunk
|
||||
{
|
||||
text_chunk(subset_id subset)
|
||||
: subset(subset)
|
||||
, 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
|
|
@ -18,212 +18,10 @@
|
|||
* E.g. "@Victory" will be shown in green.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||
|
||||
#include "font/sdl_ttf.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "font/marked-up_text.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
#include "sdl/surface.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "serialization/unicode.hpp"
|
||||
#include "video.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "preferences/general.hpp"
|
||||
|
||||
namespace font {
|
||||
|
||||
// NOTE: if you add more markup characters below, you'll need to update
|
||||
// the list in campaign_server.cpp (illegal_markup_chars) to blacklist
|
||||
// them for add-on names and titles.
|
||||
|
||||
const char LARGE_TEXT='*', SMALL_TEXT='`',
|
||||
BOLD_TEXT='~', NORMAL_TEXT='{',
|
||||
NULL_MARKUP='^',
|
||||
BLACK_TEXT='}', GRAY_TEXT='|',
|
||||
GOOD_TEXT='@', BAD_TEXT='#',
|
||||
GREEN_TEXT='@', RED_TEXT='#',
|
||||
COLOR_TEXT='<', IMAGE='&';
|
||||
|
||||
std::string::const_iterator parse_markup(std::string::const_iterator i1,
|
||||
std::string::const_iterator i2,
|
||||
int* font_size,
|
||||
color_t* color, int* style)
|
||||
namespace font
|
||||
{
|
||||
while(i1 != i2) {
|
||||
switch(*i1) {
|
||||
case '\\':
|
||||
// This must either be a quoted special character or a
|
||||
// quoted backslash - either way, remove leading backslash
|
||||
break;
|
||||
case BAD_TEXT:
|
||||
if (color) *color = BAD_COLOR;
|
||||
break;
|
||||
case GOOD_TEXT:
|
||||
if (color) *color = GOOD_COLOR;
|
||||
break;
|
||||
case NORMAL_TEXT:
|
||||
if (color) *color = NORMAL_COLOR;
|
||||
break;
|
||||
case BLACK_TEXT:
|
||||
if (color) *color = BLACK_COLOR;
|
||||
break;
|
||||
case GRAY_TEXT:
|
||||
if (color) *color = GRAY_COLOR;
|
||||
break;
|
||||
case LARGE_TEXT:
|
||||
if (font_size) *font_size += 2;
|
||||
break;
|
||||
case SMALL_TEXT:
|
||||
if (font_size) *font_size -= 2;
|
||||
break;
|
||||
case BOLD_TEXT:
|
||||
if (style) *style |= TTF_STYLE_BOLD;
|
||||
break;
|
||||
case NULL_MARKUP:
|
||||
return i1+1;
|
||||
case COLOR_TEXT:
|
||||
{
|
||||
std::string::const_iterator start = i1;
|
||||
// Very primitive parsing for rgb value
|
||||
// should look like <213,14,151>
|
||||
++i1;
|
||||
uint8_t red=0, green=0, blue=0, temp=0;
|
||||
while (i1 != i2 && *i1 >= '0' && *i1<='9') {
|
||||
temp*=10;
|
||||
temp += lexical_cast<int, char>(*i1);
|
||||
++i1;
|
||||
}
|
||||
red=temp;
|
||||
temp=0;
|
||||
if (i1 != i2 && ',' == (*i1)) {
|
||||
++i1;
|
||||
while(i1 != i2 && *i1 >= '0' && *i1<='9'){
|
||||
temp*=10;
|
||||
temp += lexical_cast<int, char>(*i1);
|
||||
++i1;
|
||||
}
|
||||
green=temp;
|
||||
temp=0;
|
||||
}
|
||||
if (i1 != i2 && ',' == (*i1)) {
|
||||
++i1;
|
||||
while(i1 != i2 && *i1 >= '0' && *i1<='9'){
|
||||
temp*=10;
|
||||
temp += lexical_cast<int, char>(*i1);
|
||||
++i1;
|
||||
}
|
||||
}
|
||||
blue=temp;
|
||||
if (i1 != i2 && '>' == (*i1)) {
|
||||
color_t temp_color {red, green, blue, 0};
|
||||
if (color) *color = temp_color;
|
||||
} else {
|
||||
// stop parsing and do not consume any chars
|
||||
return start;
|
||||
}
|
||||
if (i1 == i2) return i1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return i1;
|
||||
}
|
||||
++i1;
|
||||
}
|
||||
return i1;
|
||||
}
|
||||
|
||||
std::string del_tags(const std::string& text){
|
||||
std::vector<std::string> lines = utils::split(text, '\n', 0);
|
||||
std::vector<std::string>::iterator line;
|
||||
for(line = lines.begin(); line != lines.end(); ++line) {
|
||||
std::string::const_iterator i1 = line->begin(),
|
||||
i2 = line->end();
|
||||
*line = std::string(parse_markup(i1,i2,nullptr,nullptr,nullptr),i2);
|
||||
}
|
||||
return utils::join(lines, "\n");
|
||||
}
|
||||
|
||||
SDL_Rect text_area(const std::string& text, int size, int style)
|
||||
{
|
||||
const SDL_Rect area {0,0,10000,10000};
|
||||
return draw_text(nullptr, area, size, font::NORMAL_COLOR, text, 0, 0, false, style);
|
||||
}
|
||||
|
||||
SDL_Rect draw_text(surface& dst, const SDL_Rect& area, int size,
|
||||
const color_t& color, const std::string& txt,
|
||||
int x, int y, bool use_tooltips, int style)
|
||||
{
|
||||
// Make sure there's always at least a space,
|
||||
// so we can ensure that we can return a rectangle for height
|
||||
static const std::string blank_text(" ");
|
||||
const std::string& text = txt.empty() ? blank_text : txt;
|
||||
|
||||
SDL_Rect res;
|
||||
res.x = x;
|
||||
res.y = y;
|
||||
res.w = 0;
|
||||
res.h = 0;
|
||||
|
||||
std::string::const_iterator i1 = text.begin();
|
||||
std::string::const_iterator i2 = std::find(i1,text.end(),'\n');
|
||||
for(;;) {
|
||||
color_t col = color;
|
||||
int sz = size;
|
||||
int text_style = style;
|
||||
|
||||
i1 = parse_markup(i1,i2,&sz,&col,&text_style);
|
||||
|
||||
if(i1 != i2) {
|
||||
std::string new_string = utils::unescape(std::string(i1, i2));
|
||||
|
||||
const SDL_Rect rect = draw_text_line(dst, area, sz, col, new_string, x, y, use_tooltips, text_style);
|
||||
if(rect.w > res.w) {
|
||||
res.w = rect.w;
|
||||
}
|
||||
|
||||
res.h += rect.h;
|
||||
y += rect.h;
|
||||
}
|
||||
|
||||
if(i2 == text.end()) {
|
||||
break;
|
||||
}
|
||||
|
||||
i1 = i2+1;
|
||||
i2 = std::find(i1,text.end(),'\n');
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
SDL_Rect draw_text(CVideo* /*gui*/, const SDL_Rect& area, int size,
|
||||
const color_t& color, const std::string& txt,
|
||||
int x, int y, bool use_tooltips, int style)
|
||||
{
|
||||
surface null_surf = surface(nullptr);
|
||||
|
||||
return draw_text(null_surf, area, size, color, txt, x, y, use_tooltips, style);
|
||||
}
|
||||
|
||||
bool is_format_char(char c)
|
||||
{
|
||||
switch(c) {
|
||||
case LARGE_TEXT:
|
||||
case SMALL_TEXT:
|
||||
case GOOD_TEXT:
|
||||
case BAD_TEXT:
|
||||
case NORMAL_TEXT:
|
||||
case BLACK_TEXT:
|
||||
case GRAY_TEXT:
|
||||
case BOLD_TEXT:
|
||||
case NULL_MARKUP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_cjk_char(const ucs4::char_t ch)
|
||||
{
|
||||
/**
|
||||
|
@ -278,30 +76,6 @@ bool is_cjk_char(const ucs4::char_t ch)
|
|||
//Halfwidth and Fullwidth Forms
|
||||
(ch >= 0xff00 && ch < 0xffef);
|
||||
}
|
||||
static void cut_word(std::string& line, std::string& word, int font_size, int style, int max_width)
|
||||
{
|
||||
std::string tmp = line;
|
||||
utf8::iterator tc(word);
|
||||
bool first = true;
|
||||
font_size = preferences::font_scaled(font_size);
|
||||
|
||||
for(;tc != utf8::iterator::end(word); ++tc) {
|
||||
tmp.append(tc.substr().first, tc.substr().second);
|
||||
SDL_Rect tsize = line_size(tmp, font_size, style);
|
||||
if(tsize.w > max_width) {
|
||||
const std::string& w = word;
|
||||
if(line.empty() && first) {
|
||||
line += std::string(w.begin(), tc.substr().second);
|
||||
word = std::string(tc.substr().second, w.end());
|
||||
} else {
|
||||
line += std::string(w.begin(), tc.substr().first);
|
||||
word = std::string(tc.substr().first, w.end());
|
||||
}
|
||||
break;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -396,121 +170,4 @@ inline bool break_after(const ucs4::char_t ch)
|
|||
|
||||
} // end of anon namespace
|
||||
|
||||
std::string word_wrap_text(const std::string& unwrapped_text, int font_size,
|
||||
int max_width, int max_height, int max_lines, bool partial_line)
|
||||
{
|
||||
VALIDATE(max_width > 0, _("The maximum text width is less than 1."));
|
||||
|
||||
utf8::iterator ch(unwrapped_text);
|
||||
std::string current_word;
|
||||
std::string current_line;
|
||||
std::size_t line_width = 0;
|
||||
std::size_t current_height = 0;
|
||||
bool line_break = false;
|
||||
bool first = true;
|
||||
bool start_of_line = true;
|
||||
std::string wrapped_text;
|
||||
std::string format_string;
|
||||
color_t color;
|
||||
int font_sz = font_size;
|
||||
int style = TTF_STYLE_NORMAL;
|
||||
utf8::iterator end = utf8::iterator::end(unwrapped_text);
|
||||
|
||||
while(1) {
|
||||
if(start_of_line) {
|
||||
line_width = 0;
|
||||
format_string.clear();
|
||||
while(ch != end && *ch < static_cast<ucs4::char_t>(0x100)
|
||||
&& is_format_char(*ch) && !ch.next_is_end()) {
|
||||
|
||||
format_string.append(ch.substr().first, ch.substr().second);
|
||||
++ch;
|
||||
}
|
||||
// We need to parse the special format characters
|
||||
// to give the proper font_size and style to line_size()
|
||||
font_sz = font_size;
|
||||
style = TTF_STYLE_NORMAL;
|
||||
parse_markup(format_string.begin(),format_string.end(),&font_sz,&color,&style);
|
||||
current_line.clear();
|
||||
start_of_line = false;
|
||||
}
|
||||
|
||||
// If there is no current word, get one
|
||||
if(current_word.empty() && ch == end) {
|
||||
break;
|
||||
} else if(current_word.empty()) {
|
||||
if(*ch == ' ' || *ch == '\n') {
|
||||
current_word = *ch;
|
||||
++ch;
|
||||
} else {
|
||||
ucs4::char_t previous = 0;
|
||||
for(;ch != utf8::iterator::end(unwrapped_text) &&
|
||||
*ch != ' ' && *ch != '\n'; ++ch) {
|
||||
|
||||
if(!current_word.empty() &&
|
||||
break_before(*ch) &&
|
||||
!no_break_after(previous))
|
||||
break;
|
||||
|
||||
if(!current_word.empty() &&
|
||||
break_after(previous) &&
|
||||
!no_break_before(*ch))
|
||||
break;
|
||||
|
||||
current_word.append(ch.substr().first, ch.substr().second);
|
||||
|
||||
previous = *ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(current_word == "\n") {
|
||||
line_break = true;
|
||||
current_word.clear();
|
||||
start_of_line = true;
|
||||
} else {
|
||||
|
||||
const std::size_t word_width = line_size(current_word, preferences::font_scaled(font_sz), style).w;
|
||||
|
||||
line_width += word_width;
|
||||
|
||||
if(static_cast<long>(line_width) > max_width) {
|
||||
if (!partial_line && static_cast<long>(word_width) > max_width) {
|
||||
cut_word(current_line,
|
||||
current_word, font_sz, style, max_width);
|
||||
}
|
||||
if(current_word == " ")
|
||||
current_word = "";
|
||||
line_break = true;
|
||||
} else {
|
||||
current_line += current_word;
|
||||
current_word = "";
|
||||
}
|
||||
}
|
||||
|
||||
if(line_break || (current_word.empty() && ch == end)) {
|
||||
SDL_Rect size = line_size(current_line, preferences::font_scaled(font_sz), style);
|
||||
if(max_height > 0 && current_height + size.h >= std::size_t(max_height)) {
|
||||
return wrapped_text;
|
||||
}
|
||||
|
||||
if(!first) {
|
||||
wrapped_text += '\n';
|
||||
}
|
||||
|
||||
wrapped_text += format_string + current_line;
|
||||
current_line.clear();
|
||||
line_width = 0;
|
||||
current_height += size.h;
|
||||
line_break = false;
|
||||
first = false;
|
||||
|
||||
if(--max_lines == 0) {
|
||||
return wrapped_text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wrapped_text;
|
||||
}
|
||||
|
||||
} // end namespace font
|
||||
|
|
|
@ -16,73 +16,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "color.hpp"
|
||||
|
||||
class CVideo;
|
||||
class surface;
|
||||
|
||||
#include <string>
|
||||
#include "serialization/unicode_types.hpp"
|
||||
|
||||
#include <SDL_rect.h>
|
||||
|
||||
namespace font {
|
||||
|
||||
/** Standard markups for color, size, font, images. */
|
||||
extern const char LARGE_TEXT, SMALL_TEXT, BOLD_TEXT, NORMAL_TEXT, NULL_MARKUP, BLACK_TEXT, GRAY_TEXT,
|
||||
GOOD_TEXT, BAD_TEXT, GREEN_TEXT, RED_TEXT, COLOR_TEXT, IMAGE;
|
||||
|
||||
/** Parses the markup-tags at the front of a string. */
|
||||
std::string::const_iterator parse_markup(std::string::const_iterator i1,
|
||||
std::string::const_iterator i2,
|
||||
int* font_size,
|
||||
color_t* color, int* style);
|
||||
|
||||
/**
|
||||
* Function to draw text on a surface.
|
||||
*
|
||||
* The text will be clipped to area. If the text runs outside of area
|
||||
* horizontally, an ellipsis will be displayed at the end of it.
|
||||
*
|
||||
* If use_tooltips is true, then text with an ellipsis will have a tooltip
|
||||
* set for it equivalent to the entire contents of the text.
|
||||
*
|
||||
* Some very basic 'markup' will be done on the text:
|
||||
* - any line beginning in # will be displayed in BAD_COLOR (red)
|
||||
* - any line beginning in @ will be displayed in GOOD_COLOR (green)
|
||||
* - any line beginning in + will be displayed with size increased by 2
|
||||
* - any line beginning in - will be displayed with size decreased by 2
|
||||
* - any line beginning with 0x0n will be displayed in the color of side n
|
||||
*
|
||||
* The above special characters can be quoted using a C-style backslash.
|
||||
*
|
||||
* A bounding rectangle of the text is returned. If dst is nullptr, then the
|
||||
* text will not be drawn, and a bounding rectangle only will be returned.
|
||||
*/
|
||||
SDL_Rect draw_text(surface& dst, const SDL_Rect& area, int size,
|
||||
const color_t& color, const std::string& text,
|
||||
int x, int y, bool use_tooltips = false, int style = 0);
|
||||
|
||||
/** wrapper of the previous function, gui can also be nullptr */
|
||||
SDL_Rect draw_text(CVideo* gui, const SDL_Rect& area, int size,
|
||||
const color_t& color, const std::string& text,
|
||||
int x, int y, bool use_tooltips = false, int style = 0);
|
||||
|
||||
|
||||
/** Calculate the size of a text (in pixels) if it were to be drawn. */
|
||||
SDL_Rect text_area(const std::string& text, int size, int style=0);
|
||||
|
||||
/** Copy string, but without tags at the beginning */
|
||||
std::string del_tags(const std::string& text);
|
||||
|
||||
/**
|
||||
* Determine if char is one of the special chars used as markup.
|
||||
*
|
||||
* @retval true Input-char is a markup-char.
|
||||
* @retval false Input-char is a normal char.
|
||||
*/
|
||||
bool is_format_char(char c);
|
||||
|
||||
/**
|
||||
* Determine if a ucs4::char_t is a CJK character
|
||||
*
|
||||
|
@ -91,14 +27,4 @@ bool is_format_char(char c);
|
|||
*/
|
||||
bool is_cjk_char(const ucs4::char_t ch);
|
||||
|
||||
/**
|
||||
* Wrap text.
|
||||
*
|
||||
* - If the text exceeds the specified max width, wrap it on a word basis.
|
||||
* - If this is not possible, e.g. the word is too big to fit, wrap it on a
|
||||
* - char basis.
|
||||
*/
|
||||
std::string word_wrap_text(const std::string& unwrapped_text, int font_size,
|
||||
int max_width, int max_height = -1, int max_lines = -1, bool partial_line = false);
|
||||
|
||||
} // end namespace font
|
||||
|
|
|
@ -1,585 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 - 2018 by Chris Beck<render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://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 "game_config.hpp"
|
||||
#include "log.hpp"
|
||||
#include "font/marked-up_text.hpp"
|
||||
#include "preferences/general.hpp"
|
||||
#include "tooltips.hpp"
|
||||
|
||||
#include "sdl/rect.hpp"
|
||||
#include "sdl/surface.hpp"
|
||||
#include "serialization/unicode.hpp"
|
||||
|
||||
#include <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 {
|
||||
|
||||
/***
|
||||
* Caches used to speed up font rendering
|
||||
*/
|
||||
|
||||
// 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
|
||||
{
|
||||
TTF_Font* font;
|
||||
int style;
|
||||
};
|
||||
|
||||
static std::map<font_id, ttf_record> font_table;
|
||||
static std::vector<std::string> font_names;
|
||||
static std::vector<std::string> bold_names;
|
||||
static std::vector<std::string> italic_names;
|
||||
|
||||
struct char_block_map
|
||||
{
|
||||
char_block_map()
|
||||
: cbmap()
|
||||
{
|
||||
}
|
||||
|
||||
typedef std::pair<int, subset_id> block_t;
|
||||
typedef std::map<int, block_t> cbmap_t;
|
||||
cbmap_t cbmap;
|
||||
/** Associates not-associated parts of a range with a new font. */
|
||||
void insert(int first, int last, subset_id id)
|
||||
{
|
||||
if (first > last) return;
|
||||
cbmap_t::iterator i = cbmap.lower_bound(first);
|
||||
// At this point, either first <= i->first or i is past the end.
|
||||
if (i != cbmap.begin()) {
|
||||
cbmap_t::iterator j = i;
|
||||
--j;
|
||||
if (first <= j->second.first /* prev.last */) {
|
||||
insert(j->second.first + 1, last, id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i != cbmap.end()) {
|
||||
if (/* next.first */ i->first <= last) {
|
||||
insert(first, i->first - 1, id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cbmap.emplace(first, block_t(last, id));
|
||||
}
|
||||
/**
|
||||
* Compresses map by merging consecutive ranges with the same font, even
|
||||
* if there is some unassociated ranges in-between.
|
||||
*/
|
||||
void compress()
|
||||
{
|
||||
LOG_FT << "Font map size before compression: " << cbmap.size() << " ranges\n";
|
||||
cbmap_t::iterator i = cbmap.begin(), e = cbmap.end();
|
||||
while (i != e) {
|
||||
cbmap_t::iterator j = i;
|
||||
++j;
|
||||
if (j == e || i->second.second != j->second.second) {
|
||||
i = j;
|
||||
continue;
|
||||
}
|
||||
i->second.first = j->second.first;
|
||||
cbmap.erase(j);
|
||||
}
|
||||
LOG_FT << "Font map size after compression: " << cbmap.size() << " ranges\n";
|
||||
}
|
||||
subset_id get_id(int ch)
|
||||
{
|
||||
cbmap_t::iterator i = cbmap.upper_bound(ch);
|
||||
// At this point, either ch < i->first or i is past the end.
|
||||
if (i != cbmap.begin()) {
|
||||
--i;
|
||||
if (ch <= i->second.first /* prev.last */)
|
||||
return i->second.second;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
static char_block_map char_blocks;
|
||||
|
||||
//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;
|
||||
|
||||
typedef std::map<std::pair<std::string, int>, TTF_Font*> open_font_cache;
|
||||
open_font_cache open_fonts;
|
||||
|
||||
static TTF_Font* open_font_impl(const std::string & , int);
|
||||
|
||||
// A wrapper which caches the results of open_font_impl.
|
||||
// Note that clear_fonts() is responsible to clean up all of these font pointers,
|
||||
// so to avoid memory leaks fonts should only be opened from this function.
|
||||
static TTF_Font* open_font(const std::string& fname, int size)
|
||||
{
|
||||
const std::pair<std::string, int> key = std::make_pair(fname, size);
|
||||
const open_font_cache::iterator it = open_fonts.find(key);
|
||||
if (it != open_fonts.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
TTF_Font* result = open_font_impl(fname, size);
|
||||
open_fonts.emplace(key, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static TTF_Font* open_font_impl(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);
|
||||
TTF_Font* font = 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 << std::endl;
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
// 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.
|
||||
TTF_Font* sdl_ttf::get_font(font_id id)
|
||||
{
|
||||
const auto it = font_table.find(id);
|
||||
if(it != font_table.end()) {
|
||||
if (it->second.font != nullptr) {
|
||||
// If we found a valid record, use SDL_TTF to add in the difference
|
||||
// between its intrinsic style and the desired style.
|
||||
TTF_SetFontStyle(it->second.font, it->second.style ^ id.style);
|
||||
}
|
||||
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 (TTF_Font* font = open_font(italic_names[id.subset], id.size)) {
|
||||
ttf_record rec {font, TTF_STYLE_ITALIC};
|
||||
font_table.emplace(id, rec);
|
||||
return sdl_ttf::get_font(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Now see if the shipped Bold font is useful and available.
|
||||
if ((id.style & TTF_STYLE_BOLD) && bold_names[id.subset].size()) {
|
||||
if (TTF_Font* font = open_font(bold_names[id.subset], id.size)) {
|
||||
ttf_record rec {font, TTF_STYLE_BOLD};
|
||||
font_table.emplace(id, rec);
|
||||
return sdl_ttf::get_font(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Try just to use the basic version of the font then.
|
||||
if (font_names[id.subset].size()) {
|
||||
if(TTF_Font* font = open_font(font_names[id.subset], id.size)) {
|
||||
ttf_record rec {font, TTF_STYLE_NORMAL};
|
||||
font_table.emplace(id, rec);
|
||||
return sdl_ttf::get_font(id);
|
||||
}
|
||||
}
|
||||
|
||||
// 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, bool use_markup)
|
||||
{
|
||||
// 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;
|
||||
|
||||
std::string::const_iterator after_markup = use_markup ?
|
||||
parse_markup(ln->begin(), ln->end(), &sz, nullptr, &text_style) : ln->begin();
|
||||
text_surface txt_surf(sz, color, text_style);
|
||||
|
||||
if (after_markup == ln->end() && (ln+1 != ln_end || lines.begin()+1 == ln_end)) {
|
||||
// we replace empty line by a space (to have a line height)
|
||||
// except for the last line if we have several
|
||||
txt_surf.set_text(" ");
|
||||
} else if (after_markup == ln->begin()) {
|
||||
// simple case, no markup to skip
|
||||
txt_surf.set_text(*ln);
|
||||
} else {
|
||||
const std::string line(after_markup,ln->end());
|
||||
txt_surf.set_text(line);
|
||||
}
|
||||
|
||||
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(create_compatible_surface(surfaces.front().front(),width,height));
|
||||
if (res.null())
|
||||
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)
|
||||
{
|
||||
// TODO maybe later also to parse markup here, but a lot to check
|
||||
return render_text(str, size, color, style, false);
|
||||
}
|
||||
|
||||
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.null()) {
|
||||
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);
|
||||
|
||||
// for the main current use, we already parsed markup
|
||||
surface surface(render_text(etext,size,color,style,false));
|
||||
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 get_max_height(int size)
|
||||
{
|
||||
// Only returns the maximal size of the first font
|
||||
TTF_Font* const font = sdl_ttf::get_font(font_id(0, size));
|
||||
if(font == nullptr)
|
||||
return 0;
|
||||
return TTF_FontHeight(font);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return text; // Should not happen
|
||||
}
|
||||
|
||||
void cache_mode(CACHE mode)
|
||||
{
|
||||
if(mode == CACHE_LOBBY) {
|
||||
text_cache::resize(1000);
|
||||
} else {
|
||||
text_cache::resize(50);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 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() {
|
||||
for(const auto & i : open_fonts) {
|
||||
TTF_CloseFont(i.second);
|
||||
}
|
||||
|
||||
open_fonts.clear();
|
||||
|
||||
font_table.clear();
|
||||
|
||||
font_names.clear();
|
||||
bold_names.clear();
|
||||
italic_names.clear();
|
||||
|
||||
char_blocks.cbmap.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)
|
||||
{
|
||||
clear_fonts();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
for (const subset_descriptor::range &cp_range : f.present_codepoints) {
|
||||
char_blocks.insert(cp_range.first, cp_range.second, subset);
|
||||
}
|
||||
}
|
||||
char_blocks.compress();
|
||||
|
||||
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.
|
||||
std::vector<text_chunk> sdl_ttf::split_text(const std::string& utf8_text) {
|
||||
text_chunk current_chunk(0);
|
||||
std::vector<text_chunk> chunks;
|
||||
|
||||
if (utf8_text.empty())
|
||||
return chunks;
|
||||
|
||||
try {
|
||||
utf8::iterator ch(utf8_text);
|
||||
int sub = char_blocks.get_id(*ch);
|
||||
if (sub >= 0) current_chunk.subset = sub;
|
||||
for(utf8::iterator end = utf8::iterator::end(utf8_text); ch != end; ++ch)
|
||||
{
|
||||
sub = char_blocks.get_id(*ch);
|
||||
if (sub >= 0 && sub != current_chunk.subset) {
|
||||
chunks.push_back(current_chunk);
|
||||
current_chunk.text.clear();
|
||||
current_chunk.subset = sub;
|
||||
}
|
||||
current_chunk.text.append(ch.substr().first, ch.substr().second);
|
||||
}
|
||||
if (!current_chunk.text.empty()) {
|
||||
chunks.push_back(current_chunk);
|
||||
}
|
||||
}
|
||||
catch(utf8::invalid_utf8_exception&) {
|
||||
WRN_FT << "Invalid UTF-8 string: \"" << utf8_text << "\"" << std::endl;
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
} // end namespace font
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
|
||||
Part of the Battle for Wesnoth Project http://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 <string>
|
||||
|
||||
#include <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);
|
||||
|
||||
// Returns the maximum height of a font, in pixels
|
||||
int get_max_height(int size);
|
||||
|
||||
///
|
||||
/// 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);
|
||||
|
||||
|
||||
enum CACHE { CACHE_LOBBY, CACHE_GAME };
|
||||
void cache_mode(CACHE mode);
|
||||
|
||||
|
||||
|
||||
|
||||
/***
|
||||
* RAII object which initializes and destroys SDL_TTF, and manages caches of open fonts
|
||||
*/
|
||||
struct sdl_ttf {
|
||||
sdl_ttf();
|
||||
~sdl_ttf();
|
||||
|
||||
sdl_ttf(const sdl_ttf &) = delete;
|
||||
sdl_ttf & operator = (const sdl_ttf &) = delete;
|
||||
|
||||
// Load a font
|
||||
static TTF_Font * get_font(font_id);
|
||||
|
||||
// Set the list of fonts
|
||||
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 http://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 http://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 http://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 <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_)
|
||||
{
|
||||
TTF_Font* ttfont = sdl_ttf::get_font(font_id(chunk.subset, font_size_, style_));
|
||||
if(ttfont == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int w, h;
|
||||
TTF_SizeUTF8(ttfont, 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_)
|
||||
{
|
||||
TTF_Font* ttfont = sdl_ttf::get_font(font_id(chunk.subset, font_size_, style_));
|
||||
|
||||
surface s = surface(TTF_RenderUTF8_Blended(ttfont, chunk.text.c_str(), color_.to_sdl()));
|
||||
if(!s.null())
|
||||
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 http://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 <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"
|
||||
|
@ -277,8 +276,9 @@ void text_box::update_offsets()
|
|||
const auto conf = cast_config_to<text_box_definition>();
|
||||
assert(conf);
|
||||
|
||||
// FIXME: This should use pango-cairo code path instead of sdl_ttf code path
|
||||
text_height_ = font::get_max_height(conf->text_font_size);
|
||||
// FIXME: set this to a proper value! It used to get the max glyph height
|
||||
// of a certain font via SDL_TTF.
|
||||
text_height_ = get_height();
|
||||
|
||||
wfl::map_formula_callable variables;
|
||||
variables.add("height", wfl::variant(get_height()));
|
||||
|
|
|
@ -347,12 +347,14 @@ topic_text &topic_text::operator=(topic_generator *g)
|
|||
|
||||
const config& topic_text::parsed_text() const
|
||||
{
|
||||
#if 0
|
||||
if (generator_) {
|
||||
parsed_text_ = parse_text((*generator_)());
|
||||
if (--generator_->count == 0)
|
||||
delete generator_;
|
||||
generator_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
return parsed_text_;
|
||||
}
|
||||
|
||||
|
@ -1327,11 +1329,13 @@ std::vector<std::string> split_in_width(const std::string &s, const int font_siz
|
|||
{
|
||||
std::vector<std::string> res;
|
||||
try {
|
||||
#if 0
|
||||
const std::string& first_line = font::word_wrap_text(s, font_size, width, -1, 1, true);
|
||||
res.push_back(first_line);
|
||||
if(s.size() > first_line.size()) {
|
||||
res.push_back(s.substr(first_line.size()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (utf8::invalid_utf8_exception&)
|
||||
{
|
||||
|
@ -1481,9 +1485,9 @@ unsigned image_width(const std::string &filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void push_tab_pair(std::vector<std::pair<std::string, unsigned int>> &v, const std::string &s)
|
||||
void push_tab_pair(std::vector<std::pair<std::string, unsigned int>> &/*v*/, const std::string &/*s*/)
|
||||
{
|
||||
v.emplace_back(s, font::line_width(s, normal_font_size));
|
||||
//v.emplace_back(s, font::line_width(s, normal_font_size));
|
||||
}
|
||||
|
||||
std::string generate_table(const table_spec &tab, const unsigned int spacing)
|
||||
|
|
|
@ -31,13 +31,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "config.hpp"
|
||||
#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 <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
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "help/help_topic_generators.hpp"
|
||||
|
||||
#include "font/sdl_ttf.hpp" // for line_width
|
||||
#include "game_config.hpp" // for debug, menu_contract, etc
|
||||
#include "preferences/game.hpp" // for encountered_terrains, etc
|
||||
#include "gettext.hpp" // for _, gettext, N_
|
||||
|
@ -218,6 +217,7 @@ std::string terrain_topic_generator::operator()() const {
|
|||
//Typedef to help with formatting list of traits
|
||||
typedef std::pair<std::string, std::string> trait_data;
|
||||
|
||||
#if 0
|
||||
//Helper function for printing a list of trait data
|
||||
static void print_trait_list(std::stringstream & ss, const std::vector<trait_data> & l)
|
||||
{
|
||||
|
@ -229,8 +229,9 @@ static void print_trait_list(std::stringstream & ss, const std::vector<trait_dat
|
|||
ss << ", " << make_link(l[i].first,l[i].second);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
std::string unit_topic_generator::operator()() const {
|
||||
#if 0
|
||||
// Force the lazy loading to build this unit.
|
||||
unit_types.build_unit_type(type_, unit_type::FULL);
|
||||
|
||||
|
@ -788,10 +789,12 @@ std::string unit_topic_generator::operator()() const {
|
|||
WRN_HP << "When building unit help topics, the display object was null and we couldn't get the terrain info we need.\n";
|
||||
}
|
||||
return ss.str();
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
void unit_topic_generator::push_header(std::vector< item > &row, const std::string& name) const {
|
||||
row.emplace_back(bold(name), font::line_width(name, normal_font_size, TTF_STYLE_BOLD));
|
||||
void unit_topic_generator::push_header(std::vector< item > &/*row*/, const std::string& /*name*/) const {
|
||||
//row.emplace_back(bold(name), font::line_width(name, normal_font_size, TTF_STYLE_BOLD));
|
||||
}
|
||||
|
||||
} // end namespace help
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "display.hpp"
|
||||
#include "floating_label.hpp"
|
||||
#include "font/sdl_ttf.hpp"
|
||||
#include "font/constants.hpp"
|
||||
#include "image.hpp"
|
||||
#include "log.hpp"
|
||||
#include "ogl/utils.hpp"
|
||||
|
@ -440,6 +440,7 @@ int CVideo::set_help_string(const std::string& str)
|
|||
|
||||
int size = font::SIZE_LARGE;
|
||||
|
||||
#if 0
|
||||
while(size > 0) {
|
||||
if(font::line_width(str, size) > get_width()) {
|
||||
size--;
|
||||
|
@ -447,6 +448,7 @@ int CVideo::set_help_string(const std::string& str)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const int border = 5;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue