Cache fonts

This commit is contained in:
Jeremy Soller 2022-10-25 15:47:55 -06:00
parent c60aaaf9d2
commit 324c8837fd
No known key found for this signature in database
GPG key ID: 87F211AF2BE4C2FE
4 changed files with 46 additions and 23 deletions

View file

@ -829,8 +829,8 @@ impl<'a> TextBuffer<'a> {
"{}, {}: '{}' ('{}'): '{}' ({:?})", "{}, {}: '{}' ('{}'): '{}' ({:?})",
self.cursor.line.get(), self.cursor.line.get(),
self.cursor.index, self.cursor.index,
font_opt.map_or("?", |font| font.info.family.as_str()), font_opt.as_ref().map_or("?", |font| font.info.family.as_str()),
font_opt.map_or("?", |font| font.info.post_script_name.as_str()), font_opt.as_ref().map_or("?", |font| font.info.post_script_name.as_str()),
text_glyph, text_glyph,
text_glyph text_glyph
); );

View file

@ -1,8 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use std::sync::Arc;
use unicode_script::Script; use unicode_script::Script;
use super::Font; use crate::Font;
use self::platform::*; use self::platform::*;
@ -27,7 +28,7 @@ mod platform;
mod platform; mod platform;
pub struct FontFallbackIter<'a> { pub struct FontFallbackIter<'a> {
fonts: &'a [Font<'a>], fonts: &'a [Arc<Font<'a>>],
default_families: &'a [&'a str], default_families: &'a [&'a str],
default_i: usize, default_i: usize,
scripts: Vec<Script>, scripts: Vec<Script>,
@ -39,7 +40,12 @@ pub struct FontFallbackIter<'a> {
} }
impl<'a> FontFallbackIter<'a> { impl<'a> FontFallbackIter<'a> {
pub fn new(fonts: &'a [Font<'a>], default_families: &'a [&'a str], scripts: Vec<Script>, locale: &'a str) -> Self { pub fn new(
fonts: &'a [Arc<Font<'a>>],
default_families: &'a [&'a str],
scripts: Vec<Script>,
locale: &'a str
) -> Self {
Self { Self {
fonts, fonts,
default_families, default_families,
@ -84,7 +90,7 @@ impl<'a> FontFallbackIter<'a> {
} }
impl<'a> Iterator for FontFallbackIter<'a> { impl<'a> Iterator for FontFallbackIter<'a> {
type Item = &'a Font<'a>; type Item = &'a Arc<Font<'a>>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while self.default_i < self.default_families.len() { while self.default_i < self.default_families.len() {
let default_family = self.default_families[self.default_i]; let default_family = self.default_families[self.default_i];

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use std::sync::Arc;
use unicode_script::{Script, UnicodeScript}; use unicode_script::{Script, UnicodeScript};
use super::{Font, FontShapeGlyph, FontShapeLine, FontShapeSpan, FontShapeWord}; use super::{Font, FontShapeGlyph, FontShapeLine, FontShapeSpan, FontShapeWord};
@ -8,13 +9,13 @@ use super::fallback::{FontFallbackIter};
/// Fonts that match a pattern /// Fonts that match a pattern
pub struct FontMatches<'a> { pub struct FontMatches<'a> {
pub locale: &'a str, pub locale: &'a str,
pub fonts: Vec<Font<'a>>, pub fonts: Vec<Arc<Font<'a>>>,
} }
impl<'a> FontMatches<'a> { impl<'a> FontMatches<'a> {
fn shape_fallback( fn shape_fallback(
&self, &self,
font: &'a Font<'a>, font: &Font<'a>,
line: &str, line: &str,
start_word: usize, start_word: usize,
end_word: usize, end_word: usize,

View file

@ -1,14 +1,20 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use crate::{Attrs, Font, FontMatches}; use crate::{Attrs, Font, FontMatches};
/// Access system fonts /// Access system fonts
pub struct FontSystem { pub struct FontSystem<'a> {
pub locale: String, pub locale: String,
db: fontdb::Database, db: fontdb::Database,
pub font_cache: Mutex<HashMap<fontdb::ID, Option<Arc<Font<'a>>>>>,
} }
impl FontSystem { impl<'a> FontSystem<'a> {
pub fn new() -> Self { pub fn new() -> Self {
let locale = sys_locale::get_locale().unwrap_or_else(|| { let locale = sys_locale::get_locale().unwrap_or_else(|| {
log::warn!("failed to get system locale, falling back to en-US"); log::warn!("failed to get system locale, falling back to en-US");
@ -50,11 +56,29 @@ impl FontSystem {
); );
} }
Self { locale, db } Self {
locale,
db,
font_cache: Mutex::new(HashMap::new()),
}
}
pub fn get_font(&'a self, id: fontdb::ID) -> Option<Arc<Font<'a>>> {
let mut font_cache = self.font_cache.lock().unwrap();
font_cache.entry(id).or_insert_with(|| {
let face = self.db.face(id)?;
match Font::new(face) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!("failed to load font '{}'", face.post_script_name);
None
}
}
}).clone()
} }
pub fn matches<F: Fn(&fontdb::FaceInfo) -> bool>( pub fn matches<F: Fn(&fontdb::FaceInfo) -> bool>(
&self, &'a self,
f: F, f: F,
) -> Option<FontMatches<'_>> { ) -> Option<FontMatches<'_>> {
let mut fonts = Vec::new(); let mut fonts = Vec::new();
@ -63,11 +87,9 @@ impl FontSystem {
continue; continue;
} }
match Font::new(face) { match self.get_font(face.id) {
Some(font) => fonts.push(font), Some(font) => fonts.push(font),
None => { None => (),
log::warn!("failed to load font '{}'", face.post_script_name);
}
} }
} }
@ -81,7 +103,7 @@ impl FontSystem {
} }
} }
pub fn matches_attrs(&self, attrs: Attrs) -> Option<FontMatches<'_>> { pub fn matches_attrs(&'a self, attrs: Attrs) -> Option<FontMatches<'_>> {
self.matches(|info| { self.matches(|info| {
let matched = { let matched = {
info.style == attrs.style && info.style == attrs.style &&
@ -108,9 +130,3 @@ impl FontSystem {
}) })
} }
} }
impl Default for FontSystem {
fn default() -> Self {
Self::new()
}
}