diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e7717287..1cd52fe92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +* Improve cache of font data to use less memory. # 0.13.7 diff --git a/crates/zng-ext-font/src/lib.rs b/crates/zng-ext-font/src/lib.rs index 8af193ddf..defc818dd 100644 --- a/crates/zng-ext-font/src/lib.rs +++ b/crates/zng-ext-font/src/lib.rs @@ -1785,6 +1785,7 @@ impl> std::ops::Index for FontList { struct FontFaceLoader { custom_fonts: HashMap>, unregister_requests: Vec<(FontName, ResponderVar)>, + system_fonts_cache: HashMap>, list_cache: HashMap, Vec>, } diff --git a/crates/zng-ext-font/src/query_util.rs b/crates/zng-ext-font/src/query_util.rs index 8b90fc359..31dd0fd74 100644 --- a/crates/zng-ext-font/src/query_util.rs +++ b/crates/zng-ext-font/src/query_util.rs @@ -9,12 +9,20 @@ pub use android::*; #[cfg(not(any(target_arch = "wasm32", target_os = "android")))] mod desktop { - use std::{borrow::Cow, path::Path, sync::Arc}; - + use std::{ + borrow::Cow, + path::{Path, PathBuf}, + sync::Arc, + }; + + use parking_lot::Mutex; + use zng_layout::unit::ByteUnits; use zng_var::ResponseVar; use crate::{FontDataRef, FontLoadingError, FontName, FontStretch, FontStyle, FontWeight, GlyphLoadingError}; + static DATA_CACHE: Mutex>)>> = Mutex::new(vec![]); + pub fn system_all() -> ResponseVar> { zng_task::wait_respond(|| { font_kit::source::SystemSource::new() @@ -166,9 +174,23 @@ mod desktop { } } + for (k, data) in DATA_CACHE.lock().iter() { + if *k == *path { + if let Some(data) = data.upgrade() { + return Ok((FontDataRef(data), *font_index)); + } + } + } + let bytes = std::fs::read(&*path)?; + tracing::debug!("read font `{}:{}`, using {}", path.display(), font_index, bytes.capacity().bytes()); + + let data = Arc::new(bytes); + let mut cache = DATA_CACHE.lock(); + cache.retain(|(_, v)| v.strong_count() > 0); + cache.push((path.to_path_buf(), Arc::downgrade(&data))); - Ok((FontDataRef(Arc::new(bytes)), *font_index)) + Ok((FontDataRef(data), *font_index)) } font_kit::handle::Handle::Memory { bytes, font_index } => Ok((FontDataRef(bytes.clone()), *font_index)), }