1#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5use core::hash::{Hash, Hasher};
6use core::ops::Range;
7use rangemap::RangeMap;
8use smol_str::SmolStr;
9
10use crate::{CacheKeyFlags, Metrics};
11
12pub use fontdb::{Family, Stretch, Style, Weight};
13
14#[derive(Clone, Copy, Debug, PartialOrd, Ord, Eq, Hash, PartialEq)]
16pub struct Color(pub u32);
17
18impl Color {
19 #[inline]
21 pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
22 Self::rgba(r, g, b, 0xFF)
23 }
24
25 #[inline]
27 pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
28 Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
29 }
30
31 #[inline]
33 pub fn as_rgba_tuple(self) -> (u8, u8, u8, u8) {
34 (self.r(), self.g(), self.b(), self.a())
35 }
36
37 #[inline]
39 pub fn as_rgba(self) -> [u8; 4] {
40 [self.r(), self.g(), self.b(), self.a()]
41 }
42
43 #[inline]
45 pub fn r(&self) -> u8 {
46 ((self.0 & 0x00_FF_00_00) >> 16) as u8
47 }
48
49 #[inline]
51 pub fn g(&self) -> u8 {
52 ((self.0 & 0x00_00_FF_00) >> 8) as u8
53 }
54
55 #[inline]
57 pub fn b(&self) -> u8 {
58 (self.0 & 0x00_00_00_FF) as u8
59 }
60
61 #[inline]
63 pub fn a(&self) -> u8 {
64 ((self.0 & 0xFF_00_00_00) >> 24) as u8
65 }
66}
67
68#[derive(Clone, Debug, Eq, Hash, PartialEq)]
70pub enum FamilyOwned {
71 Name(SmolStr),
72 Serif,
73 SansSerif,
74 Cursive,
75 Fantasy,
76 Monospace,
77}
78
79impl FamilyOwned {
80 pub fn new(family: Family) -> Self {
81 match family {
82 Family::Name(name) => FamilyOwned::Name(SmolStr::from(name)),
83 Family::Serif => FamilyOwned::Serif,
84 Family::SansSerif => FamilyOwned::SansSerif,
85 Family::Cursive => FamilyOwned::Cursive,
86 Family::Fantasy => FamilyOwned::Fantasy,
87 Family::Monospace => FamilyOwned::Monospace,
88 }
89 }
90
91 pub fn as_family(&self) -> Family {
92 match self {
93 FamilyOwned::Name(name) => Family::Name(name),
94 FamilyOwned::Serif => Family::Serif,
95 FamilyOwned::SansSerif => Family::SansSerif,
96 FamilyOwned::Cursive => Family::Cursive,
97 FamilyOwned::Fantasy => Family::Fantasy,
98 FamilyOwned::Monospace => Family::Monospace,
99 }
100 }
101}
102
103#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
106pub struct CacheMetrics {
107 font_size_bits: u32,
108 line_height_bits: u32,
109}
110
111impl From<Metrics> for CacheMetrics {
112 fn from(metrics: Metrics) -> Self {
113 Self {
114 font_size_bits: metrics.font_size.to_bits(),
115 line_height_bits: metrics.line_height.to_bits(),
116 }
117 }
118}
119
120impl From<CacheMetrics> for Metrics {
121 fn from(metrics: CacheMetrics) -> Self {
122 Self {
123 font_size: f32::from_bits(metrics.font_size_bits),
124 line_height: f32::from_bits(metrics.line_height_bits),
125 }
126 }
127}
128#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
130pub struct FeatureTag([u8; 4]);
131
132impl FeatureTag {
133 pub const fn new(tag: &[u8; 4]) -> Self {
134 Self(*tag)
135 }
136
137 pub const KERNING: Self = Self::new(b"kern");
139 pub const STANDARD_LIGATURES: Self = Self::new(b"liga");
141 pub const CONTEXTUAL_LIGATURES: Self = Self::new(b"clig");
143 pub const CONTEXTUAL_ALTERNATES: Self = Self::new(b"calt");
145 pub const DISCRETIONARY_LIGATURES: Self = Self::new(b"dlig");
147 pub const SMALL_CAPS: Self = Self::new(b"smcp");
149 pub const ALL_SMALL_CAPS: Self = Self::new(b"c2sc");
151 pub const STYLISTIC_SET_1: Self = Self::new(b"ss01");
153 pub const STYLISTIC_SET_2: Self = Self::new(b"ss02");
155
156 pub fn as_bytes(&self) -> &[u8; 4] {
157 &self.0
158 }
159}
160
161#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
162pub struct Feature {
163 pub tag: FeatureTag,
164 pub value: u32,
165}
166
167#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
168pub struct FontFeatures {
169 pub features: Vec<Feature>,
170}
171
172impl FontFeatures {
173 pub fn new() -> Self {
174 Self {
175 features: Vec::new(),
176 }
177 }
178
179 pub fn set(&mut self, tag: FeatureTag, value: u32) -> &mut Self {
180 self.features.push(Feature { tag, value });
181 self
182 }
183
184 pub fn enable(&mut self, tag: FeatureTag) -> &mut Self {
186 self.set(tag, 1)
187 }
188
189 pub fn disable(&mut self, tag: FeatureTag) -> &mut Self {
191 self.set(tag, 0)
192 }
193}
194
195#[derive(Clone, Copy, Debug)]
197pub struct LetterSpacing(pub f32);
198
199impl PartialEq for LetterSpacing {
200 fn eq(&self, other: &Self) -> bool {
201 if self.0.is_nan() {
202 other.0.is_nan()
203 } else {
204 self.0 == other.0
205 }
206 }
207}
208
209impl Eq for LetterSpacing {}
210
211impl Hash for LetterSpacing {
212 fn hash<H: Hasher>(&self, hasher: &mut H) {
213 const CANONICAL_NAN_BITS: u32 = 0x7fc0_0000;
214
215 let bits = if self.0.is_nan() {
216 CANONICAL_NAN_BITS
217 } else {
218 (self.0 + 0.0).to_bits()
220 };
221
222 bits.hash(hasher);
223 }
224}
225
226#[derive(Clone, Debug, Eq, Hash, PartialEq)]
228pub struct Attrs<'a> {
229 pub color_opt: Option<Color>,
231 pub family: Family<'a>,
232 pub stretch: Stretch,
233 pub style: Style,
234 pub weight: Weight,
235 pub metadata: usize,
236 pub cache_key_flags: CacheKeyFlags,
237 pub metrics_opt: Option<CacheMetrics>,
238 pub letter_spacing_opt: Option<LetterSpacing>,
240 pub font_features: FontFeatures,
241}
242
243impl<'a> Attrs<'a> {
244 pub fn new() -> Self {
248 Self {
249 color_opt: None,
250 family: Family::SansSerif,
251 stretch: Stretch::Normal,
252 style: Style::Normal,
253 weight: Weight::NORMAL,
254 metadata: 0,
255 cache_key_flags: CacheKeyFlags::empty(),
256 metrics_opt: None,
257 letter_spacing_opt: None,
258 font_features: FontFeatures::new(),
259 }
260 }
261
262 pub fn color(mut self, color: Color) -> Self {
264 self.color_opt = Some(color);
265 self
266 }
267
268 pub fn family(mut self, family: Family<'a>) -> Self {
270 self.family = family;
271 self
272 }
273
274 pub fn stretch(mut self, stretch: Stretch) -> Self {
276 self.stretch = stretch;
277 self
278 }
279
280 pub fn style(mut self, style: Style) -> Self {
282 self.style = style;
283 self
284 }
285
286 pub fn weight(mut self, weight: Weight) -> Self {
288 self.weight = weight;
289 self
290 }
291
292 pub fn metadata(mut self, metadata: usize) -> Self {
294 self.metadata = metadata;
295 self
296 }
297
298 pub fn cache_key_flags(mut self, cache_key_flags: CacheKeyFlags) -> Self {
300 self.cache_key_flags = cache_key_flags;
301 self
302 }
303
304 pub fn metrics(mut self, metrics: Metrics) -> Self {
306 self.metrics_opt = Some(metrics.into());
307 self
308 }
309
310 pub fn letter_spacing(mut self, letter_spacing: f32) -> Self {
312 self.letter_spacing_opt = Some(LetterSpacing(letter_spacing));
313 self
314 }
315
316 pub fn font_features(mut self, font_features: FontFeatures) -> Self {
318 self.font_features = font_features;
319 self
320 }
321
322 pub fn matches(&self, face: &fontdb::FaceInfo) -> bool {
324 face.post_script_name.contains("Emoji")
326 || (face.style == self.style && face.stretch == self.stretch)
327 }
328
329 pub fn compatible(&self, other: &Self) -> bool {
331 self.family == other.family
332 && self.stretch == other.stretch
333 && self.style == other.style
334 && self.weight == other.weight
335 }
336}
337
338#[derive(Clone, Debug, Eq, Hash, PartialEq)]
340pub struct FontMatchAttrs {
341 family: FamilyOwned,
342 stretch: Stretch,
343 style: Style,
344 weight: Weight,
345}
346
347impl<'a> From<&Attrs<'a>> for FontMatchAttrs {
348 fn from(attrs: &Attrs<'a>) -> Self {
349 Self {
350 family: FamilyOwned::new(attrs.family),
351 stretch: attrs.stretch,
352 style: attrs.style,
353 weight: attrs.weight,
354 }
355 }
356}
357
358#[derive(Clone, Debug, Eq, Hash, PartialEq)]
360pub struct AttrsOwned {
361 pub color_opt: Option<Color>,
363 pub family_owned: FamilyOwned,
364 pub stretch: Stretch,
365 pub style: Style,
366 pub weight: Weight,
367 pub metadata: usize,
368 pub cache_key_flags: CacheKeyFlags,
369 pub metrics_opt: Option<CacheMetrics>,
370 pub letter_spacing_opt: Option<LetterSpacing>,
372 pub font_features: FontFeatures,
373}
374
375impl AttrsOwned {
376 pub fn new(attrs: &Attrs) -> Self {
377 Self {
378 color_opt: attrs.color_opt,
379 family_owned: FamilyOwned::new(attrs.family),
380 stretch: attrs.stretch,
381 style: attrs.style,
382 weight: attrs.weight,
383 metadata: attrs.metadata,
384 cache_key_flags: attrs.cache_key_flags,
385 metrics_opt: attrs.metrics_opt,
386 letter_spacing_opt: attrs.letter_spacing_opt,
387 font_features: attrs.font_features.clone(),
388 }
389 }
390
391 pub fn as_attrs(&self) -> Attrs {
392 Attrs {
393 color_opt: self.color_opt,
394 family: self.family_owned.as_family(),
395 stretch: self.stretch,
396 style: self.style,
397 weight: self.weight,
398 metadata: self.metadata,
399 cache_key_flags: self.cache_key_flags,
400 metrics_opt: self.metrics_opt,
401 letter_spacing_opt: self.letter_spacing_opt,
402 font_features: self.font_features.clone(),
403 }
404 }
405}
406
407#[derive(Debug, Clone, Eq, PartialEq)]
410pub struct AttrsList {
411 defaults: AttrsOwned,
412 pub(crate) spans: RangeMap<usize, AttrsOwned>,
413}
414
415impl AttrsList {
416 pub fn new(defaults: &Attrs) -> Self {
418 Self {
419 defaults: AttrsOwned::new(defaults),
420 spans: RangeMap::new(),
421 }
422 }
423
424 pub fn defaults(&self) -> Attrs {
426 self.defaults.as_attrs()
427 }
428
429 pub fn spans(&self) -> Vec<(&Range<usize>, &AttrsOwned)> {
431 self.spans_iter().collect()
432 }
433
434 pub fn spans_iter(&self) -> impl Iterator<Item = (&Range<usize>, &AttrsOwned)> + '_ {
436 self.spans.iter()
437 }
438
439 pub fn clear_spans(&mut self) {
441 self.spans.clear();
442 }
443
444 pub fn add_span(&mut self, range: Range<usize>, attrs: &Attrs) {
446 if range.is_empty() {
448 return;
449 }
450
451 self.spans.insert(range, AttrsOwned::new(attrs));
452 }
453
454 pub fn get_span(&self, index: usize) -> Attrs {
458 self.spans
459 .get(&index)
460 .map(|v| v.as_attrs())
461 .unwrap_or(self.defaults.as_attrs())
462 }
463
464 #[allow(clippy::missing_panics_doc)]
466 pub fn split_off(&mut self, index: usize) -> Self {
467 let mut new = Self::new(&self.defaults.as_attrs());
468 let mut removes = Vec::new();
469
470 for span in self.spans.iter() {
472 if span.0.end <= index {
473 continue;
474 } else if span.0.start >= index {
475 removes.push((span.0.clone(), false));
476 } else {
477 removes.push((span.0.clone(), true));
478 }
479 }
480
481 for (key, resize) in removes {
482 let (range, attrs) = self
483 .spans
484 .get_key_value(&key.start)
485 .map(|v| (v.0.clone(), v.1.clone()))
486 .expect("attrs span not found");
487 self.spans.remove(key);
488
489 if resize {
490 new.spans.insert(0..range.end - index, attrs.clone());
491 self.spans.insert(range.start..index, attrs);
492 } else {
493 new.spans
494 .insert(range.start - index..range.end - index, attrs);
495 }
496 }
497 new
498 }
499
500 pub(crate) fn reset(mut self, default: &Attrs) -> Self {
502 self.defaults = AttrsOwned::new(default);
503 self.spans.clear();
504 self
505 }
506}