term_transcript/svg/
font.rs1use std::{collections::BTreeSet, fmt};
4
5use base64::{prelude::BASE64_STANDARD, Engine};
6use serde::{Serialize, Serializer};
7
8use crate::BoxedError;
9
10#[derive(Debug, Serialize)]
12pub struct EmbeddedFont {
13 pub family_name: String,
15 pub metrics: FontMetrics,
17 pub faces: Vec<EmbeddedFontFace>,
19}
20
21#[derive(Serialize)]
23pub struct EmbeddedFontFace {
24 pub mime_type: String,
26 #[serde(serialize_with = "base64_encode")]
28 pub base64_data: Vec<u8>,
29 pub is_bold: Option<bool>,
31 pub is_italic: Option<bool>,
33}
34
35impl fmt::Debug for EmbeddedFontFace {
37 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
38 formatter
39 .debug_struct("EmbeddedFontFace")
40 .field("mime_type", &self.mime_type)
41 .field("data.len", &self.base64_data.len())
42 .field("is_bold", &self.is_bold)
43 .field("is_italic", &self.is_italic)
44 .finish()
45 }
46}
47
48impl EmbeddedFontFace {
49 pub fn woff2(data: Vec<u8>) -> Self {
51 Self {
52 mime_type: "font/woff2".to_owned(),
53 base64_data: data,
54 is_bold: None,
55 is_italic: None,
56 }
57 }
58}
59
60fn base64_encode<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
61 let encoded = BASE64_STANDARD.encode(data);
62 encoded.serialize(serializer)
63}
64
65#[derive(Debug, Clone, Copy, Serialize)]
67pub struct FontMetrics {
68 pub units_per_em: u16,
70 pub advance_width: u16,
72 pub ascent: i16,
74 pub descent: i16,
76 pub bold_spacing: f64,
78 pub italic_spacing: f64,
82}
83
84pub trait FontEmbedder: 'static + fmt::Debug + Send + Sync {
86 type Error: Into<BoxedError>;
88
89 fn embed_font(&self, used_chars: BTreeSet<char>) -> Result<EmbeddedFont, Self::Error>;
95}
96
97#[derive(Debug)]
98pub(super) struct BoxedErrorEmbedder<T>(pub(super) T);
99
100impl<T: FontEmbedder> FontEmbedder for BoxedErrorEmbedder<T> {
101 type Error = BoxedError;
102
103 fn embed_font(&self, used_chars: BTreeSet<char>) -> Result<EmbeddedFont, Self::Error> {
104 self.0.embed_font(used_chars).map_err(Into::into)
105 }
106}