OpenTTD Source: src/gfx_layout_fallback.cpp Source File

OpenTTD Source 14.1

gfx_layout_fallback.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD 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, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10 #include "stdafx.h"
11
12 #include "gfx_layout_fallback.h"
13 #include "string_func.h"
14 #include "zoom_func.h"
15
16 #include "table/control_codes.h"
17
18 #include "safeguards.h"
19
20 /*** Paragraph layout ***/
38 class FallbackParagraphLayout : public ParagraphLayouter {
39 public:
41 class FallbackVisualRun : public ParagraphLayouter::VisualRun {
42 std::vector<GlyphID> glyphs;
43 std::vector<Point> positions;
44 std::vector<int> glyph_to_char;
45
46 Font *font;
47
48 public:
49 FallbackVisualRun(Font *font, const char32_t *chars, int glyph_count, int char_offset, int x);
50 const Font *GetFont() const override { return this->font; }
51 int GetGlyphCount() const override { return static_cast<int>(this->glyphs.size()); }
52 const std::vector<GlyphID> &GetGlyphs() const override { return this->glyphs; }
53 const std::vector<Point> &GetPositions() const override { return this->positions; }
54 int GetLeading() const override { return this->GetFont()->fc->GetHeight(); }
55 const std::vector<int> &GetGlyphToCharMap() const override { return this->glyph_to_char; }
56 };
57
59 class FallbackLine : public std::vector<FallbackVisualRun>, public ParagraphLayouter::Line {
60 public:
61 int GetLeading() const override;
62 int GetWidth() const override;
63 int CountRuns() const override;
64 const ParagraphLayouter::VisualRun &GetVisualRun(int run) const override;
65
66 int GetInternalCharLength(char32_t) const override { return 1; }
67 };
68
69 const char32_t *buffer_begin;
70 const char32_t *buffer;
71 FontMap &runs;
72
73 FallbackParagraphLayout(char32_t *buffer, int length, FontMap &runs);
74 void Reflow() override;
75 std::unique_ptr<const Line> NextLine(int max_width) override;
76 };
77
85 /* static */ ParagraphLayouter *FallbackParagraphLayoutFactory::GetParagraphLayout(char32_t *buff, char32_t *buff_end, FontMap &fontMapping)
86 {
87 return new FallbackParagraphLayout(buff, buff_end - buff, fontMapping);
88 }
89
97 /* static */ size_t FallbackParagraphLayoutFactory::AppendToBuffer(char32_t *buff, [[maybe_unused]] const char32_t *buffer_last, char32_t c)
98 {
99 assert(buff < buffer_last);
100 *buff = c;
101 return 1;
102 }
103
112 FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const char32_t *chars, int char_count, int char_offset, int x) :
113 font(font)
114 {
115 const bool isbuiltin = font->fc->IsBuiltInFont();
116
117 this->glyphs.reserve(char_count);
118 this->glyph_to_char.reserve(char_count);
119
120 /* Positions contains the location of the begin of each of the glyphs, and the end of the last one. */
121 this->positions.reserve(char_count + 1);
122
123 int advance = x;
124 for (int i = 0; i < char_count; i++) {
125 const GlyphID &glyph_id = this->glyphs.emplace_back(font->fc->MapCharToGlyph(chars[i]));
126 if (isbuiltin) {
127 this->positions.emplace_back(advance, font->fc->GetAscender()); // Apply sprite font's ascender.
128 } else if (chars[i] >= SCC_SPRITE_START && chars[i] <= SCC_SPRITE_END) {
129 this->positions.emplace_back(advance, (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2); // Align sprite font to centre
130 } else {
131 this->positions.emplace_back(advance, 0); // No ascender adjustment.
132 }
133 advance += font->fc->GetGlyphWidth(glyph_id);
134 this->glyph_to_char.push_back(char_offset + i);
135 }
136 /* End-of-run position. */
137 this->positions.emplace_back(advance, 0);
138 }
139
144 int FallbackParagraphLayout::FallbackLine::GetLeading() const
145 {
146 int leading = 0;
147 for (const auto &run : *this) {
148 leading = std::max(leading, run.GetLeading());
149 }
150
151 return leading;
152 }
153
158 int FallbackParagraphLayout::FallbackLine::GetWidth() const
159 {
160 if (this->empty()) return 0;
161
162 /*
163 * The last X position of a run contains is the end of that run.
164 * Since there is no left-to-right support, taking this value of
165 * the last run gives us the end of the line and thus the width.
166 */
167 const auto &run = this->GetVisualRun(this->CountRuns() - 1);
168 return run.GetPositions().back().x;
169 }
170
175 int FallbackParagraphLayout::FallbackLine::CountRuns() const
176 {
177 return (uint)this->size();
178 }
179
184 const ParagraphLayouter::VisualRun &FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const
185 {
186 return this->at(run);
187 }
188
195 FallbackParagraphLayout::FallbackParagraphLayout(char32_t *buffer, [[maybe_unused]] int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs)
196 {
197 assert(runs.rbegin()->first == length);
198 }
199
203 void FallbackParagraphLayout::Reflow()
204 {
205 this->buffer = this->buffer_begin;
206 }
207
213 std::unique_ptr<const ParagraphLayouter::Line> FallbackParagraphLayout::NextLine(int max_width)
214 {
215 /* Simple idea:
216 * - split a line at a newline character, or at a space where we can break a line.
217 * - split for a visual run whenever a new line happens, or the font changes.
218 */
219 if (this->buffer == nullptr) return nullptr;
220
221 std::unique_ptr<FallbackLine> l(new FallbackLine());
222
223 if (*this->buffer == '\0') {
224 /* Only a newline. */
225 this->buffer = nullptr;
226 l->emplace_back(this->runs.begin()->second, this->buffer, 0, 0, 0);
227 return l;
228 }
229
230 int offset = this->buffer - this->buffer_begin;
231 FontMap::iterator iter = this->runs.begin();
232 while (iter->first <= offset) {
233 ++iter;
234 assert(iter != this->runs.end());
235 }
236
237 const FontCache *fc = iter->second->fc;
238 const char32_t *next_run = this->buffer_begin + iter->first;
239
240 const char32_t *begin = this->buffer;
241 const char32_t *last_space = nullptr;
242 const char32_t *last_char;
243 int width = 0;
244 for (;;) {
245 char32_t c = *this->buffer;
246 last_char = this->buffer;
247
248 if (c == '\0') {
249 this->buffer = nullptr;
250 break;
251 }
252
253 if (this->buffer == next_run) {
254 int w = l->GetWidth();
255 l->emplace_back(iter->second, begin, this->buffer - begin, begin - this->buffer_begin, w);
256 ++iter;
257 assert(iter != this->runs.end());
258
259 next_run = this->buffer_begin + iter->first;
260 begin = this->buffer;
261 /* Since a next run is started, there is already some text that
262 * will be shown for this line. However, we do not want to break
263 * this line at the previous space, so pretend we passed a space
264 * just before this next run. */
265 last_space = begin - 1;
266 }
267
268 if (IsWhitespace(c)) last_space = this->buffer;
269
270 if (IsPrintable(c) && !IsTextDirectionChar(c)) {
271 int char_width = GetCharacterWidth(fc->GetSize(), c);
272 width += char_width;
273 if (width > max_width) {
274 /* The string is longer than maximum width so we need to decide
275 * what to do with it. */
276 if (width == char_width) {
277 /* The character is wider than allowed width; don't know
278 * what to do with this case... bail out! */
279 this->buffer = nullptr;
280 return l;
281 }
282
283 if (last_space == nullptr) {
284 /* No space has been found. Just terminate at our current
285 * location. This usually happens for languages that do not
286 * require spaces in strings, like Chinese, Japanese and
287 * Korean. For other languages terminating mid-word might
288 * not be the best, but terminating the whole string instead
289 * of continuing the word at the next line is worse. */
290 last_char = this->buffer;
291 } else {
292 /* A space is found; perfect place to terminate */
293 this->buffer = last_space + 1;
294 last_char = last_space;
295 }
296 break;
297 }
298 }
299
300 this->buffer++;
301 }
302
303 if (l->empty() || last_char - begin > 0) {
304 int w = l->GetWidth();
305 l->emplace_back(iter->second, begin, last_char - begin, begin - this->buffer_begin, w);
306 }
307 return l;
308 }
FontCache::GetSize
FontSize GetSize() const
Get the FontSize of the font.
Definition: fontcache.h:43
Font::fc
FontCache * fc
The font we are using.
Definition: gfx_layout.h:77
FontCache::GetHeight
int GetHeight() const
Get the height of the font.
Definition: fontcache.h:49
FallbackParagraphLayout::FallbackParagraphLayout
FallbackParagraphLayout(char32_t *buffer, int length, FontMap &runs)
Create a new paragraph layouter.
Definition: gfx_layout_fallback.cpp:195
GetCharacterWidth
byte GetCharacterWidth(FontSize size, char32_t key)
Return width of character glyph.
Definition: gfx.cpp:1246
zoom_func.h
FontCache::GetAscender
int GetAscender() const
Get the ascender value of the font.
Definition: fontcache.h:55
FallbackParagraphLayout::runs
FontMap & runs
The fonts we have to use for this paragraph.
Definition: gfx_layout_fallback.cpp:71
ParagraphLayouter
Interface to glue fallback and normal layouter into one.
Definition: gfx_layout.h:89
FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun
FallbackVisualRun(Font *font, const char32_t *chars, int glyph_count, int char_offset, int x)
Create the visual run.
Definition: gfx_layout_fallback.cpp:112
control_codes.h
ParagraphLayouter::Line
A single line worth of VisualRuns.
Definition: gfx_layout.h:106
FontCache::IsBuiltInFont
virtual bool IsBuiltInFont()=0
Is this a built-in sprite font?
FallbackParagraphLayout::FallbackLine::GetWidth
int GetWidth() const override
Get the width of this line.
Definition: gfx_layout_fallback.cpp:158
FallbackParagraphLayout::Reflow
void Reflow() override
Reset the position to the start of the paragraph.
Definition: gfx_layout_fallback.cpp:203
FallbackParagraphLayout::FallbackVisualRun
Visual run contains data about the bit of text with the same font.
Definition: gfx_layout_fallback.cpp:41
gfx_layout_fallback.h
FallbackParagraphLayout::FallbackVisualRun::glyphs
std::vector< GlyphID > glyphs
The glyphs we're drawing.
Definition: gfx_layout_fallback.cpp:42
IsTextDirectionChar
bool IsTextDirectionChar(char32_t c)
Is the given character a text direction character.
Definition: string_func.h:216
safeguards.h
FallbackParagraphLayout::FallbackLine::CountRuns
int CountRuns() const override
Get the number of runs in this line.
Definition: gfx_layout_fallback.cpp:175
GlyphID
uint32_t GlyphID
Glyphs are characters from a font.
Definition: fontcache.h:17
stdafx.h
FallbackParagraphLayout::FallbackLine::GetVisualRun
const ParagraphLayouter::VisualRun & GetVisualRun(int run) const override
Get a specific visual run.
Definition: gfx_layout_fallback.cpp:184
FontCache::GetGlyphWidth
virtual uint GetGlyphWidth(GlyphID key)=0
Get the width of the glyph with the given key.
FallbackParagraphLayout::FallbackVisualRun::glyph_to_char
std::vector< int > glyph_to_char
The char index of the glyphs.
Definition: gfx_layout_fallback.cpp:44
FallbackParagraphLayout::FallbackVisualRun::positions
std::vector< Point > positions
The positions of the glyphs.
Definition: gfx_layout_fallback.cpp:43
FallbackParagraphLayout
Class handling the splitting of a paragraph of text into lines and visual runs.
Definition: gfx_layout_fallback.cpp:38
Font
Container with information about a font.
Definition: gfx_layout.h:75
ParagraphLayouter::VisualRun
Visual run contains data about the bit of text with the same font.
Definition: gfx_layout.h:94
FallbackParagraphLayout::buffer_begin
const char32_t * buffer_begin
Begin of the buffer.
Definition: gfx_layout_fallback.cpp:69
FallbackParagraphLayoutFactory::AppendToBuffer
static size_t AppendToBuffer(char32_t *buff, const char32_t *buffer_last, char32_t c)
Append a wide character to the internal buffer.
Definition: gfx_layout_fallback.cpp:97
string_func.h
FontCache::MapCharToGlyph
virtual GlyphID MapCharToGlyph(char32_t key, bool fallback=true)=0
Map a character into a glyph.
FontCache
Font cache for basic fonts.
Definition: fontcache.h:21
FallbackParagraphLayout::FallbackLine::GetLeading
int GetLeading() const override
Get the height of the line.
Definition: gfx_layout_fallback.cpp:144
FallbackParagraphLayoutFactory::GetParagraphLayout
static ParagraphLayouter * GetParagraphLayout(char32_t *buff, char32_t *buff_end, FontMap &fontMapping)
Get the actual ParagraphLayout for the given buffer.
Definition: gfx_layout_fallback.cpp:85
ScaleSpriteTrad
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition: zoom_func.h:107
IsWhitespace
bool IsWhitespace(char32_t c)
Check whether UNICODE character is whitespace or not, i.e.
Definition: string_func.h:248
FallbackParagraphLayout::FallbackLine
A single line worth of VisualRuns.
Definition: gfx_layout_fallback.cpp:59
FallbackParagraphLayout::buffer
const char32_t * buffer
The current location in the buffer.
Definition: gfx_layout_fallback.cpp:70
FontMap
std::map< int, Font * > FontMap
Mapping from index to font.
Definition: gfx_layout.h:84
FallbackParagraphLayout::FallbackVisualRun::font
Font * font
The font used to layout these.
Definition: gfx_layout_fallback.cpp:46
FallbackParagraphLayout::NextLine
std::unique_ptr< const Line > NextLine(int max_width) override
Construct a new line with a maximum width.
Definition: gfx_layout_fallback.cpp:213