neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
glyph_text.hpp
Go to the documentation of this file.
1// glyph_text.hpp
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>
23#include <optional>
30
31namespace neogfx
32{
33 // case insensitive text
34 typedef std::basic_string<char, neolib::ci_char_traits<std::char_traits<char> > > ci_string;
35
36 enum class text_category : uint8_t
37 {
38 Unknown = 0x00,
39 None = 0x01,
40 Whitespace = 0x02,
41 Digit = 0x03,
42 LTR = 0x04,
43 RTL = 0x05,
44 Mark = 0x06,
45 Mnemonic = 0x07,
46 Emoji = 0x08,
47 FontEmoji = 0x09,
48 Control = 0x0A
49 };
50
51 enum class text_direction : uint8_t
52 {
53 Invalid = 0x00,
54 LTR = 0x01,
55 RTL = 0x02
56 };
57
59 {
60 public:
63 public:
67 category(aCategory), direction(aDirection) {}
70 public:
71 bool operator==(const character_type& aRhs) const { return category == aRhs.category && direction == aRhs.direction; }
72 bool operator!=(const character_type& aRhs) const { return !(*this == aRhs); }
73 };
74
76 {
77 using value_type = std::uint32_t;
78 using cluster_index = std::uint32_t;
79 using cluster_range = std::pair<cluster_index, cluster_index>;
80 enum flags_e : uint8_t
81 {
82 Default = 0x00,
83 Underline = 0x01,
85 Subscript = 0x04,
88 Mnemonic = 0x40,
89 Subpixel = 0x80,
90 };
91
96 font_id font;
99 };
100
101 inline bool operator==(const glyph_char& lhs, const glyph_char& rhs)
102 {
103 return lhs.type.category == rhs.type.category && lhs.value == rhs.value;
104 }
105
106 inline bool has_font(glyph_char const& g)
107 {
108 return g.font != font_id{};
109 }
110
112 {
113 return g.type.category;
114 }
115
117 {
118 g.type.category = c;
119 }
120
122 {
123 return g.type.direction;
124 }
125
126 inline bool is_whitespace(glyph_char const& g)
127 {
129 };
130
132 {
133 return is_whitespace(g) && (g.value == U'\r' || g.value == U'\n');
134 }
135
137 {
139 }
140
141 inline bool is_digit(glyph_char const& g)
142 {
143 return category(g) == text_category::Digit;
144 }
145
146 inline bool is_emoji(glyph_char const& g)
147 {
148 return category(g) == text_category::Emoji;
149 }
150
151 inline bool has_font_glyph(glyph_char const& g)
152 {
153 return has_font(g) && !is_whitespace(g) && !is_emoji(g);
154 }
155
156 inline bool left_to_right(glyph_char const& g)
157 {
158 return direction(g) == text_direction::LTR;
159 }
160
161 inline bool right_to_left(glyph_char const& g)
162 {
163 return direction(g) == text_direction::RTL;
164 }
165
167 {
169 }
170
171 inline bool underline(glyph_char const& g)
172 {
174 }
175
176 inline void set_underline(glyph_char& g, bool aUnderline)
177 {
178 g.flags = static_cast<glyph_char::flags_e>(aUnderline ? g.flags | glyph_char::Underline : g.flags & ~glyph_char::Underline);
179 }
180
181 inline bool superscript(glyph_char const& g)
182 {
184 }
185
190
191 inline void set_superscript(glyph_char& g, bool aSuperscript, bool aBelowAscenderLine = false)
192 {
193 g.flags = static_cast<glyph_char::flags_e>(aSuperscript ? g.flags | glyph_char::Superscript : g.flags & ~glyph_char::Superscript);
195 }
196
197 inline bool subscript(glyph_char const& g)
198 {
200 }
201
202 inline bool above_baseline(glyph_char const& g)
203 {
205 }
206
207 inline void set_subscript(glyph_char& g, bool aSubscript, bool aAboveBaseline = false)
208 {
209 g.flags = static_cast<glyph_char::flags_e>(aSubscript ? g.flags | glyph_char::Subscript : g.flags & ~glyph_char::Subscript);
211 }
212
213 inline bool subpixel(glyph_char const& g)
214 {
216 }
217
218 inline void set_subpixel(glyph_char& g, bool aSubpixel)
219 {
220 g.flags = static_cast<glyph_char::flags_e>(aSubpixel ? g.flags | glyph_char::Subpixel : g.flags & ~glyph_char::Subpixel);
221 }
222
223 inline bool mnemonic(glyph_char const& g)
224 {
226 }
227
228 inline void set_mnemonic(glyph_char& g, bool aMnemonic)
229 {
230 g.flags = static_cast<glyph_char::flags_e>(aMnemonic ? g.flags | glyph_char::Mnemonic : g.flags & ~glyph_char::Mnemonic);
231 }
232
233 template <typename GlyphT, typename ConstIterator = GlyphT const*, typename Iterator = GlyphT*>
235 {
237 public:
238 typedef self_type abstract_type;
239 public:
240 typedef GlyphT value_type;
241 typedef value_type const* const_pointer;
245 typedef ConstIterator const_iterator;
246 typedef Iterator iterator;
247 typedef std::size_t size_type;
248 typedef std::ptrdiff_t difference_type;
250 {
251 float yExtent;
252 font_id majorFont;
253 float baseline;
254 };
255 public:
256 virtual void clone(i_ref_ptr<self_type>& aClone) const = 0;
258 {
259 ref_ptr<self_type> result;
260 clone(result);
261 return result;
262 }
263 public:
264 virtual const font& glyph_font() const = 0;
265 virtual const font& glyph_font(const_reference aGlyphChar) const = 0;
266 virtual void cache_glyph_font(font_id aFontId) const = 0;
267 virtual void cache_glyph_font(const font& aFont) const = 0;
268 virtual const i_glyph& glyph(const_reference aGlyphChar) const = 0;
269 public:
270 virtual const font& major_font() const = 0;
271 virtual void set_major_font(const font& aFont) = 0;
272 virtual scalar baseline() const = 0;
273 virtual void set_baseline(scalar aBaseline) = 0;
274 public:
275 virtual bool empty() const = 0;
276 virtual size_type size() const = 0;
277 virtual void clear() = 0;
278 public:
279 virtual void push_back(const_reference aGlyphChar) = 0;
280 public:
281 virtual neogfx::size extents() const = 0;
282 virtual neogfx::size extents(const_reference aGlyphChar) const = 0;
283 virtual neogfx::size extents(const_iterator aBegin, const_iterator aEnd) const = 0;
284 public:
285 virtual void set_extents(const neogfx::size& aExtents) = 0;
286 virtual self_type& align_baselines() = 0;
287 virtual align_baselines_result align_baselines(iterator aBegin, iterator aEnd, bool aJustCalculate = false) = 0;
288 virtual std::pair<const_iterator, const_iterator> word_break(const_iterator aBegin, const_iterator aFrom) const = 0;
289 virtual std::pair<iterator, iterator> word_break(const_iterator aBegin, const_iterator aFrom) = 0;
290 public:
291 virtual i_vector<size_type> const& line_breaks() const = 0;
293 public:
294 virtual const_iterator cbegin() const = 0;
295 virtual const_iterator cend() const = 0;
297 {
298 return cbegin();
299 }
301 {
302 return cend();
303 }
304 virtual iterator begin() = 0;
305 virtual iterator end() = 0;
306 };
307
309
310 template <typename Container, typename ConstIterator = typename Container::const_iterator, typename Iterator = typename Container::iterator>
311 class basic_glyph_text_content : public reference_counted<i_basic_glyph_text<typename Container::value_type, ConstIterator, Iterator>>, public Container
312 {
314 typedef Container base_type;
315 public:
317 public:
318 using typename abstract_type::value_type;
319 using typename abstract_type::const_pointer;
320 using typename abstract_type::pointer;
321 using typename abstract_type::const_reference;
322 using typename abstract_type::reference;
323 using typename abstract_type::const_iterator;
324 using typename abstract_type::iterator;
325 using typename abstract_type::size_type;
326 using typename abstract_type::difference_type;
328 private:
329 static constexpr std::size_t SMALL_OPTIMIZATION_FONT_COUNT = 4;
330 typedef Container container_type;
331 class font_cache
332 {
333 private:
334 typedef std::pair<neolib::small_cookie_ref_ptr, font> cache_entry;
335 typedef std::unordered_map<font_id, cache_entry, std::hash<font_id>, std::equal_to<font_id>, neolib::fast_pool_allocator<std::pair<const font_id, cache_entry>>> cache;
336 public:
337 struct cached_font_not_found : std::logic_error { cached_font_not_found() : std::logic_error("neogfx::glyph_text_content::font_cache::cached_font_not_found") {} };
338 public:
339 const font& glyph_font() const;
340 const font& glyph_font(font_id aFontId) const;
341 const font& glyph_font(const_reference aGlyphChar) const;
342 void cache_glyph_font(font_id aFontId) const;
343 void cache_glyph_font(const font& aFont) const;
344 public:
345 void clear();
346 private:
347 mutable cache iCache;
348 };
349 public:
351 basic_glyph_text_content(font const& aFont);
352 template <typename Iter>
353 basic_glyph_text_content(Iter aBegin, Iter aEnd) :
354 container_type{ aBegin, aEnd },
355 iMajorFont{},
356 iBaseline{}
357 {
358 }
359 basic_glyph_text_content(const self_type& aOther);
360 basic_glyph_text_content(self_type&& aOther);
361 public:
362 self_type& operator=(const self_type& aOther);
363 self_type& operator=(self_type&& aOther);
364 public:
365 container_type const& container() const;
366 container_type& container();
367 public:
368 void clone(i_ref_ptr<abstract_type>& aClone) const override;
369 public:
370 bool empty() const override;
371 size_type size() const override;
372 void clear() override;
373 public:
374 template< class... Args >
375 reference emplace_back(Args&&... args)
376 {
377 auto& result = container_type::emplace_back(std::forward<Args>(args)...);
378 iExtents = std::nullopt;
379 return result;
380 }
381 void push_back(const_reference aGlyphChar) override;
382 public:
383 using container_type::back;
384 reference back();
385 public:
386 const_iterator cbegin() const override;
387 const_iterator cend() const override;
389 using abstract_type::end;
390 iterator begin() override;
391 iterator end() override;
392 public:
393 bool operator==(const self_type& aOther) const;
394 public:
395 neogfx::size extents() const override;
396 neogfx::size extents(const_reference aGlyphChar) const override;
397 neogfx::size extents(const_iterator aBegin, const_iterator aEnd) const override;
398 public:
399 void set_extents(const neogfx::size& aExtents) override;
400 self_type& align_baselines() override;
401 align_baselines_result align_baselines(iterator aBegin, iterator aEnd, bool aJustCalculate = false) override;
402 std::pair<const_iterator, const_iterator> word_break(const_iterator aBegin, const_iterator aFrom) const override;
403 std::pair<iterator, iterator> word_break(const_iterator aBegin, const_iterator aFrom) override;
404 public:
405 vector<size_type> const& line_breaks() const override;
406 vector<size_type>& line_breaks() override;
407 public:
408 const font& glyph_font() const override;
409 const font& glyph_font(const_reference aGlyphChar) const override;
410 void cache_glyph_font(font_id aFontId) const override;
411 void cache_glyph_font(const font& aFont) const override;
412 const i_glyph& glyph(const_reference aGlyphChar) const override;
413 public:
414 const font& major_font() const override;
415 void set_major_font(const font& aFont) override;
416 scalar baseline() const override;
417 void set_baseline(scalar aBaseline) override;
418 private:
419 font_cache iCache;
420 mutable cache<neogfx::size> iExtents;
421 vector<size_type> iLineBreaks;
422 font_id iMajorFont;
423 scalar iBaseline;
424 };
425
428
430
432 {
433 public:
442 public:
443 glyph_text() = delete;
444 glyph_text(font const& aFont);
446 glyph_text(glyph_text const& aOther);
447 template <typename GlyphIter>
448 glyph_text(font const& aFont, GlyphIter aGlyphsBegin, GlyphIter aGlyphsEnd) :
449 glyph_text{ aFont }
450 {
451 for (auto const& glyph : std::ranges::subrange(aGlyphsBegin, aGlyphsEnd))
452 {
455 }
456 }
457 public:
460 public:
462 public:
463 const font& glyph_font() const;
464 const font& glyph_font(const_reference aGlyphChar) const;
465 const i_glyph& glyph(const_reference aGlyphChar) const;
466 public:
467 bool empty() const;
469 void clear();
470 public:
474 public:
475 void set_extents(const neogfx::size& aExtents);
476 std::pair<const_iterator, const_iterator> word_break(const_iterator aBegin, const_iterator aFrom) const;
477 std::pair<iterator, iterator> word_break(const_iterator aBegin, const_iterator aFrom);
478 public:
481 public:
488 private:
489 mutable ref_ptr<i_glyph_text> iContent;
490 };
491
505
506 template <typename Iter>
507 inline text_direction glyph_text_direction(Iter aBegin, Iter aEnd)
508 {
510 bool gotOne = false;
511 for (Iter i = aBegin; !gotOne && i != aEnd; ++i)
512 {
514 {
515 if (!gotOne)
516 {
517 gotOne = true;
518 result = direction(*i);
519 }
520 }
521 }
522 return result;
523 }
524
525 typedef std::optional<glyph_text> optional_glyph_text;
526
527 class i_graphics_context;
528
530 {
531 public:
532 virtual ~i_font_selector() = default;
533 public:
534 virtual font select_font(std::size_t CharacterPos) const = 0;
535 };
536
538 {
539 typedef std::function<font(std::size_t)> function_type;
540 public:
541 explicit font_selector(function_type const& aSelectorFunction) :
542 iSelectorFunction{ aSelectorFunction }
543 {
544 }
545 public:
546 font select_font(std::size_t CharacterPos) const override
547 {
548 return iSelectorFunction(CharacterPos);
549 }
550 private:
551 function_type iSelectorFunction;
552 };
553
555 {
556 public:
557 virtual ~i_glyph_text_factory() = default;
558 public:
560 virtual glyph_text create_glyph_text(font const& aFont) = 0;
561 virtual glyph_text to_glyph_text(i_graphics_context const& aContext, char32_t const* aUtf32Begin, char32_t const* aUtf32End, i_font_selector const& aFontSelector, bool aAlignBaselines = true) = 0;
562 virtual glyph_text to_glyph_text(i_graphics_context const& aContext, char const* aUtf8Begin, char const* aUtf8End, i_font_selector const& aFontSelector, bool aAlignBaselines = true) = 0;
563 public:
564 glyph_text to_glyph_text(i_graphics_context const& aContext, char32_t const* aUtf32Begin, char32_t const* aUtf32End, std::function<font(std::size_t)> aFontSelector, bool aAlignBaselines = true)
565 {
566 return to_glyph_text(aContext, aUtf32Begin, aUtf32End, font_selector{ aFontSelector }, aAlignBaselines);
567 }
568 glyph_text to_glyph_text(i_graphics_context const& aContext, std::u32string_view const& aString, std::function<font(std::size_t)> aFontSelector, bool aAlignBaselines = true)
569 {
570 return to_glyph_text(aContext, aString.data(), aString.data() + aString.size(), font_selector{ aFontSelector }, aAlignBaselines);
571 }
572 glyph_text to_glyph_text(i_graphics_context const& aContext, char const* aUtf8Begin, char const* aUtf8End, std::function<font(std::size_t)> aFontSelector, bool aAlignBaselines = true)
573 {
574 return to_glyph_text(aContext, aUtf8Begin, aUtf8End, font_selector{ aFontSelector }, aAlignBaselines);
575 }
576 glyph_text to_glyph_text(i_graphics_context const& aContext, std::string_view const& aString, std::function<font(std::size_t)> aFontSelector, bool aAlignBaselines = true)
577 {
578 return to_glyph_text(aContext, aString.data(), aString.data() + aString.size(), font_selector{ aFontSelector }, aAlignBaselines);
579 }
580 glyph_text to_glyph_text(i_graphics_context const& aContext, i_string const& aString, std::function<font(std::size_t)> aFontSelector, bool aAlignBaselines = true)
581 {
582 return to_glyph_text(aContext, aString.c_str(), aString.c_str() + aString.size(), font_selector{ aFontSelector }, aAlignBaselines);
583 }
584 };
585}
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
void cache_glyph_font(font_id aFontId) const override
i_basic_glyph_text< typename Container::value_type, ConstIterator, Iterator > abstract_type
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
value_type const & const_reference
const font & glyph_font() const override
scalar baseline() const override
void clone(i_ref_ptr< abstract_type > &aClone) const override
neogfx::size extents() const override
reference emplace_back(Args &&... args)
basic_glyph_text_content(Iter aBegin, Iter aEnd)
bool empty() const override
const font & major_font() const override
container_type const & container() const
void set_baseline(scalar aBaseline) override
bool operator!=(const character_type &aRhs) const
character_type(text_category aCategory)
bool operator==(const character_type &aRhs) const
character_type(text_category aCategory, text_direction aDirection)
text_category category
text_direction direction
font select_font(std::size_t CharacterPos) const override
font_selector(function_type const &aSelectorFunction)
i_glyph_text::const_iterator const_iterator
i_glyph_text::const_reference const_reference
const font & glyph_font() const
const_iterator end() const
glyph_text(font const &aFont, GlyphIter aGlyphsBegin, GlyphIter aGlyphsEnd)
i_glyph_text::difference_type difference_type
i_glyph_text::iterator iterator
const font & glyph_font(const_reference aGlyphChar) const
const_iterator begin() const
glyph_text(glyph_text const &aOther)
const_reference back() const
i_glyph_text::const_pointer const_pointer
std::pair< iterator, iterator > word_break(const_iterator aBegin, const_iterator aFrom)
const_iterator cbegin() const
const_iterator cend() const
glyph_text(font const &aFont)
i_glyph_text::pointer pointer
bool empty() const
neogfx::size extents() const
neogfx::size extents(const_reference aGlyphChar) const
glyph_text(i_glyph_text &aContents)
glyph_text operator=(const glyph_text &aOther)
void set_extents(const neogfx::size &aExtents)
i_glyph_text::size_type size_type
std::pair< const_iterator, const_iterator > word_break(const_iterator aBegin, const_iterator aFrom) const
neogfx::size extents(const_iterator aBegin, const_iterator aEnd) const
const i_glyph & glyph(const_reference aGlyphChar) const
glyph_text clone() const
i_glyph_text::reference reference
size_type size() const
i_glyph_text & content() const
reference back()
virtual std::pair< const_iterator, const_iterator > word_break(const_iterator aBegin, const_iterator aFrom) const =0
virtual i_vector< size_type > const & line_breaks() const =0
virtual std::pair< iterator, iterator > word_break(const_iterator aBegin, const_iterator aFrom)=0
value_type const * const_pointer
virtual neogfx::size extents(const_reference aGlyphChar) const =0
virtual void cache_glyph_font(const font &aFont) const =0
virtual void clone(i_ref_ptr< self_type > &aClone) const =0
virtual void set_extents(const neogfx::size &aExtents)=0
virtual neogfx::size extents() const =0
virtual iterator begin()=0
virtual const font & major_font() const =0
virtual const font & glyph_font(const_reference aGlyphChar) const =0
virtual size_type size() const =0
const_iterator end() const
virtual const font & glyph_font() const =0
virtual void clear()=0
virtual self_type & align_baselines()=0
virtual const i_glyph & glyph(const_reference aGlyphChar) const =0
virtual iterator end()=0
value_type const & const_reference
std::ptrdiff_t difference_type
virtual i_vector< size_type > & line_breaks()=0
virtual void set_baseline(scalar aBaseline)=0
const_iterator begin() const
virtual const_iterator cbegin() const =0
virtual neogfx::size extents(const_iterator aBegin, const_iterator aEnd) const =0
virtual void cache_glyph_font(font_id aFontId) const =0
virtual align_baselines_result align_baselines(iterator aBegin, iterator aEnd, bool aJustCalculate=false)=0
virtual void push_back(const_reference aGlyphChar)=0
virtual bool empty() const =0
virtual const_iterator cend() const =0
virtual void set_major_font(const font &aFont)=0
virtual scalar baseline() const =0
ref_ptr< self_type > clone() const
virtual font select_font(std::size_t CharacterPos) const =0
virtual ~i_font_selector()=default
glyph_text to_glyph_text(i_graphics_context const &aContext, std::string_view const &aString, std::function< font(std::size_t)> aFontSelector, bool aAlignBaselines=true)
glyph_text to_glyph_text(i_graphics_context const &aContext, char32_t const *aUtf32Begin, char32_t const *aUtf32End, std::function< font(std::size_t)> aFontSelector, bool aAlignBaselines=true)
glyph_text to_glyph_text(i_graphics_context const &aContext, std::u32string_view const &aString, std::function< font(std::size_t)> aFontSelector, bool aAlignBaselines=true)
virtual glyph_text create_glyph_text(font const &aFont)=0
glyph_text to_glyph_text(i_graphics_context const &aContext, i_string const &aString, std::function< font(std::size_t)> aFontSelector, bool aAlignBaselines=true)
virtual glyph_text to_glyph_text(i_graphics_context const &aContext, char const *aUtf8Begin, char const *aUtf8End, i_font_selector const &aFontSelector, bool aAlignBaselines=true)=0
virtual glyph_text to_glyph_text(i_graphics_context const &aContext, char32_t const *aUtf32Begin, char32_t const *aUtf32End, i_font_selector const &aFontSelector, bool aAlignBaselines=true)=0
virtual glyph_text create_glyph_text()=0
virtual ~i_glyph_text_factory()=default
glyph_text to_glyph_text(i_graphics_context const &aContext, char const *aUtf8Begin, char const *aUtf8End, std::function< font(std::size_t)> aFontSelector, bool aAlignBaselines=true)
virtual size_type size() const noexcept=0
virtual const value_type * c_str() const noexcept=0
void set_mnemonic(glyph_char &g, bool aMnemonic)
bool below_ascender_line(glyph_char const &g)
bool is_whitespace(glyph_char const &g)
bool category_has_no_direction(glyph_char const &g)
std::basic_string< char, neolib::ci_char_traits< std::char_traits< char > > > ci_string
void set_subscript(glyph_char &g, bool aSubscript, bool aAboveBaseline=false)
void set_subpixel(glyph_char &g, bool aSubpixel)
bool above_baseline(glyph_char const &g)
constexpr std::size_t SMALL_OPTIMIZATION_GLYPH_TEXT_GLYPH_COUNT
bool underline(glyph_char const &g)
text_direction direction(glyph_char const &g)
std::optional< glyph_text > optional_glyph_text
bool mnemonic(glyph_char const &g)
bool right_to_left(glyph_char const &g)
bool left_to_right(glyph_char const &g)
constexpr object_type category(object_type aType)
basic_glyph_text_content< neolib::vecarray< glyph_char, SMALL_OPTIMIZATION_GLYPH_TEXT_GLYPH_COUNT, -1 >, glyph_char const *, glyph_char * > glyph_text_content
bool superscript(glyph_char const &g)
bool operator==(const basic_rect< CoordinateType, CoordinateSystem > &left, const basic_rect< CoordinateType, CoordinateSystem > &right)
bool has_font(glyph_char const &g)
bool has_font_glyph(glyph_char const &g)
void set_category(glyph_char &g, text_category c)
bool is_non_line_breaking_whitespace(glyph_char const &g)
bool is_emoji(glyph_char const &g)
bool subpixel(glyph_char const &g)
bool is_line_breaking_whitespace(glyph_char const &g)
bool subscript(glyph_char const &g)
void set_underline(glyph_char &g, bool aUnderline)
void set_superscript(glyph_char &g, bool aSuperscript, bool aBelowAscenderLine=false)
text_direction glyph_text_direction(Iter aBegin, Iter aEnd)
bool is_digit(glyph_char const &g)
std::array< vec3, 4 > quad
double scalar
Definition numerical.hpp:63
std::array< vec2f, 4 > quadf_2d
boost::fast_pool_allocator< T, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex, NextSize > fast_pool_allocator
std::uint32_t cluster_index
std::uint32_t value_type
cluster_range clusters
std::pair< cluster_index, cluster_index > cluster_range
character_type type
glyph_text::difference_type end
glyph_text::difference_type begin
neolib::vecarray< line, 8, -1 > lines_t