1#[cfg(feature = "fonts-engine")]
2use crate::error::{GraphitePdfKitError, Result};
3use graphitepdf_font::{LoadedFont, StandardFont};
4use std::collections::HashMap;
5
6#[derive(Clone, Debug)]
7pub struct Font {
8 pub name: String,
9 pub data: Vec<u8>,
10 standard_font: Option<StandardFont>,
11}
12
13impl Font {
14 #[cfg(feature = "fonts-engine")]
15 pub fn from_bytes(name: impl Into<String>, data: Vec<u8>) -> Result<Self> {
16 let _ = ttf_parser::Face::parse(&data, 0)
18 .map_err(|e| GraphitePdfKitError::FontError(format!("Invalid font data: {:?}", e)))?;
19
20 Ok(Self {
21 name: name.into(),
22 data,
23 standard_font: None,
24 })
25 }
26
27 pub fn standard(name: StandardFont) -> Self {
28 Self {
29 name: name.as_str().to_string(),
30 data: Vec::new(),
31 standard_font: Some(name),
32 }
33 }
34
35 pub fn name(&self) -> &str {
36 &self.name
37 }
38
39 pub fn data(&self) -> &[u8] {
40 &self.data
41 }
42
43 pub const fn standard_font(&self) -> Option<StandardFont> {
44 self.standard_font
45 }
46
47 pub fn base_font_name(&self) -> &str {
48 match self.standard_font {
49 Some(font) => font.as_str(),
50 None => self.name.as_str(),
51 }
52 }
53
54 #[cfg(feature = "fonts-engine")]
55 pub fn measure_text_width(&self, text: &str, font_size: f64) -> Result<f64> {
56 if self.data.is_empty() {
57 Ok(text.len() as f64 * font_size * 0.6)
59 } else {
60 let face = ttf_parser::Face::parse(&self.data, 0).map_err(|e| {
61 GraphitePdfKitError::FontError(format!("Failed to parse font: {:?}", e))
62 })?;
63
64 let units_per_em = face.units_per_em() as f64;
65 let scale = font_size / units_per_em;
66
67 let mut width = 0.0;
68 for c in text.chars() {
69 if let Some(glyph_id) = face.glyph_index(c) {
70 if let Some(advance) = face.glyph_hor_advance(glyph_id) {
71 width += advance as f64 * scale;
72 }
73 }
74 }
75 Ok(width)
76 }
77 }
78}
79
80impl From<StandardFont> for Font {
81 fn from(value: StandardFont) -> Self {
82 Self::standard(value)
83 }
84}
85
86impl From<&LoadedFont> for Font {
87 fn from(value: &LoadedFont) -> Self {
88 if let Some(font) = value.standard_font() {
89 return Self::standard(font);
90 }
91
92 Self {
93 name: value.descriptor().family().to_string(),
94 data: value.bytes().map(ToOwned::to_owned).unwrap_or_default(),
95 standard_font: None,
96 }
97 }
98}
99
100impl From<LoadedFont> for Font {
101 fn from(value: LoadedFont) -> Self {
102 Self::from(&value)
103 }
104}
105
106#[derive(Clone, Debug, Default)]
107pub struct FontRegistry {
108 pub fonts: HashMap<String, (Font, u64)>,
109 next_id: u64,
110}
111
112impl FontRegistry {
113 pub fn new() -> Self {
114 Self {
115 fonts: HashMap::new(),
116 next_id: 1,
117 }
118 }
119
120 pub fn with_default_font() -> Self {
121 let mut registry = Self::new();
122 registry.register(Font::standard(StandardFont::Helvetica));
123 registry
124 }
125
126 pub fn register(&mut self, font: impl Into<Font>) -> String {
127 let font = font.into();
128 let id = self.next_id;
129 let name = format!("F{}", id);
130 self.next_id += 1;
131 self.fonts.insert(name.clone(), (font, id));
132 name
133 }
134
135 pub fn get(&self, name: &str) -> Option<&Font> {
136 self.fonts.get(name).map(|(font, _)| font)
137 }
138}