#[derive(Debug, Clone, Default, PartialEq)]
pub struct FontSpec {
pub family: Option<FontFamily>,
pub weight: Option<FontWeight>,
pub width: Option<FontWidth>,
pub style: Option<FontStyle>,
pub features: Vec<FontFeature>,
pub variations: Vec<FontVariation>,
}
impl FontSpec {
pub fn cascade(&self, over: &FontSpec) -> FontSpec {
FontSpec {
family: over.family.clone().or_else(|| self.family.clone()),
weight: over.weight.or(self.weight),
width: over.width.or(self.width),
style: over.style.or(self.style),
features: merge_by_tag(&self.features, &over.features, |f| f.tag),
variations: merge_by_tag(&self.variations, &over.variations, |v| v.tag),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FontFamily {
Named(Vec<String>),
Serif,
SansSerif,
Mono,
Cursive,
Fantasy,
SystemUi,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FontWeight(pub u16);
impl FontWeight {
pub const THIN: Self = Self(100);
pub const EXTRA_LIGHT: Self = Self(200);
pub const LIGHT: Self = Self(300);
pub const REGULAR: Self = Self(400);
pub const MEDIUM: Self = Self(500);
pub const SEMIBOLD: Self = Self(600);
pub const BOLD: Self = Self(700);
pub const EXTRA_BOLD: Self = Self(800);
pub const BLACK: Self = Self(900);
}
impl Default for FontWeight {
fn default() -> Self {
Self::REGULAR
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum FontWidth {
UltraCondensed,
ExtraCondensed,
Condensed,
SemiCondensed,
#[default]
Normal,
SemiExpanded,
Expanded,
ExtraExpanded,
UltraExpanded,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum FontStyle {
#[default]
Normal,
Italic,
Oblique(f32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FontFeature {
pub tag: [u8; 4],
pub value: u32,
}
impl FontFeature {
#[inline]
pub const fn new(tag: [u8; 4], value: u32) -> Self {
Self { tag, value }
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FontVariation {
pub tag: [u8; 4],
pub value: f32,
}
impl FontVariation {
#[inline]
pub const fn new(tag: [u8; 4], value: f32) -> Self {
Self { tag, value }
}
}
fn merge_by_tag<T: Clone, F: Fn(&T) -> [u8; 4]>(parent: &[T], child: &[T], tag: F) -> Vec<T> {
let mut out: Vec<T> = parent.to_vec();
for c in child {
let ct = tag(c);
if let Some(slot) = out.iter_mut().find(|p| tag(p) == ct) {
*slot = c.clone();
} else {
out.push(c.clone());
}
}
out
}