Skip to main content

incular_text/style/
fonts.rs

1use incular_core::Lerp;
2use std::sync::Arc;
3
4/// A logical font family. Named families are resolved by [`crate::TextEngine`];
5/// their names are shared, so cloning a style never copies them.
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub enum FontFamily {
8    SansSerif,
9    Serif,
10    Monospace,
11    Cursive,
12    SystemUi,
13    Named(Arc<str>),
14}
15
16impl FontFamily {
17    #[must_use]
18    pub fn named(name: impl Into<String>) -> Self {
19        Self::Named(name.into().into())
20    }
21}
22
23/// Font weight values (1..1000).
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
25pub struct FontWeight(pub u16);
26
27impl FontWeight {
28    pub const W100: Self = Self(100);
29    pub const W200: Self = Self(200);
30    pub const W300: Self = Self(300);
31    pub const W400: Self = Self(400);
32    pub const W500: Self = Self(500);
33    pub const W600: Self = Self(600);
34    pub const W700: Self = Self(700);
35    pub const W800: Self = Self(800);
36    pub const W900: Self = Self(900);
37
38    pub const THIN: Self = Self::W100;
39    pub const EXTRA_LIGHT: Self = Self::W200;
40    pub const LIGHT: Self = Self::W300;
41    pub const NORMAL: Self = Self::W400;
42    pub const MEDIUM: Self = Self::W500;
43    pub const SEMI_BOLD: Self = Self::W600;
44    pub const BOLD: Self = Self::W700;
45    pub const EXTRA_BOLD: Self = Self::W800;
46    pub const BLACK: Self = Self::W900;
47
48    #[must_use]
49    pub const fn new(value: u16) -> Self {
50        Self(if value < 1 {
51            1
52        } else if value > 1000 {
53            1000
54        } else {
55            value
56        })
57    }
58
59    #[must_use]
60    pub const fn value(self) -> u16 {
61        self.0
62    }
63}
64
65impl Lerp for FontWeight {
66    fn lerp(&self, other: &Self, t: f32) -> Self {
67        let t = t.clamp(0.0, 1.0);
68        let left = self.0 as f32;
69        let right = other.0 as f32;
70        Self::new((left + (right - left) * t).round() as u16)
71    }
72}
73
74/// OpenType font feature setting with a 4-byte ASCII tag and an integer value.
75#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
76pub struct FontFeature {
77    pub tag: [u8; 4],
78    pub value: i32,
79}
80
81impl FontFeature {
82    #[must_use]
83    pub const fn new(tag: [u8; 4], value: i32) -> Self {
84        Self { tag, value }
85    }
86
87    #[must_use]
88    pub const fn enable(tag: [u8; 4]) -> Self {
89        Self::new(tag, 1)
90    }
91
92    #[must_use]
93    pub const fn disable(tag: [u8; 4]) -> Self {
94        Self::new(tag, 0)
95    }
96
97    #[must_use]
98    pub const fn alternative(value: i32) -> Self {
99        Self::new(*b"aalt", value)
100    }
101
102    #[must_use]
103    pub const fn contextual_alternates() -> Self {
104        Self::enable(*b"calt")
105    }
106
107    #[must_use]
108    pub const fn tabular_figures() -> Self {
109        Self::enable(*b"tnum")
110    }
111
112    #[must_use]
113    pub const fn proportional_figures() -> Self {
114        Self::enable(*b"pnum")
115    }
116
117    #[must_use]
118    pub const fn slashed_zero() -> Self {
119        Self::enable(*b"zero")
120    }
121
122    #[must_use]
123    pub fn to_css_setting(&self) -> String {
124        let tag_str = std::str::from_utf8(&self.tag).unwrap_or("????");
125        format!("\"{}\" {}", tag_str, self.value)
126    }
127}
128
129/// OpenType font variation axis setting with a 4-byte ASCII tag and floating-point value.
130#[derive(Clone, Copy, Debug, PartialEq)]
131pub struct FontVariation {
132    pub axis: [u8; 4],
133    pub value: f32,
134}
135
136impl FontVariation {
137    #[must_use]
138    pub const fn new(axis: [u8; 4], value: f32) -> Self {
139        Self { axis, value }
140    }
141
142    #[must_use]
143    pub const fn weight(value: f32) -> Self {
144        Self::new(*b"wght", value)
145    }
146
147    #[must_use]
148    pub const fn italic(value: f32) -> Self {
149        Self::new(*b"ital", value)
150    }
151
152    #[must_use]
153    pub const fn slant(value: f32) -> Self {
154        Self::new(*b"slnt", value)
155    }
156
157    #[must_use]
158    pub const fn width(value: f32) -> Self {
159        Self::new(*b"wdth", value)
160    }
161
162    #[must_use]
163    pub const fn optical_size(value: f32) -> Self {
164        Self::new(*b"opsz", value)
165    }
166
167    #[must_use]
168    pub fn to_css_setting(&self) -> String {
169        let axis_str = std::str::from_utf8(&self.axis).unwrap_or("????");
170        format!("\"{}\" {:.1}", axis_str, self.value)
171    }
172}
173
174impl Lerp for FontVariation {
175    fn lerp(&self, other: &Self, t: f32) -> Self {
176        Self::new(self.axis, self.value.lerp(&other.value, t))
177    }
178}