use crate::{Glyph, GlyphIter, IntoGlyphId, LayoutIter, Point, Scale, VMetrics};
#[cfg(not(feature = "has-atomics"))]
use alloc::rc::Rc as Arc;
#[cfg(feature = "has-atomics")]
use alloc::sync::Arc;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
#[derive(Clone)]
pub enum Font<'a> {
Ref(Arc<owned_ttf_parser::Face<'a>>),
Owned(Arc<owned_ttf_parser::OwnedFace>),
}
impl fmt::Debug for Font<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Font")
}
}
impl Font<'_> {
pub fn try_from_bytes(bytes: &[u8]) -> Option<Font<'_>> {
Self::try_from_bytes_and_index(bytes, 0)
}
pub fn try_from_bytes_and_index(bytes: &[u8], index: u32) -> Option<Font<'_>> {
let inner = Arc::new(owned_ttf_parser::Face::from_slice(bytes, index).ok()?);
Some(Font::Ref(inner))
}
pub fn try_from_vec(data: Vec<u8>) -> Option<Font<'static>> {
Self::try_from_vec_and_index(data, 0)
}
pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Option<Font<'static>> {
let inner = Arc::new(owned_ttf_parser::OwnedFace::from_vec(data, index).ok()?);
Some(Font::Owned(inner))
}
}
impl<'font> Font<'font> {
#[inline]
pub(crate) fn inner(&self) -> &owned_ttf_parser::Face<'_> {
use owned_ttf_parser::AsFaceRef;
match self {
Self::Ref(f) => f,
Self::Owned(f) => f.as_face_ref(),
}
}
pub fn v_metrics(&self, scale: Scale) -> VMetrics {
self.v_metrics_unscaled() * self.scale_for_pixel_height(scale.y)
}
pub fn v_metrics_unscaled(&self) -> VMetrics {
let font = self.inner();
VMetrics {
ascent: font.ascender() as f32,
descent: font.descender() as f32,
line_gap: font.line_gap() as f32,
}
}
pub fn units_per_em(&self) -> u16 {
self.inner().units_per_em()
}
pub fn glyph_count(&self) -> usize {
self.inner().number_of_glyphs() as _
}
pub fn glyph<C: IntoGlyphId>(&self, id: C) -> Glyph<'font> {
let gid = id.into_glyph_id(self);
assert!((gid.0 as usize) < self.glyph_count());
Glyph {
font: self.clone(),
id: gid,
}
}
pub fn glyphs_for<'a, I: Iterator>(&'a self, itr: I) -> GlyphIter<'a, 'font, I>
where
I::Item: IntoGlyphId,
{
GlyphIter { font: self, itr }
}
pub fn layout<'a, 's>(
&'a self,
s: &'s str,
scale: Scale,
start: Point<f32>,
) -> LayoutIter<'a, 'font, 's> {
LayoutIter {
font: self,
chars: s.chars(),
caret: 0.0,
scale,
start,
last_glyph: None,
}
}
pub fn pair_kerning<A, B>(&self, scale: Scale, first: A, second: B) -> f32
where
A: IntoGlyphId,
B: IntoGlyphId,
{
let first_id = first.into_glyph_id(self).into();
let second_id = second.into_glyph_id(self).into();
let factor = {
let hscale = self.scale_for_pixel_height(scale.y);
hscale * (scale.x / scale.y)
};
let kern = if let Some(kern) = self.inner().tables().kern {
kern.subtables
.into_iter()
.filter(|st| st.horizontal && !st.variable)
.find_map(|st| st.glyphs_kerning(first_id, second_id))
.unwrap_or(0)
} else {
0
};
factor * f32::from(kern)
}
pub fn scale_for_pixel_height(&self, height: f32) -> f32 {
let inner = self.inner();
let fheight = f32::from(inner.ascender()) - f32::from(inner.descender());
height / fheight
}
}