use anyrender::{Glyph, NormalizedCoord};
use peniko::FontData;
use skrifa::instance::{LocationRef, NormalizedCoord as Coord, Size};
use skrifa::{FontRef, GlyphId, MetadataProvider as _};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) struct FaceKey {
blob: u64,
index: u32,
coords: Vec<NormalizedCoord>,
}
impl FaceKey {
pub(crate) fn of(font: &FontData, coords: &[NormalizedCoord]) -> Self {
FaceKey {
blob: font.data.id(),
index: font.index,
coords: coords.to_vec(),
}
}
}
pub(crate) struct Metrics {
pub(crate) chars: HashMap<u32, char>,
ascent: f32,
descent: f32,
data: FontData,
coords: Vec<NormalizedCoord>,
}
impl Metrics {
pub(crate) fn load(font: &FontData, coords: &[NormalizedCoord]) -> Option<Self> {
let parsed = FontRef::from_index(font.data.data(), font.index).ok()?;
let metrics = parsed.metrics(Size::unscaled(), LocationRef::default());
let per_em = f32::from(metrics.units_per_em.max(1));
Some(Metrics {
chars: crate::cmap::reverse(&parsed),
ascent: metrics.ascent / per_em,
descent: metrics.descent / per_em,
data: font.clone(),
coords: coords.to_vec(),
})
}
pub(crate) fn advances(&self, glyphs: &[Glyph], size: f32) -> Vec<f32> {
let fallback = size / 2.0;
let Ok(font) = FontRef::from_index(self.data.data.data(), self.data.index) else {
return vec![fallback; glyphs.len()];
};
let location: Vec<Coord> = self.coords.iter().map(|&c| Coord::from_bits(c)).collect();
let metrics = font.glyph_metrics(Size::new(size), LocationRef::new(&location));
glyphs
.iter()
.map(|glyph| {
metrics
.advance_width(GlyphId::new(glyph.id))
.unwrap_or(fallback)
})
.collect()
}
pub(crate) fn centre(&self, glyph: Glyph, advance: f32, size: f32) -> peniko::kurbo::Point {
peniko::kurbo::Point::new(
f64::from(glyph.x + advance / 2.0),
f64::from(glyph.y - f32::midpoint(self.ascent, self.descent) * size),
)
}
}