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 const fn as_rgba_tuple(self) -> (u8, u8, u8, u8) {
34 (self.r(), self.g(), self.b(), self.a())
35 }
36
37 #[inline]
39 pub const fn as_rgba(self) -> [u8; 4] {
40 [self.r(), self.g(), self.b(), self.a()]
41 }
42
43 #[inline]
45 pub const fn r(&self) -> u8 {
46 ((self.0 & 0x00_FF_00_00) >> 16) as u8
47 }
48
49 #[inline]
51 pub const fn g(&self) -> u8 {
52 ((self.0 & 0x00_00_FF_00) >> 8) as u8
53 }
54
55 #[inline]
57 pub const fn b(&self) -> u8 {
58 (self.0 & 0x00_00_00_FF) as u8
59 }
60
61 #[inline]
63 pub const 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) => Self::Name(SmolStr::from(name)),
83 Family::Serif => Self::Serif,
84 Family::SansSerif => Self::SansSerif,
85 Family::Cursive => Self::Cursive,
86 Family::Fantasy => Self::Fantasy,
87 Family::Monospace => Self::Monospace,
88 }
89 }
90
91 pub fn as_family(&self) -> Family<'_> {
92 match self {
93 Self::Name(name) => Family::Name(name),
94 Self::Serif => Family::Serif,
95 Self::SansSerif => Family::SansSerif,
96 Self::Cursive => Family::Cursive,
97 Self::Fantasy => Family::Fantasy,
98 Self::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, Ord, PartialEq, PartialOrd)]
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 const 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 features: Vec<Feature>,
170}
171
172impl FontFeatures {
173 pub const fn new() -> Self {
174 Self {
175 features: Vec::new(),
176 }
177 }
178
179 pub fn iter(&self) -> impl Iterator<Item = &Feature> {
180 self.features.iter()
181 }
182
183 pub fn set(&mut self, tag: FeatureTag, value: u32) -> &mut Self {
187 match self
188 .features
189 .binary_search_by_key(&tag, |feature| feature.tag)
190 {
191 Ok(index) => self.features[index].value = value,
192 Err(index) => self.features.insert(index, Feature { tag, value }),
193 }
194 self
195 }
196
197 pub fn enable(&mut self, tag: FeatureTag) -> &mut Self {
199 self.set(tag, 1)
200 }
201
202 pub fn disable(&mut self, tag: FeatureTag) -> &mut Self {
204 self.set(tag, 0)
205 }
206}
207
208#[derive(Clone, Copy, Debug)]
210pub struct LetterSpacing(pub f32);
211
212impl PartialEq for LetterSpacing {
213 fn eq(&self, other: &Self) -> bool {
214 if self.0.is_nan() {
215 other.0.is_nan()
216 } else {
217 self.0 == other.0
218 }
219 }
220}
221
222impl Eq for LetterSpacing {}
223
224impl Hash for LetterSpacing {
225 fn hash<H: Hasher>(&self, hasher: &mut H) {
226 const CANONICAL_NAN_BITS: u32 = 0x7fc0_0000;
227
228 let bits = if self.0.is_nan() {
229 CANONICAL_NAN_BITS
230 } else {
231 (self.0 + 0.0).to_bits()
233 };
234
235 bits.hash(hasher);
236 }
237}
238
239#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
240pub enum UnderlineStyle {
241 #[default]
242 None,
243 Single,
244 Double,
245 }
247
248#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
249pub struct TextDecoration {
250 pub underline: UnderlineStyle,
251 pub underline_color_opt: Option<Color>,
252 pub strikethrough: bool,
253 pub strikethrough_color_opt: Option<Color>,
254 pub overline: bool,
255 pub overline_color_opt: Option<Color>,
256}
257
258impl TextDecoration {
259 pub const fn new() -> Self {
260 Self {
261 underline: UnderlineStyle::None,
262 underline_color_opt: None,
263 strikethrough: false,
264 strikethrough_color_opt: None,
265 overline: false,
266 overline_color_opt: None,
267 }
268 }
269
270 pub const fn has_decoration(&self) -> bool {
271 !matches!(self.underline, UnderlineStyle::None) || self.strikethrough || self.overline
272 }
273}
274
275#[derive(Clone, Copy, Debug, Default, PartialEq)]
277pub struct DecorationMetrics {
278 pub offset: f32,
280 pub thickness: f32,
282}
283
284#[derive(Clone, Debug, PartialEq)]
285pub struct GlyphDecorationData {
286 pub text_decoration: TextDecoration,
288 pub underline_metrics: DecorationMetrics,
290 pub strikethrough_metrics: DecorationMetrics,
292 pub ascent: f32,
295}
296
297#[derive(Clone, Debug, Eq, Hash, PartialEq)]
299pub struct Attrs<'a> {
300 pub color_opt: Option<Color>,
302 pub family: Family<'a>,
303 pub stretch: Stretch,
304 pub style: Style,
305 pub weight: Weight,
306 pub metadata: usize,
307 pub cache_key_flags: CacheKeyFlags,
308 pub metrics_opt: Option<CacheMetrics>,
309 pub letter_spacing_opt: Option<LetterSpacing>,
311 pub font_features: FontFeatures,
312 pub text_decoration: TextDecoration,
313}
314
315impl<'a> Attrs<'a> {
316 pub const fn new() -> Self {
320 Self {
321 color_opt: None,
322 family: Family::SansSerif,
323 stretch: Stretch::Normal,
324 style: Style::Normal,
325 weight: Weight::NORMAL,
326 metadata: 0,
327 cache_key_flags: CacheKeyFlags::empty(),
328 metrics_opt: None,
329 letter_spacing_opt: None,
330 font_features: FontFeatures::new(),
331 text_decoration: TextDecoration::new(),
332 }
333 }
334
335 pub const fn color(mut self, color: Color) -> Self {
337 self.color_opt = Some(color);
338 self
339 }
340
341 pub const fn family(mut self, family: Family<'a>) -> Self {
343 self.family = family;
344 self
345 }
346
347 pub const fn stretch(mut self, stretch: Stretch) -> Self {
349 self.stretch = stretch;
350 self
351 }
352
353 pub const fn style(mut self, style: Style) -> Self {
355 self.style = style;
356 self
357 }
358
359 pub const fn weight(mut self, weight: Weight) -> Self {
361 self.weight = weight;
362 self
363 }
364
365 pub const fn metadata(mut self, metadata: usize) -> Self {
367 self.metadata = metadata;
368 self
369 }
370
371 pub const fn cache_key_flags(mut self, cache_key_flags: CacheKeyFlags) -> Self {
373 self.cache_key_flags = cache_key_flags;
374 self
375 }
376
377 pub fn metrics(mut self, metrics: Metrics) -> Self {
379 self.metrics_opt = Some(metrics.into());
380 self
381 }
382
383 pub const fn letter_spacing(mut self, letter_spacing: f32) -> Self {
385 self.letter_spacing_opt = Some(LetterSpacing(letter_spacing));
386 self
387 }
388
389 pub fn font_features(mut self, font_features: FontFeatures) -> Self {
391 self.font_features = font_features;
392 self
393 }
394
395 pub const fn underline(mut self, style: UnderlineStyle) -> Self {
396 self.text_decoration.underline = style;
397 self
398 }
399
400 pub const fn underline_color(mut self, color: Color) -> Self {
401 self.text_decoration.underline_color_opt = Some(color);
402 self
403 }
404
405 pub const fn strikethrough(mut self) -> Self {
406 self.text_decoration.strikethrough = true;
407 self
408 }
409
410 pub const fn strikethrough_color(mut self, color: Color) -> Self {
411 self.text_decoration.strikethrough_color_opt = Some(color);
412 self
413 }
414
415 pub const fn overline(mut self) -> Self {
416 self.text_decoration.overline = true;
417 self
418 }
419
420 pub const fn overline_color(mut self, color: Color) -> Self {
421 self.text_decoration.overline_color_opt = Some(color);
422 self
423 }
424
425 pub fn compatible(&self, other: &Self) -> bool {
427 self.family == other.family
428 && self.stretch == other.stretch
429 && self.style == other.style
430 && self.weight == other.weight
431 && self.font_features == other.font_features
432 }
433}
434
435#[derive(Clone, Debug, Eq, Hash, PartialEq)]
437pub struct FontMatchAttrs {
438 family: FamilyOwned,
439 stretch: Stretch,
440 style: Style,
441 weight: Weight,
442}
443
444impl<'a> From<&Attrs<'a>> for FontMatchAttrs {
445 fn from(attrs: &Attrs<'a>) -> Self {
446 Self {
447 family: FamilyOwned::new(attrs.family),
448 stretch: attrs.stretch,
449 style: attrs.style,
450 weight: attrs.weight,
451 }
452 }
453}
454
455#[derive(Clone, Debug, Eq, Hash, PartialEq)]
457pub struct AttrsOwned {
458 pub color_opt: Option<Color>,
460 pub family_owned: FamilyOwned,
461 pub stretch: Stretch,
462 pub style: Style,
463 pub weight: Weight,
464 pub metadata: usize,
465 pub cache_key_flags: CacheKeyFlags,
466 pub metrics_opt: Option<CacheMetrics>,
467 pub letter_spacing_opt: Option<LetterSpacing>,
469 pub font_features: FontFeatures,
470 pub text_decoration: TextDecoration,
471}
472
473impl AttrsOwned {
474 pub fn eq_shape_attrs(&self, other: &Self) -> bool {
477 self.color_opt == other.color_opt
478 && self.family_owned == other.family_owned
479 && self.stretch == other.stretch
480 && self.style == other.style
481 && self.weight == other.weight
482 && self.metadata == other.metadata
483 && self.cache_key_flags == other.cache_key_flags
484 && self.metrics_opt == other.metrics_opt
485 && self.letter_spacing_opt == other.letter_spacing_opt
486 && self.font_features == other.font_features
487 }
488
489 pub fn new(attrs: &Attrs) -> Self {
490 Self {
491 color_opt: attrs.color_opt,
492 family_owned: FamilyOwned::new(attrs.family),
493 stretch: attrs.stretch,
494 style: attrs.style,
495 weight: attrs.weight,
496 metadata: attrs.metadata,
497 cache_key_flags: attrs.cache_key_flags,
498 metrics_opt: attrs.metrics_opt,
499 letter_spacing_opt: attrs.letter_spacing_opt,
500 font_features: attrs.font_features.clone(),
501 text_decoration: attrs.text_decoration,
502 }
503 }
504
505 pub fn as_attrs(&self) -> Attrs<'_> {
506 Attrs {
507 color_opt: self.color_opt,
508 family: self.family_owned.as_family(),
509 stretch: self.stretch,
510 style: self.style,
511 weight: self.weight,
512 metadata: self.metadata,
513 cache_key_flags: self.cache_key_flags,
514 metrics_opt: self.metrics_opt,
515 letter_spacing_opt: self.letter_spacing_opt,
516 font_features: self.font_features.clone(),
517 text_decoration: self.text_decoration,
518 }
519 }
520}
521
522#[derive(Debug, Clone, Eq, PartialEq)]
525pub struct AttrsList {
526 defaults: AttrsOwned,
527 pub(crate) spans: RangeMap<usize, AttrsOwned>,
528}
529
530impl AttrsList {
531 pub fn new(defaults: &Attrs) -> Self {
533 Self {
534 defaults: AttrsOwned::new(defaults),
535 spans: RangeMap::new(),
536 }
537 }
538
539 pub fn defaults(&self) -> Attrs<'_> {
541 self.defaults.as_attrs()
542 }
543
544 pub fn eq_shape_attrs(&self, other: &Self) -> bool {
547 if !self.defaults.eq_shape_attrs(&other.defaults) {
548 return false;
549 }
550 let mut a = self
551 .spans_iter()
552 .filter(|(_, attrs)| !attrs.eq_shape_attrs(&self.defaults));
553 let mut b = other
554 .spans_iter()
555 .filter(|(_, attrs)| !attrs.eq_shape_attrs(&other.defaults));
556 loop {
557 match (a.next(), b.next()) {
558 (None, None) => return true,
559 (Some((ra, aa)), Some((rb, ab))) if ra == rb && aa.eq_shape_attrs(ab) => {}
560 _ => return false,
561 }
562 }
563 }
564
565 pub fn spans(&self) -> Vec<(&Range<usize>, &AttrsOwned)> {
567 self.spans_iter().collect()
568 }
569
570 pub fn spans_iter(&self) -> impl Iterator<Item = (&Range<usize>, &AttrsOwned)> + '_ {
572 self.spans.iter()
573 }
574
575 pub fn clear_spans(&mut self) {
577 self.spans.clear();
578 }
579
580 pub fn add_span(&mut self, range: Range<usize>, attrs: &Attrs) {
582 if range.is_empty() {
584 return;
585 }
586
587 self.spans.insert(range, AttrsOwned::new(attrs));
588 }
589
590 pub fn get_span(&self, index: usize) -> Attrs<'_> {
594 self.spans
595 .get(&index)
596 .map(|v| v.as_attrs())
597 .unwrap_or(self.defaults.as_attrs())
598 }
599
600 #[allow(clippy::missing_panics_doc)]
602 pub fn split_off(&mut self, index: usize) -> Self {
603 let mut new = Self::new(&self.defaults.as_attrs());
604 let mut removes = Vec::new();
605
606 for span in self.spans.iter() {
608 if span.0.end <= index {
609 continue;
610 }
611
612 if span.0.start >= index {
613 removes.push((span.0.clone(), false));
614 } else {
615 removes.push((span.0.clone(), true));
616 }
617 }
618
619 for (key, resize) in removes {
620 let (range, attrs) = self
621 .spans
622 .get_key_value(&key.start)
623 .map(|v| (v.0.clone(), v.1.clone()))
624 .expect("attrs span not found");
625 self.spans.remove(key);
626
627 if resize {
628 new.spans.insert(0..range.end - index, attrs.clone());
629 self.spans.insert(range.start..index, attrs);
630 } else {
631 new.spans
632 .insert(range.start - index..range.end - index, attrs);
633 }
634 }
635 new
636 }
637
638 pub(crate) fn reset(mut self, default: &Attrs) -> Self {
640 self.defaults = AttrsOwned::new(default);
641 self.spans.clear();
642 self
643 }
644}