OpenTTD Source: src/gfx_layout.h Source File

OpenTTD Source 15.0-RC2

gfx_layout.h
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#ifndef GFX_LAYOUT_H
11#define GFX_LAYOUT_H
12
13#include "misc/lrucache.hpp"
14#include "fontcache.h"
15#include "gfx_func.h"
16#include "core/math_func.hpp"
17
18#include <string_view>
19
24 struct FontState {
25 FontSize fontsize;
26 TextColour cur_colour;
27 std::vector<TextColour> colour_stack;
28
29 FontState() : fontsize(FS_END), cur_colour(TC_INVALID) {}
30 FontState(TextColour colour, FontSize fontsize) : fontsize(fontsize), cur_colour(colour) {}
31
32 auto operator<=>(const FontState &) const = default;
33
38 inline void SetColour(TextColour c)
39 {
40 assert(((c & TC_COLOUR_MASK) >= TC_BLUE && (c & TC_COLOUR_MASK) <= TC_BLACK) || (c & TC_COLOUR_MASK) == TC_INVALID);
41 assert((c & (TC_COLOUR_MASK | TC_FLAGS_MASK)) == c);
42 if ((this->cur_colour & TC_FORCED) == 0) this->cur_colour = c;
43 }
44
48 inline void PopColour()
49 {
50 if (colour_stack.empty()) return;
51 SetColour(colour_stack.back());
52 colour_stack.pop_back();
53 }
54
58 inline void PushColour()
59 {
60 colour_stack.push_back(this->cur_colour);
61 }
62
67 inline void SetFontSize(FontSize f)
68 {
69 this->fontsize = f;
70 }
71};
72
73 template <typename T> struct std::hash<std::vector<T>> {
74 size_t operator()(const std::vector<T> &vec) const
75 {
76 /* This is not an optimal hash algorithm but in most cases this is empty and therefore the same anyway. */
77 return std::transform_reduce(std::begin(vec), std::end(vec),
78 std::hash<size_t>{}(std::size(vec)),
79 [](const size_t &a, const size_t &b) -> size_t { return a ^ b; },
80 [](const T &x) -> size_t { return std::hash<T>{}(x); });
81 }
82};
83
84 template <> struct std::hash<FontState> {
85 std::size_t operator()(const FontState &state) const noexcept
86 {
87 size_t h1 = std::hash<FontSize>{}(state.fontsize);
88 size_t h2 = std::hash<TextColour>{}(state.cur_colour);
89 size_t h3 = std::hash<std::vector<TextColour>>{}(state.colour_stack);
90 return h1 ^ (h2 << 1) ^ (h3 << 2);
91 }
92};
93
97 class Font {
98public:
99 FontCache *fc;
100 TextColour colour;
101
102 Font(FontSize size, TextColour colour);
103};
104
106 using FontMap = std::vector<std::pair<int, Font *>>;
107
111 class ParagraphLayouter {
112public:
113 virtual ~ParagraphLayouter() = default;
114
116 class Position {
117 public:
118 int16_t left;
119 int16_t right;
120 int16_t top;
121
122 constexpr inline Position(int16_t left, int16_t right, int16_t top) : left(left), right(right), top(top) { }
123
125 constexpr inline Position(const Point &pt) : left(pt.x), right(pt.x), top(pt.y) { }
126 };
127
129 class VisualRun {
130 public:
131 virtual ~VisualRun() = default;
132 virtual const Font *GetFont() const = 0;
133 virtual int GetGlyphCount() const = 0;
134 virtual std::span<const GlyphID> GetGlyphs() const = 0;
135 virtual std::span<const Position> GetPositions() const = 0;
136 virtual int GetLeading() const = 0;
137 virtual std::span<const int> GetGlyphToCharMap() const = 0;
138 };
139
141 class Line {
142 public:
143 virtual ~Line() = default;
144 virtual int GetLeading() const = 0;
145 virtual int GetWidth() const = 0;
146 virtual int CountRuns() const = 0;
147 virtual const VisualRun &GetVisualRun(int run) const = 0;
148 virtual int GetInternalCharLength(char32_t c) const = 0;
149 };
150
151 virtual void Reflow() = 0;
152 virtual std::unique_ptr<const Line> NextLine(int max_width) = 0;
153};
154
160 class Layouter : public std::vector<const ParagraphLayouter::Line *> {
161 std::string_view string;
162
164 struct LineCacheKey {
165 FontState state_before;
166 std::string str;
167 };
168
169 struct LineCacheQuery {
170 const FontState &state_before;
171 std::string_view str;
172 };
173
174 friend struct std::hash<Layouter::LineCacheQuery>;
175 struct LineCacheHash;
176
177 struct LineCacheEqualTo {
178 using is_transparent = void;
179
180 template <typename Tlhs, typename Trhs>
181 bool operator()(const Tlhs &lhs, const Trhs &rhs) const
182 {
183 return lhs.state_before == rhs.state_before && lhs.str == rhs.str;
184 }
185 };
186
187public:
189 struct LineCacheItem {
190 /* Due to the type of data in the buffer differing depending on the Layouter, we need to pass our own deleter routine. */
191 using Buffer = std::unique_ptr<void, void(*)(void *)>;
192 /* Stuff that cannot be freed until the ParagraphLayout is freed */
193 Buffer buffer{nullptr, [](void *){}};
194 FontMap runs;
195
196 FontState state_after;
197 std::unique_ptr<ParagraphLayouter> layout = nullptr;
198
199 std::vector<std::unique_ptr<const ParagraphLayouter::Line>> cached_layout{};
200 int cached_width = 0;
201 };
202private:
203 using LineCache = LRUCache<LineCacheKey, LineCacheItem, LineCacheHash, LineCacheEqualTo>;
204 static std::unique_ptr<LineCache> linecache;
205
206 static LineCacheItem &GetCachedParagraphLayout(std::string_view str, const FontState &state);
207
208 using FontColourMap = std::map<TextColour, std::unique_ptr<Font>>;
209 static FontColourMap fonts[FS_END];
210public:
211 static Font *GetFont(FontSize size, TextColour colour);
212
213 Layouter(std::string_view str, int maxw = INT32_MAX, FontSize fontsize = FS_NORMAL);
214 Dimension GetBounds();
215 ParagraphLayouter::Position GetCharPosition(std::string_view::const_iterator ch) const;
216 ptrdiff_t GetCharAtPosition(int x, size_t line_index) const;
217
218 static void Initialize();
219 static void ResetFontCache(FontSize size);
220 static void ResetLineCache();
221};
222
223 ParagraphLayouter::Position GetCharPosInString(std::string_view str, size_t pos, FontSize start_fontsize = FS_NORMAL);
224ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize = FS_NORMAL);
225
226 template <> struct std::hash<Layouter::LineCacheQuery> {
227 std::size_t operator()(const Layouter::LineCacheQuery &state) const noexcept
228 {
229 size_t h1 = std::hash<std::string_view>{}(state.str);
230 size_t h2 = std::hash<FontState>{}(state.state_before);
231 return h1 ^ (h2 << 1);
232 }
233};
234
235 struct Layouter::LineCacheHash {
236 using is_transparent = void;
237
238 std::size_t operator()(const Layouter::LineCacheKey &query) const { return std::hash<Layouter::LineCacheQuery>{}(LineCacheQuery{query.state_before, query.str}); }
239 std::size_t operator()(const Layouter::LineCacheQuery &query) const { return std::hash<Layouter::LineCacheQuery>{}(query); }
240};
241
242#endif /* GFX_LAYOUT_H */
FontCache
Font cache for basic fonts.
Definition fontcache.h:22
Font
Container with information about a font.
Definition gfx_layout.h:97
Font::fc
FontCache * fc
The font we are using.
Definition gfx_layout.h:99
Font::colour
TextColour colour
The colour this font has to be.
Definition gfx_layout.h:100
LRUCache
Size limited cache with a least recently used eviction strategy.
Definition lrucache.hpp:23
Layouter
The layouter performs all the layout work.
Definition gfx_layout.h:160
Layouter::Initialize
static void Initialize()
Perform initialization of layout engine.
Definition gfx_layout.cpp:356
Layouter::fonts
static FontColourMap fonts[FS_END]
Cache of Font instances.
Definition gfx_layout.h:209
Layouter::GetCharAtPosition
ptrdiff_t GetCharAtPosition(int x, size_t line_index) const
Get the character that is at a pixel position in the first line of the layouted text.
Definition gfx_layout.cpp:303
Layouter::ResetFontCache
static void ResetFontCache(FontSize size)
Reset cached font information.
Definition gfx_layout.cpp:367
Layouter::GetCharPosition
ParagraphLayouter::Position GetCharPosition(std::string_view::const_iterator ch) const
Get the position of a character in the layout.
Definition gfx_layout.cpp:237
Layouter::linecache
static std::unique_ptr< LineCache > linecache
Cache of ParagraphLayout lines.
Definition gfx_layout.h:204
Layouter::GetFont
static Font * GetFont(FontSize size, TextColour colour)
Get a static font instance.
Definition gfx_layout.cpp:344
Layouter::string
std::string_view string
Pointer to the original string.
Definition gfx_layout.h:161
Layouter::ResetLineCache
static void ResetLineCache()
Clear line cache.
Definition gfx_layout.cpp:412
Layouter::GetBounds
Dimension GetBounds()
Get the boundaries of this paragraph.
Definition gfx_layout.cpp:208
Layouter::GetCachedParagraphLayout
static LineCacheItem & GetCachedParagraphLayout(std::string_view str, const FontState &state)
Get reference to cache item.
Definition gfx_layout.cpp:389
ParagraphLayouter::Line
A single line worth of VisualRuns.
Definition gfx_layout.h:141
ParagraphLayouter::Position
Position of a glyph within a VisualRun.
Definition gfx_layout.h:116
ParagraphLayouter::Position::right
int16_t right
Right-most position of glyph.
Definition gfx_layout.h:119
ParagraphLayouter::Position::Position
constexpr Position(const Point &pt)
Conversion from a single point to a Position.
Definition gfx_layout.h:125
ParagraphLayouter::Position::left
int16_t left
Left-most position of glyph.
Definition gfx_layout.h:118
ParagraphLayouter::Position::top
int16_t top
Top-most position of glyph.
Definition gfx_layout.h:120
ParagraphLayouter::VisualRun
Visual run contains data about the bit of text with the same font.
Definition gfx_layout.h:129
ParagraphLayouter
Interface to glue fallback and normal layouter into one.
Definition gfx_layout.h:111
fontcache.h
Functions to read fonts from files and cache them.
gfx_func.h
Functions related to the gfx engine.
GetCharPosInString
ParagraphLayouter::Position GetCharPosInString(std::string_view str, size_t pos, FontSize start_fontsize=FS_NORMAL)
Get the leading corner of a character in a single-line string relative to the start of the string.
Definition gfx_layout.cpp:425
GetCharAtPosition
ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize=FS_NORMAL)
Get the character from a string that is drawn at a specific position.
Definition gfx_layout.cpp:441
FontMap
std::vector< std::pair< int, Font * > > FontMap
Mapping from index to font.
Definition gfx_layout.h:106
FontSize
FontSize
Available font sizes.
Definition gfx_type.h:248
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
TextColour
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
TC_FORCED
@ TC_FORCED
Ignore colour changes from strings.
Definition gfx_type.h:332
TC_FLAGS_MASK
@ TC_FLAGS_MASK
Mask to test if TextColour (with flags) is within limits.
Definition gfx_type.h:335
TC_COLOUR_MASK
@ TC_COLOUR_MASK
Mask to test if TextColour (without flags) is within limits.
Definition gfx_type.h:334
lrucache.hpp
Size limited cache map with a least recently used eviction strategy.
math_func.hpp
Integer math functions.
Coord2D< int >
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition geometry_type.hpp:56
FontState
Text drawing parameters, which can change while drawing a line, but are kept between multiple parts o...
Definition gfx_layout.h:24
FontState::PushColour
void PushColour()
Push the current colour on to the stack.
Definition gfx_layout.h:58
FontState::SetColour
void SetColour(TextColour c)
Switch to new colour c.
Definition gfx_layout.h:38
FontState::PopColour
void PopColour()
Switch to and pop the last saved colour on the stack.
Definition gfx_layout.h:48
FontState::SetFontSize
void SetFontSize(FontSize f)
Switch to using a new font f.
Definition gfx_layout.h:67
FontState::fontsize
FontSize fontsize
Current font size.
Definition gfx_layout.h:25
FontState::colour_stack
std::vector< TextColour > colour_stack
Stack of colours to assist with colour switching.
Definition gfx_layout.h:27
FontState::cur_colour
TextColour cur_colour
Current text colour.
Definition gfx_layout.h:26
Layouter::LineCacheEqualTo
Definition gfx_layout.h:177
Layouter::LineCacheHash
Definition gfx_layout.h:235
Layouter::LineCacheItem
Item in the linecache.
Definition gfx_layout.h:189
Layouter::LineCacheItem::runs
FontMap runs
Accessed by our ParagraphLayout::nextLine.
Definition gfx_layout.h:194
Layouter::LineCacheItem::buffer
Buffer buffer
Accessed by our ParagraphLayout::nextLine.
Definition gfx_layout.h:193
Layouter::LineCacheItem::cached_width
int cached_width
Width used for the cached layout.
Definition gfx_layout.h:200
Layouter::LineCacheItem::cached_layout
std::vector< std::unique_ptr< const ParagraphLayouter::Line > > cached_layout
Cached results of line layouting.
Definition gfx_layout.h:199
Layouter::LineCacheItem::state_after
FontState state_after
Font state after the line.
Definition gfx_layout.h:196
Layouter::LineCacheItem::layout
std::unique_ptr< ParagraphLayouter > layout
Layout of the line.
Definition gfx_layout.h:197
Layouter::LineCacheKey
Key into the linecache.
Definition gfx_layout.h:164
Layouter::LineCacheKey::state_before
FontState state_before
Font state at the beginning of the line.
Definition gfx_layout.h:165
Layouter::LineCacheKey::str
std::string str
Source string of the line (including colour and font size codes).
Definition gfx_layout.h:166
Layouter::LineCacheQuery
Definition gfx_layout.h:169
Layouter::LineCacheQuery::state_before
const FontState & state_before
Font state at the beginning of the line.
Definition gfx_layout.h:170
Layouter::LineCacheQuery::str
std::string_view str
Source string of the line (including colour and font size codes).
Definition gfx_layout.h:171