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