use std::{collections::BTreeSet, fmt};
use base64::{Engine, prelude::BASE64_STANDARD};
use serde::{Serialize, Serializer};
use crate::types::BoxedError;
#[derive(Debug, Serialize)]
pub struct EmbeddedFont {
pub family_name: String,
pub metrics: FontMetrics,
pub faces: Vec<EmbeddedFontFace>,
}
#[derive(Serialize)]
pub struct EmbeddedFontFace {
pub mime_type: String,
#[serde(serialize_with = "base64_encode")]
pub base64_data: Vec<u8>,
pub is_bold: Option<bool>,
pub is_italic: Option<bool>,
}
impl fmt::Debug for EmbeddedFontFace {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("EmbeddedFontFace")
.field("mime_type", &self.mime_type)
.field("data.len", &self.base64_data.len())
.field("is_bold", &self.is_bold)
.field("is_italic", &self.is_italic)
.finish()
}
}
impl EmbeddedFontFace {
pub fn woff2(data: Vec<u8>) -> Self {
Self {
mime_type: "font/woff2".to_owned(),
base64_data: data,
is_bold: None,
is_italic: None,
}
}
}
fn base64_encode<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
let encoded = BASE64_STANDARD.encode(data);
encoded.serialize(serializer)
}
#[derive(Debug, Clone, Copy, Serialize)]
pub struct FontMetrics {
pub units_per_em: u16,
pub advance_width: u16,
pub ascent: i16,
pub descent: i16,
pub bold_spacing: f64,
pub italic_spacing: f64,
}
pub trait FontEmbedder: 'static + fmt::Debug + Send + Sync {
type Error: Into<BoxedError>;
fn embed_font(&self, used_chars: BTreeSet<char>) -> Result<EmbeddedFont, Self::Error>;
}
#[derive(Debug)]
pub(super) struct BoxedErrorEmbedder<T>(pub(super) T);
impl<T: FontEmbedder> FontEmbedder for BoxedErrorEmbedder<T> {
type Error = BoxedError;
fn embed_font(&self, used_chars: BTreeSet<char>) -> Result<EmbeddedFont, Self::Error> {
self.0.embed_font(used_chars).map_err(Into::into)
}
}