use crate::usvgr::fontdb::{self, Family, Query, Weight};
use crate::{FontFace, FontStretch, FontStyle};
use std::path::Path;
use std::sync::Arc;
pub(crate) struct RendererFont<'a> {
pub(crate) index: u32,
pub(crate) data: Arc<dyn AsRef<[u8]> + Send + Sync + 'a>,
}
impl std::fmt::Debug for RendererFont<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RendererFont")
.field("index", &self.index)
.finish()
}
}
impl<'a> crate::FontFace<'a> for RendererFont<'a> {
fn is_monospaced(&self) -> Option<bool> {
let face = crate::ttf_parser::Face::parse(self.data.as_ref().as_ref(), self.index).ok()?;
Some(face.is_monospaced())
}
fn resolve_char_width(&self, font_size: usize, char: char) -> Option<usize> {
let face = crate::ttf_parser::Face::parse(self.data.as_ref().as_ref(), self.index).ok()?;
let glyph_id = face.glyph_index(char)?;
Some(
font_size * face.tables().hmtx?.advance(glyph_id)? as usize
/ face.units_per_em() as usize,
)
}
}
#[derive(Debug)]
pub struct RendererFontSource {
pub(crate) fontdb: fontdb::Database,
}
impl RendererFontSource {
pub fn as_db_ref(&self) -> &fontdb::Database {
&self.fontdb
}
pub fn read_folder(&mut self, path: impl AsRef<Path>) {
self.fontdb.load_fonts_dir(path);
}
pub fn load_system_fonts(&mut self) {
self.fontdb.load_system_fonts();
}
}
impl<'a> crate::FontSource<'a> for RendererFontSource {
fn resolve_font(
&'a self,
font_name: &str,
font_weight: u16,
font_style: FontStyle,
font_stretch: FontStretch,
) -> Option<Box<dyn FontFace<'a> + 'a>> {
let font_id = self.fontdb.query(&Query {
families: &[Family::Name(font_name)],
weight: Weight(font_weight),
style: match font_style {
FontStyle::Normal => fontdb::Style::Normal,
FontStyle::Italic => fontdb::Style::Italic,
FontStyle::Oblique => fontdb::Style::Oblique,
},
stretch: match font_stretch {
FontStretch::ExtraCondensed => fontdb::Stretch::ExtraCondensed,
FontStretch::UltraCondensed => fontdb::Stretch::UltraCondensed,
FontStretch::Condensed => fontdb::Stretch::Condensed,
FontStretch::SemiCondensed => fontdb::Stretch::SemiCondensed,
FontStretch::Normal => fontdb::Stretch::Normal,
FontStretch::SemiExpanded => fontdb::Stretch::SemiExpanded,
FontStretch::Expanded => fontdb::Stretch::Expanded,
FontStretch::ExtraExpanded => fontdb::Stretch::ExtraExpanded,
FontStretch::UltraExpanded => fontdb::Stretch::UltraExpanded,
},
})?;
let (source, index) = self.fontdb.face_source(font_id)?;
let font_data = match source {
fontdb::Source::Binary(data) | fontdb::Source::SharedFile(_, data) => data.clone(),
fontdb::Source::File(path) => Arc::new(std::fs::read(path).ok()?),
};
Some(Box::new(RendererFont {
index,
data: font_data,
}))
}
fn add_font(&mut self, _filename: String, font_data: Arc<dyn AsRef<[u8]> + Sync + Send>) {
self.fontdb
.load_font_source(fontdb::Source::Binary(font_data.clone()));
}
}