1 use std::borrow::{Borrow, Cow};
2 use std::cell::RefCell;
3 use std::collections::HashMap;
4 use std::i32;
5 use std::sync::{Arc, RwLock};
6 
7 use lazy_static::lazy_static;
8 
9 use 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 
20 use ttf_parser::{Face, GlyphId};
21 
22 use pathfinder_geometry::transform2d::Transform2F;
23 use pathfinder_geometry::vector::{Vector2F, Vector2I};
24 
25 use super::{FontData, FontFamily, FontStyle, LayoutBox};
26 
27 type FontResult<T> = Result<T, FontError>;
28 
29 #[derive(Debug, Clone)]
30 pub enum FontError {
31     LockError,
32     NoSuchFont(String, String),
33     FontLoadError(Arc<FontLoadingError>),
34     GlyphError(Arc<GlyphLoadingError>),
35 }
36 
37 impl std::fmt::Display for FontError {
fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>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 
50 impl std::error::Error for FontError {}
51 
52 lazy_static! {
53     static ref DATA_CACHE: RwLock<HashMap<String, FontResult<Handle>>> =
54         RwLock::new(HashMap::new());
55 }
56 
57 thread_local! {
58     static FONT_SOURCE: SystemSource = SystemSource::new();
59     static FONT_OBJECT_CACHE: RefCell<HashMap<String, FontExt>> = RefCell::new(HashMap::new());
60 }
61 
62 const PLACEHOLDER_CHAR: char = '�';
63 
64 #[derive(Clone)]
65 struct FontExt {
66     inner: Font,
67     face: Option<Face<'static>>,
68 }
69 
70 impl Drop for FontExt {
drop(&mut self)71     fn drop(&mut self) {
72         // We should make sure the face object dead first
73         self.face.take();
74     }
75 }
76 
77 impl FontExt {
new(font: Font) -> Self78     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 
query_kerning_table(&self, prev: u32, next: u32) -> f3290     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 
107 impl std::ops::Deref for FontExt {
108     type Target = Font;
deref(&self) -> &Font109     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.
load_font_data(face: FontFamily, style: FontStyle) -> FontResult<FontExt>116 fn 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)]
197 pub struct FontDataInternal(FontExt);
198 
199 impl FontData for FontDataInternal {
200     type ErrorType = FontError;
201 
new(family: FontFamily, style: FontStyle) -> Result<Self, FontError>202     fn new(family: FontFamily, style: FontStyle) -> Result<Self, FontError> {
203         Ok(FontDataInternal(load_font_data(family, style)?))
204     }
205 
estimate_layout(&self, size: f64, text: &str) -> Result<LayoutBox, Self::ErrorType>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 
draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>( &self, (base_x, mut base_y): (i32, i32), size: f64, text: &str, mut draw: DrawFunc, ) -> Result<Result<(), E>, Self::ErrorType>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)]
300 mod test {
301 
302     use super::*;
303 
304     #[test]
test_font_cache() -> FontResult<()>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