diff --git a/Cargo.toml b/Cargo.toml index 748641d..d912a7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/font/mod.rs b/src/font/mod.rs index a25d8b2..c512457 100644 --- a/src/font/mod.rs +++ b/src/font/mod.rs @@ -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() + ) + } +} \ No newline at end of file diff --git a/src/font/system.rs b/src/font/system.rs index 0872ba4..52206f6 100644 --- a/src/font/system.rs +++ b/src/font/system.rs @@ -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) { + #[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::>>>() + .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> {