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