HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
font_glyph_ids.hpp
1// Copyright Take Vos 2020-2021.
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 "glyph_id.hpp"
8#include "../hash.hpp"
9#include "../tagged_id.hpp"
10#include "../geometry/axis_aligned_rectangle.hpp"
11#include "../architecture.hpp"
12#include <tuple>
13
14namespace tt {
15struct graphic_path;
16class font;
17
18// "Compatibility mappings are guaranteed to be no longer than 18 characters, although most consist of just a few characters."
19// https://unicode.org/reports/tr44/ (TR44 5.7.3)
21 int8_t nr_glyphs = 0;
23
24 font_glyph_ids_long() noexcept = delete;
25 font_glyph_ids_long(font_glyph_ids_long const &rhs) noexcept = default;
26 font_glyph_ids_long(font_glyph_ids_long &&rhs) noexcept = default;
27 font_glyph_ids_long &operator=(font_glyph_ids_long const &rhs) noexcept = default;
28 font_glyph_ids_long &operator=(font_glyph_ids_long &&rhs) noexcept = default;
29
31 {
32 (*this) += g1;
33 (*this) += g2;
34 (*this) += g3;
35 }
36
37 font_glyph_ids_long operator+=(glyph_id rhs) noexcept
38 {
39 tt_axiom(nr_glyphs >= 0);
40 tt_axiom(nr_glyphs < std::ssize(glyph_ids));
41 glyph_ids[nr_glyphs++] = rhs;
42 return *this;
43 }
44
45 [[nodiscard]] size_t hash() const noexcept
46 {
47 tt_axiom(nr_glyphs > 3);
48 tt_axiom(nr_glyphs < std::ssize(glyph_ids));
49
50 uint64_t r = 0;
51 for (int8_t i = 0; i != nr_glyphs; ++i) {
52 r = hash_mix_two(r, std::hash<glyph_id>{}(glyph_ids[i]));
53 }
54
55 return r;
56 }
57
58 [[nodiscard]] friend bool operator==(font_glyph_ids_long const &lhs, font_glyph_ids_long const &rhs) noexcept
59 {
60 tt_axiom(lhs.nr_glyphs > 3);
61 tt_axiom(rhs.nr_glyphs > 3);
62 tt_axiom(lhs.nr_glyphs < std::ssize(lhs.glyph_ids));
63 tt_axiom(rhs.nr_glyphs < std::ssize(rhs.glyph_ids));
64
65 if (lhs.nr_glyphs == rhs.nr_glyphs) {
66 for (int8_t i = 0; i != lhs.nr_glyphs; ++i) {
67 if (lhs.glyph_ids[i] != rhs.glyph_ids[i]) {
68 return false;
69 }
70 }
71 return true;
72 } else {
73 return false;
74 }
75 }
76
77 friend class font_glyph_ids;
78};
79
81public:
82 constexpr font_glyph_ids() noexcept : _font(nullptr)
83 {
84 _glyphs.ids_short = ids_short_empty;
85 }
86
87 constexpr font_glyph_ids(tt::font const &font) noexcept : _font(&font)
88 {
89 _glyphs.ids_short = ids_short_empty;
90 }
91
92 font_glyph_ids(font_glyph_ids const &other) noexcept : _font(other._font)
93 {
94 if (other.is_long()) {
95 _glyphs.ids_long = new font_glyph_ids_long(*other._glyphs.ids_long);
96 } else {
97 _glyphs.ids_short = other._glyphs.ids_short;
98 }
99 }
100
101 font_glyph_ids(font_glyph_ids &&other) noexcept : _font(other._font), _glyphs(other._glyphs)
102 {
103 other._glyphs.ids_short = ids_short_empty;
104 }
105
106 font_glyph_ids &operator=(font_glyph_ids const &other) noexcept
107 {
108 tt_return_on_self_assignment(other);
109
110 if (is_long()) {
111 delete _glyphs.ids_long;
112 }
113
114 _font = other._font;
115 if (other.is_long()) {
116 _glyphs.ids_long = new font_glyph_ids_long(*other._glyphs.ids_long);
117 } else {
118 _glyphs.ids_short = other._glyphs.ids_short;
119 }
120
121 return *this;
122 }
123
124 font_glyph_ids &operator=(font_glyph_ids &&other) noexcept
125 {
126 using std::swap;
127
128 swap(_font, other._font);
129 swap(_glyphs, other._glyphs);
130 return *this;
131 }
132
133 ~font_glyph_ids() noexcept
134 {
135 if (is_long()) {
136 delete _glyphs.ids_long;
137 }
138 }
139
140 void clear() noexcept
141 {
142 if (is_long()) {
143 delete _glyphs.ids_long;
144 }
145 _glyphs.ids_short = ids_short_empty;
146 }
147
148 operator bool() const noexcept
149 {
150 return size() > 0;
151 }
152
153 [[nodiscard]] font const &font() const noexcept
154 {
155 tt_axiom(_font);
156 return *_font;
157 }
158
159 void set_font(tt::font const &font) noexcept
160 {
161 _font = &font;
162 }
163
164 font_glyph_ids &operator+=(glyph_id rhs) noexcept
165 {
166 switch (size()) {
167 case 0: _glyphs.ids_short = (_glyphs.ids_short & 0xffff'ffff'0000'0000) | (uint64_t{rhs} << 16) | 1; break;
168 case 1: _glyphs.ids_short = (_glyphs.ids_short & 0xffff'0000'ffff'0000) | (uint64_t{rhs} << 32) | 2; break;
169 case 2: _glyphs.ids_short = (_glyphs.ids_short & 0x0000'ffff'ffff'0000) | (uint64_t{rhs} << 48) | 3; break;
170 case 3: _glyphs.ids_long = new font_glyph_ids_long((*this)[0], (*this)[1], (*this)[2]); [[fallthrough]];
171 default: *_glyphs.ids_long += rhs;
172 }
173 return *this;
174 }
175
176 [[nodiscard]] glyph_id front() const noexcept
177 {
178 if (size() == 0) {
179 return glyph_id{};
180 } else {
181 return (*this)[0];
182 }
183 }
184
185 [[nodiscard]] glyph_id operator[](size_t index) const noexcept
186 {
187 tt_axiom(index < size());
188 if (is_long()) {
189 tt_axiom(index < 18);
190 return _glyphs.ids_long->glyph_ids[index];
191 } else {
192 switch (index) {
193 case 0: return glyph_id{(_glyphs.ids_short >> 16) & glyph_id::mask};
194 case 1: return glyph_id{(_glyphs.ids_short >> 32) & glyph_id::mask};
195 case 2: return glyph_id{(_glyphs.ids_short >> 48) & glyph_id::mask};
196 default: tt_no_default();
197 }
198 }
199 }
200
201 [[nodiscard]] size_t size() const noexcept
202 {
203 if (is_long()) {
204 return _glyphs.ids_long->nr_glyphs;
205 } else if ((_glyphs.ids_short & 7) == 3) {
206 return 3;
207 } else if ((_glyphs.ids_short & 7) == 2) {
208 return 2;
209 } else if ((_glyphs.ids_short & 7) == 1) {
210 return 1;
211 } else {
212 return 0;
213 }
214 }
215
216 [[nodiscard]] size_t hash() const noexcept
217 {
218 if (is_long()) {
219 return _glyphs.ids_long->hash();
220 } else {
221 return std::hash<uint64_t>{}(_glyphs.ids_short);
222 }
223 }
224
225 [[nodiscard]] std::pair<graphic_path, aarectangle> get_path_and_bounding_box() const noexcept;
226 [[nodiscard]] aarectangle get_bounding_box() const noexcept;
227
228 [[nodiscard]] friend bool operator==(font_glyph_ids const &lhs, font_glyph_ids const &rhs) noexcept
229 {
230 if (lhs._font == rhs._font and lhs.is_long() == rhs.is_long()) {
231 if (lhs.is_long()) {
232 return *lhs._glyphs.ids_long == *rhs._glyphs.ids_long;
233 } else {
234 return lhs._glyphs.ids_short == rhs._glyphs.ids_short;
235 }
236 } else {
237 return false;
238 }
239 }
240
241private:
242 static constexpr uint64_t ids_short_empty = 4;
243
244 tt::font const *_font;
245
246 union {
247 font_glyph_ids_long *ids_long;
248
249 static_assert(sizeof(ids_long) == 8);
250
258 uint64_t ids_short;
259 } _glyphs;
260
261 [[nodiscard]] bool is_long() const noexcept
262 {
263 uint64_t tmp = std::bit_cast<uint64_t>(_glyphs);
264 // Pointers have the bottom 3 bits zero.
265 return (tmp & 0x7) == 0;
266 }
267};
268
269} // namespace tt
270
271namespace std {
272
273template<>
274struct hash<tt::font_glyph_ids> {
275 [[nodiscard]] size_t operator()(tt::font_glyph_ids const &rhs) const noexcept
276 {
277 return rhs.hash();
278 }
279};
280
281} // namespace std
STL namespace.
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:20
Definition tagged_id.hpp:18
Definition font.hpp:28
Definition font_glyph_ids.hpp:20
Definition font_glyph_ids.hpp:80
uint64_t ids_short
A list of up to 3 glyphs.
Definition font_glyph_ids.hpp:258
T operator()(T... args)
T swap(T... args)