HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
text_style.hpp
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "text_decoration.hpp"
8#include "semantic_text_style.hpp"
9#include "../color/module.hpp"
10#include "../i18n/module.hpp"
11#include "../unicode/module.hpp"
12#include "../utility/module.hpp"
13#include "../font/module.hpp"
14#include "../telemetry/module.hpp"
15#include "../container/module.hpp"
16#include <ostream>
17#include <vector>
18#include <algorithm>
19
20namespace hi::inline v1 {
21class font_book;
22
24 phrasing_mask phrasing_mask;
25 iso_639 language_filter;
26 iso_15924 script_filter;
27
28 font_family_id family_id;
29 ::hi::color color;
30 float size;
31 font_variant variant;
32 text_decoration decoration;
33
34 text_sub_style() noexcept = default;
35
37 hi::phrasing_mask phrasing_mask,
38 iso_639 language_filter,
39 iso_15924 script_filter,
40 font_family_id family_id,
41 font_variant variant,
42 float size,
43 ::hi::color color,
44 text_decoration decoration) noexcept :
45 phrasing_mask(phrasing_mask),
46 language_filter(language_filter),
47 script_filter(script_filter),
48 family_id(family_id),
49 color(color),
50 size(size),
51 variant(variant),
52 decoration(decoration)
53 {
54 }
55
56 [[nodiscard]] size_t hash() const noexcept
57 {
58 auto r = 0_uz;
59 r ^= std::hash<hi::phrasing_mask>{}(phrasing_mask);
60 r ^= std::hash<iso_639>{}(language_filter);
61 r ^= std::hash<iso_15924>{}(script_filter);
62 r ^= std::hash<font_family_id>{}(family_id);
63 r ^= std::hash<hi::color>{}(color);
64 r ^= std::hash<float>{}(size);
65 r ^= std::hash<font_variant>{}(variant);
66 r ^= std::hash<text_decoration>{}(decoration);
67 return r;
68 }
69
70 [[nodiscard]] float cap_height(font_book const& font_book) const noexcept;
71 [[nodiscard]] float x_height(font_book const& font_book) const noexcept;
72
73 [[nodiscard]] bool matches(phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
74 {
75 if (not to_bool(phrasing_mask & to_phrasing_mask(phrasing))) {
76 return false;
77 }
78 if (language_filter and language and language_filter != language) {
79 return false;
80 }
81 if (script_filter and script and script_filter != script) {
82 return false;
83 }
84 return true;
85 }
86
87 [[nodiscard]] friend bool operator==(text_sub_style const&, text_sub_style const&) noexcept = default;
88};
89
90} // namespace hi::inline v1
91
92template<>
93struct std::hash<hi::text_sub_style> {
94 [[nodiscard]] size_t operator()(hi::text_sub_style const& rhs) const noexcept
95 {
96 return rhs.hash();
97 }
98};
99
100namespace hi::inline v1::detail {
101
104 using reference = value_type const&;
106 using iterator = vector_type::const_iterator;
107
108 vector_type _sub_styles;
109
110 constexpr text_style_impl() noexcept = default;
111
112 text_style_impl(std::vector<text_sub_style> sub_styles) noexcept : _sub_styles(std::move(sub_styles))
113 {
114 hi_assert(not empty());
115 hi_assert(all(back().phrasing_mask));
116 hi_assert(back().language_filter.empty());
117 hi_assert(back().script_filter.empty());
118 }
119
120 [[nodiscard]] bool empty() const noexcept
121 {
122 return _sub_styles.empty();
123 }
124
125 explicit operator bool() const noexcept
126 {
127 return not empty();
128 }
129
130 [[nodiscard]] size_t hash() const noexcept
131 {
132 auto r = 0_uz;
133 for (hilet& sub_style : _sub_styles) {
134 r ^= std::hash<text_sub_style>{}(sub_style);
135 }
136 return r;
137 }
138
139 [[nodiscard]] reference back() const noexcept
140 {
141 return _sub_styles.back();
142 }
143
144 [[nodiscard]] iterator begin() const noexcept
145 {
146 return _sub_styles.begin();
147 }
148
149 [[nodiscard]] iterator end() const noexcept
150 {
151 return _sub_styles.end();
152 }
153
154 [[nodiscard]] constexpr friend bool operator==(text_style_impl const&, text_style_impl const&) noexcept = default;
155};
156
157} // namespace hi::inline v1::detail
158
159template<>
160struct std::hash<hi::detail::text_style_impl> {
161 [[nodiscard]] size_t operator()(hi::detail::text_style_impl const& rhs) const noexcept
162 {
163 return rhs.hash();
164 }
165};
166
167namespace hi::inline v1 {
168namespace detail {
169inline auto text_styles = stable_set<text_style_impl>{};
170}
171
173public:
174 using int_type = uint16_t;
175
176 constexpr text_style() : _value(0xffff) {}
177 constexpr text_style(text_style const&) noexcept = default;
178 constexpr text_style(text_style&&) noexcept = default;
179 constexpr text_style& operator=(text_style const&) noexcept = default;
180 constexpr text_style& operator=(text_style&&) noexcept = default;
181 [[nodiscard]] constexpr friend bool operator==(text_style const&, text_style const&) noexcept = default;
182
183 constexpr text_style(semantic_text_style rhs) noexcept : _value(0xff00 + std::to_underlying(rhs)) {}
184
186 {
187 hilet index = detail::text_styles.emplace(std::move(rhs));
188 if (index < 0xff00) {
189 _value = narrow_cast<uint16_t>(index);
190 } else {
191 hi_log_error_once("text-style:error:too-many", "Too many text-styles");
192 // semantic text-style "label".
193 _value = 0xff00;
194 }
195 }
196
197 [[nodiscard]] constexpr bool empty() const noexcept
198 {
199 return _value == 0xffff;
200 }
201
202 constexpr explicit operator bool() const noexcept
203 {
204 return not empty();
205 }
206
207 [[nodiscard]] constexpr bool is_semantic() const noexcept
208 {
209 hi_assert(not empty());
210 return _value >= 0xff00;
211 }
212
213 constexpr explicit operator semantic_text_style() const noexcept
214 {
215 return static_cast<semantic_text_style>(narrow_cast<std::underlying_type_t<semantic_text_style>>(_value - 0xff00));
216 }
217
218 text_sub_style const *operator->() const noexcept
219 {
220 hi_axiom(not empty());
221 if (_value < 0xff00) {
222 return std::addressof(detail::text_styles[_value].back());
223 } else {
225 }
226 }
227
228 text_sub_style const& operator*() const noexcept
229 {
230 hi_axiom(not empty());
231 if (_value < 0xff00) {
232 return detail::text_styles[_value].back();
233 } else {
235 }
236 }
237
238 text_sub_style const& sub_style(phrasing phrasing, iso_639 language, iso_15924 script) const noexcept
239 {
240 for (hilet& style : detail::text_styles[_value]) {
241 if (style.matches(phrasing, language, script)) {
242 return style;
243 }
244 }
245 }
246
247private:
248 int_type _value;
249};
250
251} // namespace hi::inline v1
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:199
#define hi_not_implemented(...)
This part of the code has not been implemented yet.
Definition assert.hpp:335
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
phrasing
Phrasing.
Definition phrasing.hpp:27
DOXYGEN BUG.
Definition algorithm.hpp:13
text_decoration
Describes how a grapheme should be underlined when rendering the text.
Definition text_decoration.hpp:20
constexpr bool matches(phrasing_mask const &lhs, phrasing const &rhs) noexcept
Check if the text-phrasing is included in the text-phrasing-mask.
Definition phrasing.hpp:224
geometry/margins.hpp
Definition cache.hpp:11
This is a RGBA floating point color.
Definition color.hpp:42
font_book keeps track of multiple fonts.
Definition font_book.hpp:31
A font variant is one of 16 different fonts that can be part of a family.
Definition font_variant.hpp:16
ISO-15924 script code.
Definition iso_15924.hpp:17
ISO-639 language code.
Definition iso_639.hpp:23
Definition text_style.hpp:23
Definition text_style.hpp:102
Definition text_style.hpp:172
Definition concepts.hpp:39
T addressof(T... args)
T back(T... args)
T begin(T... args)
T empty(T... args)
T end(T... args)
T move(T... args)
T operator()(T... args)