feat: concurrently load & parse fonts

This commit is contained in:
Itsusinn 2024-04-28 18:29:32 +08:00 committed by Jeremy Soller
parent 5e82de11cf
commit 658025314c
3 changed files with 66 additions and 2 deletions

View file

@ -28,6 +28,7 @@ ttf-parser = { version = "0.20.0", default-features = false }
unicode-linebreak = "0.1.5"
unicode-script = "0.5.5"
unicode-segmentation = "1.10.1"
rayon = { version = "1", optional = true }
[dependencies.unicode-bidi]
version = "0.3.13"
@ -35,7 +36,7 @@ default-features = false
features = ["hardcoded-data"]
[features]
default = ["std", "swash", "fontconfig"]
default = ["std", "swash", "fontconfig", "rayon"]
fontconfig = ["fontdb/fontconfig", "std"]
no_std = ["rustybuzz/libm", "hashbrown"]
shape-run-cache = []
@ -50,6 +51,7 @@ std = [
vi = ["modit", "syntect", "cosmic_undo_2"]
wasm-web = ["sys-locale?/js"]
warn_on_missing_glyphs = []
rayon = ["dep:rayon"]
[[bench]]
name = "layout"

View file

@ -158,3 +158,26 @@ impl Font {
})
}
}
#[cfg(test)]
mod test{
#[test]
fn test_fonts_load_time(){
use crate::FontSystem;
use sys_locale::get_locale;
#[cfg(not(target_arch = "wasm32"))]
let now = std::time::Instant::now();
let mut db = fontdb::Database::new();
let locale = get_locale().unwrap();
db.load_system_fonts();
FontSystem::new_with_locale_and_db(locale, db);
#[cfg(not(target_arch = "wasm32"))]
println!(
"Fonts load time {}ms.",
now.elapsed().as_millis()
)
}
}

View file

@ -172,7 +172,7 @@ impl FontSystem {
#[cfg(feature = "shape-run-cache")]
shape_run_cache: crate::ShapeRunCache::default(),
};
ret.cache_fonts(cloned_monospace_font_ids.clone());
cloned_monospace_font_ids.into_iter().for_each(|id| {
if let Some(font) = ret.get_font(id) {
font.scripts().iter().copied().for_each(|script| {
@ -211,6 +211,45 @@ impl FontSystem {
pub fn into_locale_and_db(self) -> (String, fontdb::Database) {
(self.locale, self.db)
}
/// Concurrently cache fonts by id list
pub fn cache_fonts(&mut self, mut ids: Vec<fontdb::ID>) {
#[cfg(feature = "rayon")]
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
ids = ids
.into_iter()
.filter(|id| {
let contains = self.font_cache.contains_key(id);
#[cfg(feature = "std")]
unsafe {
self.db.make_shared_face_data(*id);
}
!contains
})
.collect::<_>();
#[cfg(feature = "rayon")]
let fonts = ids.par_iter();
#[cfg(not(feature = "rayon"))]
let fonts = ids.iter();
fonts
.map(|id| match Font::new(&self.db, *id) {
Some(font) => Some(Arc::new(font)),
None => {
log::warn!(
"failed to load font '{}'",
self.db.face(*id)?.post_script_name
);
None
}
})
.collect::<Vec<Option<Arc<Font>>>>()
.into_iter()
.flatten()
.for_each(|font| {
self.font_cache.insert(font.id, Some(font));
});
}
/// Get a font by its ID.
pub fn get_font(&mut self, id: fontdb::ID) -> Option<Arc<Font>> {