1use std::borrow::{Borrow, Cow};
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::i32;
5use std::sync::{Arc, RwLock};
6
7use lazy_static::lazy_static;
8
9use font_kit::{
10 canvas::{Canvas, Format, RasterizationOptions},
11 error::{FontLoadingError, GlyphLoadingError},
12 family_name::FamilyName,
13 font::Font,
14 handle::Handle,
15 hinting::HintingOptions,
16 properties::{Properties, Style, Weight},
17 source::SystemSource,
18};
19
20use ttf_parser::{Face, GlyphId};
21
22use pathfinder_geometry::transform2d::Transform2F;
23use pathfinder_geometry::vector::{Vector2F, Vector2I};
24
25use super::{FontData, FontFamily, FontStyle, LayoutBox};
26
27type FontResult<T> = Result<T, FontError>;
28
29#[derive(Debug, Clone)]
30pub enum FontError {
31 LockError,
32 NoSuchFont(String, String),
33 FontLoadError(Arc<FontLoadingError>),
34 GlyphError(Arc<GlyphLoadingError>),
35}
36
37impl std::fmt::Display for FontError {
38 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
39 match self {
40 FontError::LockError => write!(fmt, "Could not lock mutex"),
41 FontError::NoSuchFont(family, style) => {
42 write!(fmt, "No such font: {} {}", family, style)
43 }
44 FontError::FontLoadError(e) => write!(fmt, "Font loading error {}", e),
45 FontError::GlyphError(e) => write!(fmt, "Glyph error {}", e),
46 }
47 }
48}
49
50impl std::error::Error for FontError {}
51
52lazy_static! {
53 static ref DATA_CACHE: RwLock<HashMap<String, FontResult<Handle>>> =
54 RwLock::new(HashMap::new());
55}
56
57thread_local! {
58 static FONT_SOURCE: SystemSource = SystemSource::new();
59 static FONT_OBJECT_CACHE: RefCell<HashMap<String, FontExt>> = RefCell::new(HashMap::new());
60}
61
62const PLACEHOLDER_CHAR: char = '�';
63
64#[derive(Clone)]
65struct FontExt {
66 inner: Font,
67 face: Option<Face<'static>>,
68}
69
70impl Drop for FontExt {
71 fn drop(&mut self) {
72 // We should make sure the face object dead first
73 self.face.take();
74 }
75}
76
77impl FontExt {
78 fn new(font: Font) -> Self {
79 let handle = font.handle();
80 let (data, idx) = match handle.as_ref() {
81 Some(Handle::Memory { bytes, font_index }) => (&bytes[..], *font_index),
82 _ => unreachable!(),
83 };
84 let face = unsafe {
85 std::mem::transmute::<_, Option<Face<'static>>>(ttf_parser::Face::parse(data, idx).ok())
86 };
87 Self { inner: font, face }
88 }
89
90 fn query_kerning_table(&self, prev: u32, next: u32) -> f32 {
91 if let Some(face) = self.face.as_ref() {
92 if let Some(kern) = face.tables().kern {
93 let kern = kern
94 .subtables
95 .into_iter()
96 .filter(|st| st.horizontal && !st.variable)
97 .filter_map(|st| st.glyphs_kerning(GlyphId(prev as u16), GlyphId(next as u16)))
98 .next()
99 .unwrap_or(0);
100 return kern as f32;
101 }
102 }
103 0.0
104 }
105}
106
107impl std::ops::Deref for FontExt {
108 type Target = Font;
109 fn deref(&self) -> &Font {
110 &self.inner
111 }
112}
113
114/// Lazily load font data. Font type doesn't own actual data, which
115/// lives in the cache.
116fn load_font_data(face: FontFamily, style: FontStyle) -> FontResult<FontExt> {
117 let key = match style {
118 FontStyle::Normal => Cow::Borrowed(face.as_str()),
119 _ => Cow::Owned(format!("{}, {}", face.as_str(), style.as_str())),
120 };
121
122 // First, we try to find the font object for current thread
123 if let Some(font_object) = FONT_OBJECT_CACHE.with(|font_object_cache| {
124 font_object_cache
125 .borrow()
126 .get(Borrow::<str>::borrow(&key))
127 .map(Clone::clone)
128 }) {
129 return Ok(font_object);
130 }
131
132 // Then we need to check if the data cache contains the font data
133 let cache = DATA_CACHE.read().unwrap();
134 if let Some(data) = cache.get(Borrow::<str>::borrow(&key)) {
135 return data.clone().map(|handle| {
136 handle
137 .load()
138 .map(FontExt::new)
139 .map_err(|e| FontError::FontLoadError(Arc::new(e)))
140 })?;
141 }
142 drop(cache);
143
144 // Otherwise we should load from system
145 let mut properties = Properties::new();
146 match style {
147 FontStyle::Normal => properties.style(Style::Normal),
148 FontStyle::Italic => properties.style(Style::Italic),
149 FontStyle::Oblique => properties.style(Style::Oblique),
150 FontStyle::Bold => properties.weight(Weight::BOLD),
151 };
152
153 let family = match face {
154 FontFamily::Serif => FamilyName::Serif,
155 FontFamily::SansSerif => FamilyName::SansSerif,
156 FontFamily::Monospace => FamilyName::Monospace,
157 FontFamily::Name(name) => FamilyName::Title(name.to_owned()),
158 };
159
160 let make_not_found_error =
161 || FontError::NoSuchFont(face.as_str().to_owned(), style.as_str().to_owned());
162
163 if let Ok(handle) = FONT_SOURCE
164 .with(|source| source.select_best_match(&[family, FamilyName::SansSerif], &properties))
165 {
166 let font = handle
167 .load()
168 .map(FontExt::new)
169 .map_err(|e| FontError::FontLoadError(Arc::new(e)));
170 let (should_cache, data) = match font.as_ref().map(|f| f.handle()) {
171 Ok(None) => (false, Err(FontError::LockError)),
172 Ok(Some(handle)) => (true, Ok(handle)),
173 Err(e) => (true, Err(e.clone())),
174 };
175
176 if should_cache {
177 DATA_CACHE
178 .write()
179 .map_err(|_| FontError::LockError)?
180 .insert(key.clone().into_owned(), data);
181 }
182
183 if let Ok(font) = font.as_ref() {
184 FONT_OBJECT_CACHE.with(|font_object_cache| {
185 font_object_cache
186 .borrow_mut()
187 .insert(key.into_owned(), font.clone());
188 });
189 }
190
191 return font;
192 }
193 Err(make_not_found_error())
194}
195
196#[derive(Clone)]
197pub struct FontDataInternal(FontExt);
198
199impl FontData for FontDataInternal {
200 type ErrorType = FontError;
201
202 fn new(family: FontFamily, style: FontStyle) -> Result<Self, FontError> {
203 Ok(FontDataInternal(load_font_data(family, style)?))
204 }
205
206 fn estimate_layout(&self, size: f64, text: &str) -> Result<LayoutBox, Self::ErrorType> {
207 let font = &self.0;
208 let pixel_per_em = size / 1.24;
209 let metrics = font.metrics();
210
211 let font = &self.0;
212
213 let mut x_in_unit = 0f32;
214
215 let mut prev = None;
216 let place_holder = font.glyph_for_char(PLACEHOLDER_CHAR);
217
218 for c in text.chars() {
219 if let Some(glyph_id) = font.glyph_for_char(c).or(place_holder) {
220 if let Ok(size) = font.advance(glyph_id) {
221 x_in_unit += size.x();
222 }
223 if let Some(pc) = prev {
224 x_in_unit += font.query_kerning_table(pc, glyph_id);
225 }
226 prev = Some(glyph_id);
227 }
228 }
229
230 let x_pixels = x_in_unit * pixel_per_em as f32 / metrics.units_per_em as f32;
231
232 Ok(((0, 0), (x_pixels as i32, pixel_per_em as i32)))
233 }
234
235 fn draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>(
236 &self,
237 (base_x, mut base_y): (i32, i32),
238 size: f64,
239 text: &str,
240 mut draw: DrawFunc,
241 ) -> Result<Result<(), E>, Self::ErrorType> {
242 let em = (size / 1.24) as f32;
243
244 let mut x = base_x as f32;
245 let font = &self.0;
246 let metrics = font.metrics();
247
248 let canvas_size = size as usize;
249
250 base_y -= (0.24 * em) as i32;
251
252 let mut prev = None;
253 let place_holder = font.glyph_for_char(PLACEHOLDER_CHAR);
254
255 let mut result = Ok(());
256
257 for c in text.chars() {
258 if let Some(glyph_id) = font.glyph_for_char(c).or(place_holder) {
259 if let Some(pc) = prev {
260 x += font.query_kerning_table(pc, glyph_id) * em / metrics.units_per_em as f32;
261 }
262
263 let mut canvas = Canvas::new(Vector2I::splat(canvas_size as i32), Format::A8);
264
265 result = font
266 .rasterize_glyph(
267 &mut canvas,
268 glyph_id,
269 em as f32,
270 Transform2F::from_translation(Vector2F::new(0.0, em as f32)),
271 HintingOptions::None,
272 RasterizationOptions::GrayscaleAa,
273 )
274 .map_err(|e| FontError::GlyphError(Arc::new(e)))
275 .and(result);
276
277 let base_x = x as i32;
278
279 for dy in 0..canvas_size {
280 for dx in 0..canvas_size {
281 let alpha = canvas.pixels[dy * canvas_size + dx] as f32 / 255.0;
282 if let Err(e) = draw(base_x + dx as i32, base_y + dy as i32, alpha) {
283 return Ok(Err(e));
284 }
285 }
286 }
287
288 x += font.advance(glyph_id).map(|size| size.x()).unwrap_or(0.0) * em
289 / metrics.units_per_em as f32;
290
291 prev = Some(glyph_id);
292 }
293 }
294 result?;
295 Ok(Ok(()))
296 }
297}
298
299#[cfg(test)]
300mod test {
301
302 use super::*;
303
304 #[test]
305 fn test_font_cache() -> FontResult<()> {
306 // We cannot only check the size of font cache, because
307 // the test case may be run in parallel. Thus the font cache
308 // may contains other fonts.
309 let _a = load_font_data(FontFamily::Serif, FontStyle::Normal)?;
310 assert!(DATA_CACHE.read().unwrap().contains_key("serif"));
311
312 let _b = load_font_data(FontFamily::Serif, FontStyle::Normal)?;
313 assert!(DATA_CACHE.read().unwrap().contains_key("serif"));
314
315 // TODO: Check they are the same
316
317 return Ok(());
318 }
319}
320