The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
text_surface.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2017 by Chris Beck<render787@gmail.com>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "font/text_surface.hpp"
16 
17 #include "font/sdl_ttf.hpp"
18 
19 #include "sdl/surface.hpp"
20 
21 #include "log.hpp"
22 
23 #include <SDL_ttf.h>
24 
25 #include <string>
26 #include <vector>
27 
28 #ifdef HAVE_FRIBIDI
29 #include <fribidi.h>
30 #endif
31 
32 static lg::log_domain log_font("font");
33 #define DBG_FT LOG_STREAM(debug, log_font)
34 #define LOG_FT LOG_STREAM(info, log_font)
35 #define WRN_FT LOG_STREAM(warn, log_font)
36 #define ERR_FT LOG_STREAM(err, log_font)
37 
38 namespace font {
39 
40 #ifdef HAVE_FRIBIDI
41 void text_surface::bidi_cvt()
42 {
43  char *c_str = const_cast<char *>(str_.c_str()); // fribidi forgot const...
44  FriBidiStrIndex len = str_.length();
45  FriBidiChar *bidi_logical = new FriBidiChar[len + 2];
46  FriBidiChar *bidi_visual = new FriBidiChar[len + 2];
47  char *utf8str = new char[4*len + 1]; //assume worst case here (all 4 Byte characters)
48  FriBidiCharType base_dir = FRIBIDI_TYPE_ON;
49  FriBidiStrIndex n;
50 
51 
52  n = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, c_str, len, bidi_logical);
53  #ifdef __GNUC__
54  #pragma GCC diagnostic push
55  #pragma GCC diagnostic ignored "-Wunused-result"
56  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
57  #endif
58  fribidi_log2vis(bidi_logical, n, &base_dir, bidi_visual, nullptr, nullptr, nullptr);
59  #ifdef __GNUC__
60  #pragma GCC diagnostic pop
61  #endif
62 
63  fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, bidi_visual, n, utf8str);
64  is_rtl_ = base_dir == FRIBIDI_TYPE_RTL;
65  str_ = std::string(utf8str);
66  delete[] bidi_logical;
67  delete[] bidi_visual;
68  delete[] utf8str;
69 }
70 #endif
71 
73  color_t color, int style)
74  : hash_(0)
75  , font_size_(size)
76  , color_(color)
77  , style_(style)
78  , w_(-1)
79  , h_(-1)
80  , str_(str)
81  , initialized_(false)
82  , chunks_()
83  , surfs_()
84 #ifdef HAVE_FRIBIDI
85  , is_rtl_(false)
86 #endif
87 {
88 #ifdef HAVE_FRIBIDI
89  bidi_cvt();
90 #endif
91  hash();
92 }
93 
94 text_surface::text_surface(int size, color_t color, int style) :
95  hash_(0),
96  font_size_(size),
97  color_(color),
98  style_(style),
99  w_(-1),
100  h_(-1),
101  str_(),
102  initialized_(false),
103  chunks_(),
104  surfs_()
105 #ifdef HAVE_FRIBIDI
106  ,is_rtl_(false)
107 #endif
108 {
109 }
110 
112 {
113  initialized_ = false;
114  w_ = -1;
115  h_ = -1;
116  str_ = str;
117 #ifdef HAVE_FRIBIDI
118  bidi_cvt();
119 #endif
120  hash();
121 }
122 
124 {
125  unsigned int h = 0;
126  for(const char c : str_) {
127  h = ((h << 9) | (h >> (sizeof(int) * 8 - 9))) ^ (c);
128  }
129  hash_ = h;
130 }
131 
133 {
134  w_ = 0;
135  h_ = 0;
136 
137  for(text_chunk const &chunk : chunks_)
138  {
139  TTF_Font* ttfont = sdl_ttf::get_font(font_id(chunk.subset, font_size_, style_));
140  if(ttfont == nullptr) {
141  continue;
142  }
143 
144  int w, h;
145  TTF_SizeUTF8(ttfont, chunk.text.c_str(), &w, &h);
146  w_ += w;
147  h_ = std::max<int>(h_, h);
148  }
149 }
150 
151 size_t text_surface::width() const
152 {
153  if (w_ == -1) {
154  if(chunks_.empty())
156  measure();
157  }
158  return w_;
159 }
160 
161 size_t text_surface::height() const
162 {
163  if (h_ == -1) {
164  if(chunks_.empty())
166  measure();
167  }
168  return h_;
169 }
170 
171 std::vector<surface> const &text_surface::get_surfaces() const
172 {
173  if(initialized_)
174  return surfs_;
175 
176  initialized_ = true;
177 
178  // Impose a maximal number of characters for a text line. Do now draw
179  // any text longer that that, to prevent a SDL buffer overflow
180  if(width() > max_text_line_width)
181  return surfs_;
182 
183  for(text_chunk const &chunk : chunks_)
184  {
185  TTF_Font* ttfont = sdl_ttf::get_font(font_id(chunk.subset, font_size_, style_));
186 
187  surface s = surface(TTF_RenderUTF8_Blended(ttfont, chunk.text.c_str(), color_.to_sdl()));
188  if(!s.null())
189  surfs_.push_back(s);
190  }
191 
192  return surfs_;
193 }
194 
196  return hash_ == t.hash_ && font_size_ == t.font_size_
197  && color_ == t.color_ && style_ == t.style_ && str_ == t.str_;
198 }
199 
200 } // end namespace font
std::vector< char_t > string
Note: Specific to sdl_ttf.
bool null() const
Definition: surface.hpp:79
std::vector< text_chunk > chunks_
std::vector< surface > const & get_surfaces() const
#define h
size_t height() const
static lg::log_domain log_font("font")
const size_t max_text_line_width
Definition: constants.cpp:32
static std::vector< text_chunk > split_text(const std::string &utf8_text)
Definition: sdl_ttf.cpp:554
text_surface(const std::string &str, int size, color_t color, int style)
void set_text(const std::string &str)
size_t size(const utf8::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
size_t w_
SDL_Color to_sdl() const
Returns the stored color as an color_t object.
Definition: utils.cpp:2404
static map_location::DIRECTION s
size_t width() const
void measure() const
std::vector< surface > surfs_
int w
double t
Definition: astarsearch.cpp:64
Standard logging facilities (interface).
bool operator==(text_surface const &t) const
mock_char c
static map_location::DIRECTION n
static TTF_Font * get_font(font_id)
Definition: sdl_ttf.cpp:207