neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
glyph_text.ipp
Go to the documentation of this file.
1// glyph_char.ipp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2015, 2020 Leigh Johnston. All Rights Reserved.
5
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#pragma once
21
22#include <neogfx/neogfx.hpp>
25
26namespace neogfx
27{
28 template <typename Container, typename ConstIterator, typename Iterator>
29 inline const font& basic_glyph_text_content<Container, ConstIterator, Iterator>::font_cache::glyph_font() const
30 {
31 if (!iCache.empty())
32 return iCache.begin()->second.second;
33 throw cached_font_not_found();
34 }
35
36 template <typename Container, typename ConstIterator, typename Iterator>
37 inline const font& basic_glyph_text_content<Container, ConstIterator, Iterator>::font_cache::glyph_font(font_id aFontId) const
38 {
39 cache_glyph_font(aFontId);
40 auto existing = iCache.find(aFontId);
41 if (existing != iCache.end())
42 return existing->second.second;
43 throw cached_font_not_found();
44 }
45
46 template <typename Container, typename ConstIterator, typename Iterator>
47 inline const font& basic_glyph_text_content<Container, ConstIterator, Iterator>::font_cache::glyph_font(const_reference aGlyphChar) const
48 {
49 return glyph_font(aGlyphChar.font);
50 }
51
52 template <typename Container, typename ConstIterator, typename Iterator>
53 inline void basic_glyph_text_content<Container, ConstIterator, Iterator>::font_cache::cache_glyph_font(font_id aFontId) const
54 {
55 if (iCache.find(aFontId) == iCache.end())
56 {
57 auto& fontService = service<i_font_manager>();
58 iCache.emplace(aFontId, cache_entry{ neolib::small_cookie_ref_ptr{ fontService, aFontId }, fontService.font_from_id(aFontId) });
59 }
60 }
61
62 template <typename Container, typename ConstIterator, typename Iterator>
63 inline void basic_glyph_text_content<Container, ConstIterator, Iterator>::font_cache::cache_glyph_font(const font& aFont) const
64 {
65 if (iCache.find(aFont.id()) == iCache.end())
66 {
67 auto& fontService = service<i_font_manager>();
68 iCache.emplace(aFont.id(), cache_entry{ neolib::small_cookie_ref_ptr{ fontService, aFont.id() }, aFont });
69 }
70 }
71
72 template <typename Container, typename ConstIterator, typename Iterator>
73 inline void basic_glyph_text_content<Container, ConstIterator, Iterator>::font_cache::clear()
74 {
75 iCache.clear();
76 }
77
78 template <typename Container, typename ConstIterator, typename Iterator>
80 container_type{},
81 iMajorFont{},
82 iBaseline{}
83 {
84 }
85
86 template <typename Container, typename ConstIterator, typename Iterator>
88 container_type{},
89 iMajorFont{ aFont.id() },
90 iBaseline{}
91 {
92 cache_glyph_font(aFont.id());
93 }
94
95 template <typename Container, typename ConstIterator, typename Iterator>
97 container_type{ aOther },
98 iCache{ aOther.iCache },
99 iExtents{ aOther.iExtents },
100 iMajorFont{ aOther.iMajorFont },
101 iBaseline{ aOther.iBaseline }
102 {
103 }
104
105 template <typename Container, typename ConstIterator, typename Iterator>
107 container_type{ std::move(aOther) },
108 iCache{ std::move(aOther.iCache) },
109 iExtents{ aOther.iExtents },
110 iMajorFont{ aOther.iMajorFont },
111 iBaseline{ aOther.iBaseline }
112 {
113 }
114
115 template <typename Container, typename ConstIterator, typename Iterator>
117 {
118 if (&aOther == this)
119 return *this;
120 container_type::operator=(aOther);
121 iCache = aOther.iCache;
122 iExtents = aOther.iExtents;
123 iMajorFont = aOther.iMajorFont;
124 iBaseline = aOther.iBaseline;
125 return *this;
126 }
127
128 template <typename Container, typename ConstIterator, typename Iterator>
130 {
131 if (&aOther == this)
132 return *this;
133 container_type::operator=(std::move(aOther));
134 iCache = aOther.iCache;
135 iExtents = aOther.iExtents;
136 iMajorFont = aOther.iMajorFont;
137 iBaseline = aOther.iBaseline;
138 return *this;
139 }
140
141 template <typename Container, typename ConstIterator, typename Iterator>
143 {
144 aClone = make_ref<self_type>(*this);
145 }
146
147 template <typename Container, typename ConstIterator, typename Iterator>
149 {
150 return container_type::empty();
151 }
152
153 template <typename Container, typename ConstIterator, typename Iterator>
158
159 template <typename Container, typename ConstIterator, typename Iterator>
161 {
162 if constexpr (std::is_same_v<const_iterator, typename container_type::const_iterator>)
163 return container_type::cbegin();
164 else
165 {
166 if (!empty())
167 return &*container_type::cbegin();
168 else
169 return nullptr;
170 }
171 }
172
173 template <typename Container, typename ConstIterator, typename Iterator>
175 {
176 if constexpr (std::is_same_v<const_iterator, typename container_type::const_iterator>)
177 return container_type::cend();
178 else
179 {
180 if (!empty())
181 return std::next(&*std::prev(container_type::cend()));
182 else
183 return nullptr;
184 }
185 }
186
187 template <typename Container, typename ConstIterator, typename Iterator>
189 {
190 iExtents = invalid;
191 if constexpr (std::is_same_v<iterator, typename container_type::iterator>)
192 return container_type::begin();
193 else
194 {
195 if (!empty())
196 return &*container_type::begin();
197 else
198 return nullptr;
199 }
200 }
201
202 template <typename Container, typename ConstIterator, typename Iterator>
204 {
205 iExtents = invalid;
206 if constexpr (std::is_same_v<iterator, typename container_type::iterator>)
207 return container_type::end();
208 else
209 {
210 if (!empty())
211 return std::next(&*std::prev(container_type::end()));
212 else
213 return nullptr;
214 }
215 }
216
217 template <typename Container, typename ConstIterator, typename Iterator>
223
224 template <typename Container, typename ConstIterator, typename Iterator>
226 {
227 container_type::push_back(aGlyphChar);
228 iExtents = invalid;
229 }
230
231 template <typename Container, typename ConstIterator, typename Iterator>
233 {
234 container_type::clear();
235 iCache.clear();
236 iExtents = invalid;
237 }
238
239 template <typename Container, typename ConstIterator, typename Iterator>
241 {
242 return static_cast<const container_type&>(*this) == static_cast<const container_type&>(aOther);
243 }
244
245 template <typename Container, typename ConstIterator, typename Iterator>
247 {
248 return *this;
249 }
250
251 template <typename Container, typename ConstIterator, typename Iterator>
253 {
254 return *this;
255 }
256
257 template <typename Container, typename ConstIterator, typename Iterator>
259 {
260 if (!iExtents)
261 iExtents = extents(begin(), end());
262 return *iExtents;
263 }
264
265 template <typename Container, typename ConstIterator, typename Iterator>
267 {
268 return rect{ to_aabb_2d(aGlyphChar.cell.begin(), aGlyphChar.cell.end()) }.extents().ceil();
269 }
270
271 template <typename Container, typename ConstIterator, typename Iterator>
272 inline size basic_glyph_text_content<Container, ConstIterator, Iterator>::extents(const_iterator aBegin, const_iterator aEnd) const
273 {
274 if (aBegin == aEnd)
275 return neogfx::size{ 0.0, glyph_font().height() };
276 auto const& firstGlyph = *aBegin;
277 auto const& lastGlyph = *std::prev(aEnd);
278 quad_2d const quadExtents{
279 firstGlyph.cell[0],
280 lastGlyph.cell[1],
281 lastGlyph.cell[3],
282 firstGlyph.cell[3] };
283 rect const boundingRect{ to_aabb_2d(quadExtents.begin(), quadExtents.end()) };
284 return boundingRect.extents().ceil();
285 }
286
287 template <typename Container, typename ConstIterator, typename Iterator>
289 {
290 iExtents = aExtents;
291 }
292
293 template <typename Container, typename ConstIterator, typename Iterator>
295 {
296 auto result = align_baselines(begin(), end());
297 iMajorFont = result.majorFont;
298 iBaseline = result.baseline;
299 return *this;
300 }
301
302 template <typename Container, typename ConstIterator, typename Iterator>
304 {
305 align_baselines_result result = {};
306 float cyMax = 0.0f;
307 float yMax = 0.0f;
308 if (aBegin != aEnd)
309 {
310 for (auto const& g : std::ranges::subrange(aBegin, aEnd))
311 {
312 auto const& gf = glyph_font(g);
313 auto const existingExtents = quad_extents(g.cell);
314 result.yExtent = std::max(result.yExtent, existingExtents.y);
315 float cy = existingExtents.y + static_cast<float>(gf.descender());
316 if (cy > cyMax)
317 {
318 cyMax = cy;
319 result.majorFont = gf.id();
320 result.baseline = cyMax;
321 }
322 yMax = std::max(yMax, existingExtents.y);
323 }
324 }
325 else
326 {
327 result.majorFont = major_font().id();
328 result.yExtent = static_cast<float>(major_font().height());
329 }
330 if (aJustCalculate)
331 return result;
332 for (auto& g : std::ranges::subrange(aBegin, aEnd))
333 {
334 auto const& gf = glyph_font(g);
335 auto const existingExtents = quad_extents(g.cell);
336 g.shape += vec2f{ 0.0f, cyMax - (existingExtents.y + static_cast<float>(gf.descender())) };
337 g.cell[2].y = g.cell[1].y + yMax;
338 g.cell[3].y = g.cell[0].y + yMax;
340 {
341 scalar const ascender = gf.ascender();
342 scalar const descender = gf.descender();
343 scalar const cy = ascender - descender;
344 scalar const dyLarge = cy / 0.58 * 0.33; // todo: make configurable attributes
345 scalar const dySmall = dyLarge * 0.5; // todo: make configurable attributes
347 {
348 auto const belowAscenderDelta = static_cast<float>(dySmall);
349 auto const aboveAscenderDelta = static_cast<float>(dyLarge);
351 g.shape -= vec2f{ 0.0f, std::ceil(belowAscenderDelta) };
352 else
353 g.shape -= vec2f{ 0.0f, std::ceil(aboveAscenderDelta) };
354 }
355 else if ((g.flags & glyph_char::Subscript) == glyph_char::Subscript)
356 {
357 auto const aboveBaselineDelta = 0.0f;
358 auto const belowBaselineDelta = static_cast<float>(dyLarge + descender / 0.58);
360 g.shape += vec2f{ 0.0f, aboveBaselineDelta };
361 else
362 g.shape += vec2f{ 0.0f, belowBaselineDelta };
363 }
364 }
365 }
366 return result;
367 }
368
369 template <typename Container, typename ConstIterator, typename Iterator>
370 inline std::pair<typename basic_glyph_text_content<Container, ConstIterator, Iterator>::const_iterator, typename basic_glyph_text_content<Container, ConstIterator, Iterator>::const_iterator> basic_glyph_text_content<Container, ConstIterator, Iterator>::word_break(const_iterator aBegin, const_iterator aFrom) const
371 {
372 std::pair<const_iterator, const_iterator> result(aFrom, aFrom);
373 if (!is_whitespace(*aFrom))
374 {
375 while (result.first != aBegin && !is_whitespace(*result.first))
376 --result.first;
377 if (!is_whitespace(*result.first))
378 {
379 result.first = aFrom;
380 while (result.first != aBegin && (result.first - 1)->clusters == aFrom->clusters)
381 --result.first;
382 result.second = result.first;
383 return result;
384 }
385 result.second = result.first;
386 }
387 while (result.first != aBegin && is_whitespace(*(result.first - 1)))
388 --result.first;
389 while (is_whitespace(*result.second) && result.second != end())
390 ++result.second;
391 return result;
392 }
393
394 template <typename Container, typename ConstIterator, typename Iterator>
395 inline std::pair<typename basic_glyph_text_content<Container, ConstIterator, Iterator>::iterator, typename basic_glyph_text_content<Container, ConstIterator, Iterator>::iterator> basic_glyph_text_content<Container, ConstIterator, Iterator>::word_break(const_iterator aBegin, const_iterator aFrom)
396 {
397 auto result = const_cast<const self_type&>(*this).word_break(aBegin, aFrom);
398 return std::make_pair(std::next(begin(), std::distance(cbegin(), result.first)), std::next(begin(), std::distance(cbegin(), result.second)));
399 }
400
401 template <typename Container, typename ConstIterator, typename Iterator>
406
407 template <typename Container, typename ConstIterator, typename Iterator>
412
413 template <typename Container, typename ConstIterator, typename Iterator>
415 {
416 return iCache.glyph_font();
417 }
418
419 template <typename Container, typename ConstIterator, typename Iterator>
420 inline const font& basic_glyph_text_content<Container, ConstIterator, Iterator>::glyph_font(const_reference aGlyphChar) const
421 {
422 return iCache.glyph_font(aGlyphChar);
423 }
424
425 template <typename Container, typename ConstIterator, typename Iterator>
427 {
428 iCache.cache_glyph_font(aFontId);
429 }
430
431 template <typename Container, typename ConstIterator, typename Iterator>
433 {
434 iCache.cache_glyph_font(aFont);
435 }
436
437 template <typename Container, typename ConstIterator, typename Iterator>
439 {
440 return glyph_font(aGlyphChar).glyph(aGlyphChar);
441 }
442
443 template <typename Container, typename ConstIterator, typename Iterator>
445 {
446 iMajorFont = aFont.id();
447 }
448
449 template <typename Container, typename ConstIterator, typename Iterator>
451 {
452 return iCache.glyph_font(iMajorFont);
453 }
454
455 template <typename Container, typename ConstIterator, typename Iterator>
460
461 template <typename Container, typename ConstIterator, typename Iterator>
463 {
464 iBaseline = aBaseline;
465 }
466}
const_iterator cend() const override
self_type & operator=(const self_type &aOther)
self_type & align_baselines() override
void set_major_font(const font &aFont) override
const i_glyph & glyph(const_reference aGlyphChar) const override
void cache_glyph_font(font_id aFontId) const override
std::pair< const_iterator, const_iterator > word_break(const_iterator aBegin, const_iterator aFrom) const override
void push_back(const_reference aGlyphChar) override
void set_extents(const neogfx::size &aExtents) override
vector< size_type > const & line_breaks() const override
const_iterator cbegin() const override
size_type size() const override
const font & glyph_font() const override
bool operator==(const self_type &aOther) const
scalar baseline() const override
void clone(i_ref_ptr< abstract_type > &aClone) const override
neogfx::size extents() const override
bool empty() const override
const font & major_font() const override
container_type const & container() const
void set_baseline(scalar aBaseline) override
bool is_whitespace(glyph_char const &g)
uint32_t id
std::array< vec2, 4 > quad_2d
double scalar
Definition numerical.hpp:63
basic_vector< T, D > quad_extents(std::array< basic_vector< T, D >, 4 > const &aQuad)
vector2f vec2f
aabb_2d to_aabb_2d(const vec3 &aOrigin, scalar aSize)
basic_cookie_ref_ptr< small_cookie > small_cookie_ref_ptr
Definition jar.hpp:733
Definition plf_hive.h:79
it_type next(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:89
iterator_traits< it_type >::difference_type distance(const it_type first, const it_type last)
Definition plf_hive.h:107
it_type prev(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:98