diff --git a/examples/editor-libcosmic/src/main.rs b/examples/editor-libcosmic/src/main.rs index a28f826..be2f89a 100644 --- a/examples/editor-libcosmic/src/main.rs +++ b/examples/editor-libcosmic/src/main.rs @@ -139,7 +139,10 @@ impl Application for Window { .family(cosmic_text::Family::Monospace); let mut editor = SyntaxEditor::new( - Buffer::new(&FONT_SYSTEM.lock().unwrap(), FontSize::Body.to_metrics()), + Buffer::new( + &mut FONT_SYSTEM.lock().unwrap(), + FontSize::Body.to_metrics(), + ), &SYNTAX_SYSTEM, "base16-eighties.dark", ) diff --git a/examples/editor-libcosmic/src/text.rs b/examples/editor-libcosmic/src/text.rs index 76c1cea..f0c9c9a 100644 --- a/examples/editor-libcosmic/src/text.rs +++ b/examples/editor-libcosmic/src/text.rs @@ -53,7 +53,7 @@ impl Text { let mut line = BufferLine::new(string, AttrsList::new(Attrs::new())); //TODO: do we have to immediately shape? - line.shape(&FONT_SYSTEM.lock().unwrap()); + line.shape(&mut FONT_SYSTEM.lock().unwrap()); let text = Self { line, @@ -186,7 +186,7 @@ where }; cache.with_pixels( - &FONT_SYSTEM.lock().unwrap(), + &mut FONT_SYSTEM.lock().unwrap(), cache_key, glyph_color, |pixel_x, pixel_y, color| { diff --git a/examples/editor-orbclient/src/main.rs b/examples/editor-orbclient/src/main.rs index 396be80..f784cee 100644 --- a/examples/editor-orbclient/src/main.rs +++ b/examples/editor-orbclient/src/main.rs @@ -58,7 +58,7 @@ fn main() { let line_x = 8.0 * display_scale; let mut editor = SyntaxEditor::new( - Buffer::new(&font_system, font_sizes[font_size_i]), + Buffer::new(&mut font_system, font_sizes[font_size_i]), &syntax_system, "base16-eighties.dark", ) diff --git a/examples/editor-test/src/main.rs b/examples/editor-test/src/main.rs index 69a5498..ea859d5 100644 --- a/examples/editor-test/src/main.rs +++ b/examples/editor-test/src/main.rs @@ -60,7 +60,7 @@ fn main() { ]; let font_size_default = 1; // Body - let mut buffer = Buffer::new(&font_system, font_sizes[font_size_default]); + let mut buffer = Buffer::new(&mut font_system, font_sizes[font_size_default]); buffer .borrow_with(&mut font_system) .set_size(window.width() as f32, window.height() as f32); diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index e8e8213..89bc450 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -37,7 +37,7 @@ fn main() { .unwrap(); let mut editor = Editor::new(Buffer::new( - &font_system, + &mut font_system, Metrics::new(32.0, 44.0).scale(display_scale), )); diff --git a/examples/terminal/src/main.rs b/examples/terminal/src/main.rs index eae3ffe..852207f 100644 --- a/examples/terminal/src/main.rs +++ b/examples/terminal/src/main.rs @@ -15,7 +15,7 @@ fn main() { let metrics = Metrics::new(14.0, 20.0); // A Buffer provides shaping and layout for a UTF-8 string, create one per text widget - let mut buffer = Buffer::new(&font_system, metrics); + let mut buffer = Buffer::new(&mut font_system, metrics); let mut buffer = buffer.borrow_with(&mut font_system); diff --git a/src/buffer.rs b/src/buffer.rs index 937a60b..d8a67d4 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -317,7 +317,7 @@ impl Buffer { /// # Panics /// /// Will panic if `metrics.line_height` is zero. - pub fn new(font_system: &FontSystem, metrics: Metrics) -> Self { + pub fn new(font_system: &mut FontSystem, metrics: Metrics) -> Self { assert_ne!(metrics.line_height, 0.0, "line height cannot be 0"); let mut buffer = Self { @@ -343,7 +343,7 @@ impl Buffer { } } - pub(crate) fn relayout(&mut self, font_system: &FontSystem) { + pub(crate) fn relayout(&mut self, font_system: &mut FontSystem) { #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let instant = std::time::Instant::now(); @@ -360,7 +360,7 @@ impl Buffer { log::debug!("relayout: {:?}", instant.elapsed()); } - pub(crate) fn shape_until(&mut self, font_system: &FontSystem, lines: i32) -> i32 { + pub(crate) fn shape_until(&mut self, font_system: &mut FontSystem, lines: i32) -> i32 { #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let instant = std::time::Instant::now(); @@ -387,7 +387,7 @@ impl Buffer { total_layout } - pub(crate) fn shape_until_cursor(&mut self, font_system: &FontSystem, cursor: Cursor) { + pub(crate) fn shape_until_cursor(&mut self, font_system: &mut FontSystem, cursor: Cursor) { #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let instant = std::time::Instant::now(); @@ -427,7 +427,7 @@ impl Buffer { self.shape_until_scroll(font_system); } - pub(crate) fn shape_until_scroll(&mut self, font_system: &FontSystem) { + pub(crate) fn shape_until_scroll(&mut self, font_system: &mut FontSystem) { let lines = self.visible_lines(); let scroll_end = self.scroll + lines; @@ -468,7 +468,7 @@ impl Buffer { pub(crate) fn line_shape( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, line_i: usize, ) -> Option<&ShapeLine> { let line = self.lines.get_mut(line_i)?; @@ -477,7 +477,7 @@ impl Buffer { pub(crate) fn line_layout( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, line_i: usize, ) -> Option<&[LayoutLine]> { let line = self.lines.get_mut(line_i)?; @@ -489,7 +489,7 @@ impl Buffer { self.metrics } - fn set_metrics(&mut self, font_system: &FontSystem, metrics: Metrics) { + fn set_metrics(&mut self, font_system: &mut FontSystem, metrics: Metrics) { if metrics != self.metrics { assert_ne!(metrics.font_size, 0.0, "font size cannot be 0"); self.metrics = metrics; @@ -503,7 +503,7 @@ impl Buffer { self.wrap } - pub(crate) fn set_wrap(&mut self, font_system: &FontSystem, wrap: Wrap) { + pub(crate) fn set_wrap(&mut self, font_system: &mut FontSystem, wrap: Wrap) { if wrap != self.wrap { self.wrap = wrap; self.relayout(font_system); @@ -516,7 +516,7 @@ impl Buffer { (self.width, self.height) } - pub(crate) fn set_size(&mut self, font_system: &FontSystem, width: f32, height: f32) { + pub(crate) fn set_size(&mut self, font_system: &mut FontSystem, width: f32, height: f32) { let clamped_width = width.max(0.0); let clamped_height = height.max(0.0); @@ -546,7 +546,7 @@ impl Buffer { (self.height / self.metrics.line_height) as i32 } - pub(crate) fn set_text(&mut self, font_system: &FontSystem, text: &str, attrs: Attrs) { + pub(crate) fn set_text(&mut self, font_system: &mut FontSystem, text: &str, attrs: Attrs) { self.lines.clear(); for line in text.lines() { self.lines @@ -682,7 +682,7 @@ impl Buffer { #[cfg(feature = "swash")] pub(crate) fn draw( &self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache: &mut crate::SwashCache, color: Color, mut f: F, @@ -758,7 +758,7 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> { /// Draw the buffer #[cfg(feature = "swash")] - pub fn draw(&self, cache: &mut crate::SwashCache, color: Color, f: F) + pub fn draw(&mut self, cache: &mut crate::SwashCache, color: Color, f: F) where F: FnMut(i32, i32, u32, u32, Color), { diff --git a/src/buffer_line.rs b/src/buffer_line.rs index e9b7e0b..3ff511a 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -167,7 +167,7 @@ impl BufferLine { } /// Shape line, will cache results - pub fn shape(&mut self, font_system: &FontSystem) -> &ShapeLine { + pub fn shape(&mut self, font_system: &mut FontSystem) -> &ShapeLine { if self.shape_opt.is_none() { self.shape_opt = Some(ShapeLine::new(font_system, &self.text, &self.attrs_list)); self.layout_opt = None; @@ -183,7 +183,7 @@ impl BufferLine { /// Layout line, will cache results pub fn layout( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, font_size: f32, width: f32, wrap: Wrap, diff --git a/src/edit/editor.rs b/src/edit/editor.rs index d97216e..a0987e3 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -35,7 +35,7 @@ impl Editor { } } - fn set_layout_cursor(&mut self, font_system: &FontSystem, cursor: LayoutCursor) { + pub(crate) fn set_layout_cursor(&mut self, font_system: &mut FontSystem, cursor: LayoutCursor) { let layout = self .buffer .line_layout(font_system, cursor.line) @@ -94,7 +94,7 @@ impl Edit for Editor { } } - fn shape_as_needed(&mut self, font_system: &FontSystem) { + fn shape_as_needed(&mut self, font_system: &mut FontSystem) { if self.cursor_moved { self.buffer.shape_until_cursor(font_system, self.cursor); self.cursor_moved = false; @@ -281,7 +281,7 @@ impl Edit for Editor { self.cursor.index = self.buffer.lines[self.cursor.line].text().len() - after_len; } - fn action(&mut self, font_system: &FontSystem, action: Action) { + fn action(&mut self, font_system: &mut FontSystem, action: Action) { let old_cursor = self.cursor; match action { @@ -677,7 +677,7 @@ impl Edit for Editor { #[cfg(feature = "swash")] fn draw( &self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache: &mut crate::SwashCache, color: Color, mut f: F, diff --git a/src/edit/mod.rs b/src/edit/mod.rs index b7ddee8..4cd1b2b 100644 --- a/src/edit/mod.rs +++ b/src/edit/mod.rs @@ -108,7 +108,7 @@ pub trait Edit { fn set_select_opt(&mut self, select_opt: Option); /// Shape lines until scroll, after adjusting scroll if the cursor moved - fn shape_as_needed(&mut self, font_system: &FontSystem); + fn shape_as_needed(&mut self, font_system: &mut FontSystem); /// Copy selection fn copy_selection(&mut self) -> Option; @@ -122,12 +122,17 @@ pub trait Edit { fn insert_string(&mut self, data: &str, attrs_list: Option); /// Perform an [Action] on the editor - fn action(&mut self, font_system: &FontSystem, action: Action); + fn action(&mut self, font_system: &mut FontSystem, action: Action); /// Draw the editor #[cfg(feature = "swash")] - fn draw(&self, font_system: &FontSystem, cache: &mut crate::SwashCache, color: Color, f: F) - where + fn draw( + &self, + font_system: &mut FontSystem, + cache: &mut crate::SwashCache, + color: Color, + f: F, + ) where F: FnMut(i32, i32, u32, u32, Color); } @@ -152,7 +157,7 @@ impl<'a, T: Edit> BorrowedWithFontSystem<'a, T> { /// Draw the editor #[cfg(feature = "swash")] - pub fn draw(&self, cache: &mut crate::SwashCache, color: Color, f: F) + pub fn draw(&mut self, cache: &mut crate::SwashCache, color: Color, f: F) where F: FnMut(i32, i32, u32, u32, Color), { diff --git a/src/edit/syntect.rs b/src/edit/syntect.rs index 7c7e3da..c1d8dea 100644 --- a/src/edit/syntect.rs +++ b/src/edit/syntect.rs @@ -63,7 +63,7 @@ impl<'a> SyntaxEditor<'a> { #[cfg(feature = "std")] pub(crate) fn load_text>( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, path: P, attrs: crate::Attrs, ) -> io::Result<()> { @@ -131,7 +131,7 @@ impl<'a> Edit for SyntaxEditor<'a> { self.editor.set_select_opt(select_opt); } - fn shape_as_needed(&mut self, font_system: &FontSystem) { + fn shape_as_needed(&mut self, font_system: &mut FontSystem) { #[cfg(feature = "std")] let now = std::time::Instant::now(); @@ -236,7 +236,7 @@ impl<'a> Edit for SyntaxEditor<'a> { self.editor.insert_string(data, attrs_list); } - fn action(&mut self, font_system: &FontSystem, action: Action) { + fn action(&mut self, font_system: &mut FontSystem, action: Action) { self.editor.action(font_system, action); } @@ -244,7 +244,7 @@ impl<'a> Edit for SyntaxEditor<'a> { #[cfg(feature = "swash")] fn draw( &self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache: &mut crate::SwashCache, _color: Color, mut f: F, diff --git a/src/edit/vi.rs b/src/edit/vi.rs index e1ef722..666d4db 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -32,7 +32,7 @@ impl<'a> ViEditor<'a> { #[cfg(feature = "std")] pub(crate) fn load_text>( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, path: P, attrs: crate::Attrs, ) -> std::io::Result<()> { @@ -71,7 +71,7 @@ impl<'a> Edit for ViEditor<'a> { self.editor.set_select_opt(select_opt); } - fn shape_as_needed(&mut self, font_system: &FontSystem) { + fn shape_as_needed(&mut self, font_system: &mut FontSystem) { self.editor.shape_as_needed(font_system); } @@ -87,7 +87,7 @@ impl<'a> Edit for ViEditor<'a> { self.editor.insert_string(data, attrs_list); } - fn action(&mut self, font_system: &FontSystem, action: Action) { + fn action(&mut self, font_system: &mut FontSystem, action: Action) { let old_mode = self.mode; match self.mode { @@ -229,7 +229,7 @@ impl<'a> Edit for ViEditor<'a> { #[cfg(feature = "swash")] fn draw( &self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache: &mut crate::SwashCache, color: Color, mut f: F, diff --git a/src/font/system/no_std.rs b/src/font/system/no_std.rs index 70318f6..e402615 100644 --- a/src/font/system/no_std.rs +++ b/src/font/system/no_std.rs @@ -44,24 +44,17 @@ impl FontSystem { } pub fn get_font(&self, id: fontdb::ID) -> Option> { - 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 - } - } + get_font(&self.db, id) } - pub fn get_font_matches(&self, attrs: Attrs) -> Arc>> { + pub fn get_font_matches(&mut self, attrs: Attrs) -> Arc>> { let mut fonts = Vec::new(); for face in self.db.faces() { if !attrs.matches(face) { continue; } - if let Some(font) = self.get_font(face.id) { + if let Some(font) = get_font(&self.db, face.id) { fonts.push(font); } } @@ -69,3 +62,14 @@ impl FontSystem { Arc::new(fonts) } } + +fn get_font(db: &fontdb::Database, id: fontdb::ID) -> Option> { + let face = 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 + } + } +} diff --git a/src/font/system/std.rs b/src/font/system/std.rs index 3f8e0e0..7ac5cbe 100644 --- a/src/font/system/std.rs +++ b/src/font/system/std.rs @@ -1,9 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; +use std::{collections::HashMap, sync::Arc}; use crate::{Attrs, AttrsOwned, Font}; @@ -11,8 +8,8 @@ use crate::{Attrs, AttrsOwned, Font}; pub struct FontSystem { locale: String, db: fontdb::Database, - font_cache: Mutex>>>, - font_matches_cache: Mutex>>>>, + font_cache: HashMap>>, + font_matches_cache: HashMap>>>, } impl FontSystem { @@ -88,8 +85,8 @@ impl FontSystem { Self { locale, db, - font_cache: Mutex::new(HashMap::new()), - font_matches_cache: Mutex::new(HashMap::new()), + font_cache: HashMap::new(), + font_matches_cache: HashMap::new(), } } @@ -105,44 +102,28 @@ impl FontSystem { (self.locale, self.db) } - pub fn get_font(&self, id: fontdb::ID) -> Option> { - self.font_cache - .lock() - .expect("failed to lock 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 get_font(&mut self, id: fontdb::ID) -> Option> { + get_font(&mut self.font_cache, &mut self.db, id) } - pub fn get_font_matches(&self, attrs: Attrs) -> Arc>> { + pub fn get_font_matches(&mut self, attrs: Attrs) -> Arc>> { self.font_matches_cache - .lock() - .expect("failed to lock font matches cache") //TODO: do not create AttrsOwned unless entry does not already exist .entry(AttrsOwned::new(attrs)) .or_insert_with(|| { #[cfg(not(target_arch = "wasm32"))] let now = std::time::Instant::now(); - let mut fonts = Vec::new(); - for face in self.db.faces() { - if !attrs.matches(face) { - continue; - } - - if let Some(font) = self.get_font(face.id) { - fonts.push(font); - } - } + let ids = self + .db + .faces() + .filter(|face| attrs.matches(face)) + .map(|face| face.id) + .collect::>(); + let fonts = ids + .into_iter() + .filter_map(|id| get_font(&mut self.font_cache, &mut self.db, id)) + .collect(); #[cfg(not(target_arch = "wasm32"))] { @@ -155,3 +136,23 @@ impl FontSystem { .clone() } } + +fn get_font( + font_cache: &mut HashMap>>, + db: &mut fontdb::Database, + id: fontdb::ID, +) -> Option> { + font_cache + .entry(id) + .or_insert_with(|| { + let face = 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() +} diff --git a/src/shape.rs b/src/shape.rs index 4cc0346..dae7bc5 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -99,7 +99,7 @@ fn shape_fallback( } fn shape_run( - font_system: &FontSystem, + font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList, start_run: usize, @@ -273,7 +273,7 @@ pub struct ShapeWord { impl ShapeWord { pub fn new( - font_system: &FontSystem, + font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList, word_range: Range, @@ -347,7 +347,7 @@ pub struct ShapeSpan { impl ShapeSpan { pub fn new( - font_system: &FontSystem, + font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList, span_range: Range, @@ -431,7 +431,7 @@ impl ShapeLine { /// # Panics /// /// Will panic if `line` contains more than one paragraph. - pub fn new(font_system: &FontSystem, line: &str, attrs_list: &AttrsList) -> Self { + pub fn new(font_system: &mut FontSystem, line: &str, attrs_list: &AttrsList) -> Self { let mut spans = Vec::new(); let bidi = unicode_bidi::BidiInfo::new(line, None); diff --git a/src/swash.rs b/src/swash.rs index f951c3e..363c900 100644 --- a/src/swash.rs +++ b/src/swash.rs @@ -16,7 +16,7 @@ pub use swash::scale::image::{Content as SwashContent, Image as SwashImage}; pub use swash::zeno::{Command, Placement}; fn swash_image( - font_system: &FontSystem, + font_system: &mut FontSystem, context: &mut ScaleContext, cache_key: CacheKey, ) -> Option { @@ -57,7 +57,7 @@ fn swash_image( } fn swash_outline_commands( - font_system: &FontSystem, + font_system: &mut FontSystem, context: &mut ScaleContext, cache_key: CacheKey, ) -> Option> { @@ -109,7 +109,7 @@ impl SwashCache { /// Create a swash Image from a cache key, without caching results pub fn get_image_uncached( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache_key: CacheKey, ) -> Option { swash_image(font_system, &mut self.context, cache_key) @@ -118,7 +118,7 @@ impl SwashCache { /// Create a swash Image from a cache key, caching results pub fn get_image( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache_key: CacheKey, ) -> &Option { self.image_cache @@ -128,7 +128,7 @@ impl SwashCache { pub fn get_outline_commands( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache_key: CacheKey, ) -> Option<&[swash::zeno::Command]> { self.outline_command_cache @@ -140,7 +140,7 @@ impl SwashCache { /// Enumerate pixels in an Image, use `with_image` for better performance pub fn with_pixels( &mut self, - font_system: &FontSystem, + font_system: &mut FontSystem, cache_key: CacheKey, base: Color, mut f: F,