1#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5use core::ops::Range;
6use rangemap::RangeMap;
7use smol_str::SmolStr;
8
9use crate::{CacheKeyFlags, Metrics};
10
11pub use fontdb::{Family, Stretch, Style, Weight};
12
13#[derive(Clone, Copy, Debug, PartialOrd, Ord, Eq, Hash, PartialEq)]
15pub struct Color(pub u32);
16
17impl Color {
18 #[inline]
20 pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
21 Self::rgba(r, g, b, 0xFF)
22 }
23
24 #[inline]
26 pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
27 Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
28 }
29
30 #[inline]
32 pub fn as_rgba_tuple(self) -> (u8, u8, u8, u8) {
33 (self.r(), self.g(), self.b(), self.a())
34 }
35
36 #[inline]
38 pub fn as_rgba(self) -> [u8; 4] {
39 [self.r(), self.g(), self.b(), self.a()]
40 }
41
42 #[inline]
44 pub fn r(&self) -> u8 {
45 ((self.0 & 0x00_FF_00_00) >> 16) as u8
46 }
47
48 #[inline]
50 pub fn g(&self) -> u8 {
51 ((self.0 & 0x00_00_FF_00) >> 8) as u8
52 }
53
54 #[inline]
56 pub fn b(&self) -> u8 {
57 (self.0 & 0x00_00_00_FF) as u8
58 }
59
60 #[inline]
62 pub fn a(&self) -> u8 {
63 ((self.0 & 0xFF_00_00_00) >> 24) as u8
64 }
65}
66
67#[derive(Clone, Debug, Eq, Hash, PartialEq)]
69pub enum FamilyOwned {
70 Name(SmolStr),
71 Serif,
72 SansSerif,
73 Cursive,
74 Fantasy,
75 Monospace,
76}
77
78impl FamilyOwned {
79 pub fn new(family: Family) -> Self {
80 match family {
81 Family::Name(name) => FamilyOwned::Name(SmolStr::from(name)),
82 Family::Serif => FamilyOwned::Serif,
83 Family::SansSerif => FamilyOwned::SansSerif,
84 Family::Cursive => FamilyOwned::Cursive,
85 Family::Fantasy => FamilyOwned::Fantasy,
86 Family::Monospace => FamilyOwned::Monospace,
87 }
88 }
89
90 pub fn as_family(&self) -> Family {
91 match self {
92 FamilyOwned::Name(name) => Family::Name(name),
93 FamilyOwned::Serif => Family::Serif,
94 FamilyOwned::SansSerif => Family::SansSerif,
95 FamilyOwned::Cursive => Family::Cursive,
96 FamilyOwned::Fantasy => Family::Fantasy,
97 FamilyOwned::Monospace => Family::Monospace,
98 }
99 }
100}
101
102#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
105pub struct CacheMetrics {
106 font_size_bits: u32,
107 line_height_bits: u32,
108}
109
110impl From<Metrics> for CacheMetrics {
111 fn from(metrics: Metrics) -> Self {
112 Self {
113 font_size_bits: metrics.font_size.to_bits(),
114 line_height_bits: metrics.line_height.to_bits(),
115 }
116 }
117}
118
119impl From<CacheMetrics> for Metrics {
120 fn from(metrics: CacheMetrics) -> Self {
121 Self {
122 font_size: f32::from_bits(metrics.font_size_bits),
123 line_height: f32::from_bits(metrics.line_height_bits),
124 }
125 }
126}
127
128#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
130pub struct Attrs<'a> {
131 pub color_opt: Option<Color>,
133 pub family: Family<'a>,
134 pub stretch: Stretch,
135 pub style: Style,
136 pub weight: Weight,
137 pub metadata: usize,
138 pub cache_key_flags: CacheKeyFlags,
139 pub metrics_opt: Option<CacheMetrics>,
140}
141
142impl<'a> Attrs<'a> {
143 pub fn new() -> Self {
147 Self {
148 color_opt: None,
149 family: Family::SansSerif,
150 stretch: Stretch::Normal,
151 style: Style::Normal,
152 weight: Weight::NORMAL,
153 metadata: 0,
154 cache_key_flags: CacheKeyFlags::empty(),
155 metrics_opt: None,
156 }
157 }
158
159 pub fn color(mut self, color: Color) -> Self {
161 self.color_opt = Some(color);
162 self
163 }
164
165 pub fn family(mut self, family: Family<'a>) -> Self {
167 self.family = family;
168 self
169 }
170
171 pub fn stretch(mut self, stretch: Stretch) -> Self {
173 self.stretch = stretch;
174 self
175 }
176
177 pub fn style(mut self, style: Style) -> Self {
179 self.style = style;
180 self
181 }
182
183 pub fn weight(mut self, weight: Weight) -> Self {
185 self.weight = weight;
186 self
187 }
188
189 pub fn metadata(mut self, metadata: usize) -> Self {
191 self.metadata = metadata;
192 self
193 }
194
195 pub fn cache_key_flags(mut self, cache_key_flags: CacheKeyFlags) -> Self {
197 self.cache_key_flags = cache_key_flags;
198 self
199 }
200
201 pub fn metrics(mut self, metrics: Metrics) -> Self {
203 self.metrics_opt = Some(metrics.into());
204 self
205 }
206
207 pub fn matches(&self, face: &fontdb::FaceInfo) -> bool {
209 face.post_script_name.contains("Emoji")
211 || (face.style == self.style && face.stretch == self.stretch)
212 }
213
214 pub fn compatible(&self, other: &Self) -> bool {
216 self.family == other.family
217 && self.stretch == other.stretch
218 && self.style == other.style
219 && self.weight == other.weight
220 }
221}
222
223#[derive(Clone, Debug, Eq, Hash, PartialEq)]
225pub struct FontMatchAttrs {
226 family: FamilyOwned,
227 stretch: Stretch,
228 style: Style,
229 weight: Weight,
230}
231
232impl<'a> From<Attrs<'a>> for FontMatchAttrs {
233 fn from(attrs: Attrs<'a>) -> Self {
234 Self {
235 family: FamilyOwned::new(attrs.family),
236 stretch: attrs.stretch,
237 style: attrs.style,
238 weight: attrs.weight,
239 }
240 }
241}
242
243#[derive(Clone, Debug, Eq, Hash, PartialEq)]
245pub struct AttrsOwned {
246 pub color_opt: Option<Color>,
248 pub family_owned: FamilyOwned,
249 pub stretch: Stretch,
250 pub style: Style,
251 pub weight: Weight,
252 pub metadata: usize,
253 pub cache_key_flags: CacheKeyFlags,
254 pub metrics_opt: Option<CacheMetrics>,
255}
256
257impl AttrsOwned {
258 pub fn new(attrs: Attrs) -> Self {
259 Self {
260 color_opt: attrs.color_opt,
261 family_owned: FamilyOwned::new(attrs.family),
262 stretch: attrs.stretch,
263 style: attrs.style,
264 weight: attrs.weight,
265 metadata: attrs.metadata,
266 cache_key_flags: attrs.cache_key_flags,
267 metrics_opt: attrs.metrics_opt,
268 }
269 }
270
271 pub fn as_attrs(&self) -> Attrs {
272 Attrs {
273 color_opt: self.color_opt,
274 family: self.family_owned.as_family(),
275 stretch: self.stretch,
276 style: self.style,
277 weight: self.weight,
278 metadata: self.metadata,
279 cache_key_flags: self.cache_key_flags,
280 metrics_opt: self.metrics_opt,
281 }
282 }
283}
284
285#[derive(Debug, Clone, Eq, PartialEq)]
288pub struct AttrsList {
289 defaults: AttrsOwned,
290 pub(crate) spans: RangeMap<usize, AttrsOwned>,
291}
292
293impl AttrsList {
294 pub fn new(defaults: Attrs) -> Self {
296 Self {
297 defaults: AttrsOwned::new(defaults),
298 spans: RangeMap::new(),
299 }
300 }
301
302 pub fn defaults(&self) -> Attrs {
304 self.defaults.as_attrs()
305 }
306
307 pub fn spans(&self) -> Vec<(&Range<usize>, &AttrsOwned)> {
309 self.spans_iter().collect()
310 }
311
312 pub fn spans_iter(&self) -> impl Iterator<Item = (&Range<usize>, &AttrsOwned)> + '_ {
314 self.spans.iter()
315 }
316
317 pub fn clear_spans(&mut self) {
319 self.spans.clear();
320 }
321
322 pub fn add_span(&mut self, range: Range<usize>, attrs: Attrs) {
324 if range.is_empty() {
326 return;
327 }
328
329 self.spans.insert(range, AttrsOwned::new(attrs));
330 }
331
332 pub fn get_span(&self, index: usize) -> Attrs {
336 self.spans
337 .get(&index)
338 .map(|v| v.as_attrs())
339 .unwrap_or(self.defaults.as_attrs())
340 }
341
342 #[allow(clippy::missing_panics_doc)]
344 pub fn split_off(&mut self, index: usize) -> Self {
345 let mut new = Self::new(self.defaults.as_attrs());
346 let mut removes = Vec::new();
347
348 for span in self.spans.iter() {
350 if span.0.end <= index {
351 continue;
352 } else if span.0.start >= index {
353 removes.push((span.0.clone(), false));
354 } else {
355 removes.push((span.0.clone(), true));
356 }
357 }
358
359 for (key, resize) in removes {
360 let (range, attrs) = self
361 .spans
362 .get_key_value(&key.start)
363 .map(|v| (v.0.clone(), v.1.clone()))
364 .expect("attrs span not found");
365 self.spans.remove(key);
366
367 if resize {
368 new.spans.insert(0..range.end - index, attrs.clone());
369 self.spans.insert(range.start..index, attrs);
370 } else {
371 new.spans
372 .insert(range.start - index..range.end - index, attrs);
373 }
374 }
375 new
376 }
377
378 pub(crate) fn reset(mut self, default: Attrs) -> Self {
380 self.defaults = AttrsOwned::new(default);
381 self.spans.clear();
382 self
383 }
384}