diff --git a/Cargo.toml b/Cargo.toml index a358327..b40a098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/pop-os/cosmic-text" fontdb = { version = "0.13.0", default-features = false } libm = "0.2.6" log = "0.4.17" -ouroboros = "0.15.5" +ouroboros = { version = "0.15.5", default-features = false } rustybuzz = { version = "0.7.0", default-features = false, features = ["libm"] } swash = { version = "0.1.6", optional = true } syntect = { version = "5.0.0", optional = true } @@ -35,6 +35,7 @@ no_std = [ std = [ "fontdb/memmap", "fontdb/std", + "ouroboros/std", "rustybuzz/std", "sys-locale", "unicode-bidi/std", diff --git a/examples/editor-libcosmic/src/main.rs b/examples/editor-libcosmic/src/main.rs index 7c8c591..be2f89a 100644 --- a/examples/editor-libcosmic/src/main.rs +++ b/examples/editor-libcosmic/src/main.rs @@ -23,7 +23,7 @@ use self::text_box::text_box; mod text_box; lazy_static::lazy_static! { - static ref FONT_SYSTEM: FontSystem = FontSystem::new(); + static ref FONT_SYSTEM: Mutex = Mutex::new(FontSystem::new()); static ref SYNTAX_SYSTEM: SyntaxSystem = SyntaxSystem::new(); } @@ -112,6 +112,8 @@ pub enum Message { impl Window { pub fn open(&mut self, path: PathBuf) { let mut editor = self.editor.lock().unwrap(); + let mut font_system = FONT_SYSTEM.lock().unwrap(); + let mut editor = editor.borrow_with(&mut font_system); match editor.load_text(&path, self.attrs) { Ok(()) => { log::info!("opened '{}'", path.display()); @@ -137,7 +139,10 @@ impl Application for Window { .family(cosmic_text::Family::Monospace); let mut editor = SyntaxEditor::new( - Buffer::new(&FONT_SYSTEM, FontSize::Body.to_metrics()), + Buffer::new( + &mut FONT_SYSTEM.lock().unwrap(), + FontSize::Body.to_metrics(), + ), &SYNTAX_SYSTEM, "base16-eighties.dark", ) @@ -169,11 +174,11 @@ impl Application for Window { if let Some(path) = &self.path_opt { format!( "COSMIC Text - {} - {}", - FONT_SYSTEM.locale(), + FONT_SYSTEM.lock().unwrap().locale(), path.display() ) } else { - format!("COSMIC Text - {}", FONT_SYSTEM.locale()) + format!("COSMIC Text - {}", FONT_SYSTEM.lock().unwrap().locale()) } } @@ -237,13 +242,18 @@ impl Application for Window { } Message::FontSizeChanged(font_size) => { self.font_size = font_size; - let mut editor = self.editor.lock().unwrap(); - editor.buffer_mut().set_metrics(font_size.to_metrics()); + editor + .borrow_with(&mut FONT_SYSTEM.lock().unwrap()) + .buffer_mut() + .set_metrics(font_size.to_metrics()); } Message::WrapChanged(wrap) => { let mut editor = self.editor.lock().unwrap(); - editor.buffer_mut().set_wrap(wrap); + editor + .borrow_with(&mut FONT_SYSTEM.lock().unwrap()) + .buffer_mut() + .set_wrap(wrap); } Message::AlignmentChanged(align) => { let mut editor = self.editor.lock().unwrap(); @@ -360,13 +370,13 @@ impl Application for Window { } } -fn update_attrs<'a, T: Edit<'a>>(editor: &mut T, attrs: Attrs<'a>) { +fn update_attrs(editor: &mut T, attrs: Attrs) { editor.buffer_mut().lines.iter_mut().for_each(|line| { line.set_attrs_list(AttrsList::new(attrs)); }); } -fn update_alignment<'a, T: Edit<'a>>(editor: &mut T, align: Align) { +fn update_alignment(editor: &mut T, align: Align) { let current_line = editor.cursor().line; if let Some(select) = editor.select_opt() { let (start, end) = match select.line.cmp(¤t_line) { diff --git a/examples/editor-libcosmic/src/text.rs b/examples/editor-libcosmic/src/text.rs index 2ffc3af..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(&crate::FONT_SYSTEM); + line.shape(&mut FONT_SYSTEM.lock().unwrap()); let text = Self { line, @@ -186,7 +186,7 @@ where }; cache.with_pixels( - &FONT_SYSTEM, + &mut FONT_SYSTEM.lock().unwrap(), cache_key, glyph_color, |pixel_x, pixel_y, color| { diff --git a/examples/editor-libcosmic/src/text_box.rs b/examples/editor-libcosmic/src/text_box.rs index 241adc1..a5463e6 100644 --- a/examples/editor-libcosmic/src/text_box.rs +++ b/examples/editor-libcosmic/src/text_box.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 +use crate::FONT_SYSTEM; + use super::text; use cosmic::{ iced_native::{ @@ -66,11 +68,11 @@ pub fn text_box(editor: &Mutex) -> TextBox { TextBox::new(editor) } -impl<'a, 'editor, Editor, Message, Renderer> Widget for TextBox<'a, Editor> +impl<'a, Editor, Message, Renderer> Widget for TextBox<'a, Editor> where Renderer: renderer::Renderer + image::Renderer, Renderer::Theme: StyleSheet, - Editor: Edit<'editor>, + Editor: Edit, { fn tag(&self) -> tree::Tag { tree::Tag::of::() @@ -93,7 +95,10 @@ where //TODO: allow lazy shape let mut editor = self.editor.lock().unwrap(); - editor.buffer_mut().shape_until(i32::max_value()); + editor + .borrow_with(&mut FONT_SYSTEM.lock().unwrap()) + .buffer_mut() + .shape_until(i32::max_value()); let mut layout_lines = 0; for line in editor.buffer().lines.iter() { @@ -162,6 +167,10 @@ where let view_w = viewport.width.min(layout.bounds().width) - self.padding.horizontal() as f32; let view_h = viewport.height.min(layout.bounds().height) - self.padding.vertical() as f32; + + let mut font_system = FONT_SYSTEM.lock().unwrap(); + let mut editor = editor.borrow_with(&mut font_system); + editor.buffer_mut().set_size(view_w, view_h); editor.shape_as_needed(); @@ -232,6 +241,8 @@ where ) -> Status { let state = tree.state.downcast_mut::(); let mut editor = self.editor.lock().unwrap(); + let mut font_system = FONT_SYSTEM.lock().unwrap(); + let mut editor = editor.borrow_with(&mut font_system); let mut status = Status::Ignored; match event { @@ -330,12 +341,11 @@ where } } -impl<'a, 'editor, Editor, Message, Renderer> From> - for Element<'a, Message, Renderer> +impl<'a, Editor, Message, Renderer> From> for Element<'a, Message, Renderer> where Renderer: renderer::Renderer + image::Renderer, Renderer::Theme: StyleSheet, - Editor: Edit<'editor>, + Editor: Edit, { fn from(text_box: TextBox<'a, Editor>) -> Self { Self::new(text_box) diff --git a/examples/editor-orbclient/src/main.rs b/examples/editor-orbclient/src/main.rs index 0ceed80..f784cee 100644 --- a/examples/editor-orbclient/src/main.rs +++ b/examples/editor-orbclient/src/main.rs @@ -40,7 +40,7 @@ fn main() { ) .unwrap(); - let font_system = FontSystem::new(); + let mut font_system = FontSystem::new(); let syntax_system = SyntaxSystem::new(); @@ -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", ) @@ -67,6 +67,8 @@ fn main() { #[cfg(feature = "vi")] let mut editor = cosmic_text::ViEditor::new(editor); + let mut editor = editor.borrow_with(&mut font_system); + editor .buffer_mut() .set_size(window.width() as f32 - line_x * 2.0, window.height() as f32); diff --git a/examples/editor-test/src/main.rs b/examples/editor-test/src/main.rs index 0b627fa..ea859d5 100644 --- a/examples/editor-test/src/main.rs +++ b/examples/editor-test/src/main.rs @@ -1,11 +1,17 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use cosmic_text::{Action, Buffer, Color, Edit, Editor, FontSystem, Metrics, SwashCache}; +use cosmic_text::{ + Action, BorrowedWithFontSystem, Buffer, Color, Edit, Editor, FontSystem, Metrics, SwashCache, +}; use orbclient::{EventOption, Renderer, Window, WindowFlag}; use std::{env, fs, process, time::Instant}; use unicode_segmentation::UnicodeSegmentation; -fn redraw(window: &mut Window, editor: &mut Editor<'_>, swash_cache: &mut SwashCache) { +fn redraw( + window: &mut Window, + editor: &mut BorrowedWithFontSystem, + swash_cache: &mut SwashCache, +) { let bg_color = orbclient::Color::rgb(0x34, 0x34, 0x34); let font_color = Color::rgb(0xFF, 0xFF, 0xFF); @@ -32,7 +38,7 @@ fn main() { env_logger::init(); let display_scale = 1.0; - let font_system = FontSystem::new(); + let mut font_system = FontSystem::new(); let mut window = Window::new_flags( -1, @@ -54,11 +60,15 @@ fn main() { ]; let font_size_default = 1; // Body - let mut buffer = Buffer::new(&font_system, font_sizes[font_size_default]); - buffer.set_size(window.width() as f32, window.height() as f32); + 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); let mut editor = Editor::new(buffer); + let mut editor = editor.borrow_with(&mut font_system); + let mut swash_cache = SwashCache::new(); let text = if let Some(arg) = env::args().nth(1) { diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index fa5132c..89bc450 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -13,7 +13,7 @@ use std::{ fn main() { env_logger::init(); - let font_system = FontSystem::new(); + let mut font_system = FontSystem::new(); let display_scale = match orbclient::get_display_size() { Ok((w, h)) => { @@ -37,10 +37,12 @@ fn main() { .unwrap(); let mut editor = Editor::new(Buffer::new( - &font_system, + &mut font_system, Metrics::new(32.0, 44.0).scale(display_scale), )); + let mut editor = editor.borrow_with(&mut font_system); + editor .buffer_mut() .set_size(window.width() as f32, window.height() as f32); diff --git a/examples/terminal/src/main.rs b/examples/terminal/src/main.rs index b55b354..852207f 100644 --- a/examples/terminal/src/main.rs +++ b/examples/terminal/src/main.rs @@ -6,7 +6,7 @@ use termion::{color, cursor}; fn main() { // A FontSystem provides access to detected system fonts, create one per application - let font_system = FontSystem::new(); + let mut font_system = FontSystem::new(); // A SwashCache stores rasterized glyphs, create one per application let mut swash_cache = SwashCache::new(); @@ -15,7 +15,9 @@ 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); // Set a size for the text buffer, in pixels let width = 80u16; diff --git a/src/buffer.rs b/src/buffer.rs index 144fcd5..497cafd 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -10,7 +10,10 @@ use unicode_segmentation::UnicodeSegmentation; #[cfg(feature = "swash")] use crate::Color; -use crate::{Attrs, AttrsList, BufferLine, FontSystem, LayoutGlyph, LayoutLine, ShapeLine, Wrap}; +use crate::{ + Attrs, AttrsList, BorrowedWithFontSystem, BufferLine, FontSystem, LayoutGlyph, LayoutLine, + ShapeLine, Wrap, +}; /// Current cursor location #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)] @@ -169,8 +172,8 @@ impl<'a> LayoutRun<'a> { } /// An iterator of visible text lines, see [`LayoutRun`] -pub struct LayoutRunIter<'a, 'b> { - buffer: &'b Buffer<'a>, +pub struct LayoutRunIter<'b> { + buffer: &'b Buffer, line_i: usize, layout_i: usize, remaining_len: usize, @@ -178,8 +181,8 @@ pub struct LayoutRunIter<'a, 'b> { total_layout: i32, } -impl<'a, 'b> LayoutRunIter<'a, 'b> { - pub fn new(buffer: &'b Buffer<'a>) -> Self { +impl<'b> LayoutRunIter<'b> { + pub fn new(buffer: &'b Buffer) -> Self { let total_layout_lines: usize = buffer .lines .iter() @@ -215,7 +218,7 @@ impl<'a, 'b> LayoutRunIter<'a, 'b> { } } -impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> { +impl<'b> Iterator for LayoutRunIter<'b> { type Item = LayoutRun<'b>; fn size_hint(&self) -> (usize, Option) { @@ -258,7 +261,7 @@ impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> { } } -impl<'a, 'b> ExactSizeIterator for LayoutRunIter<'a, 'b> {} +impl<'b> ExactSizeIterator for LayoutRunIter<'b> {} /// Metrics of text #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -296,8 +299,7 @@ impl fmt::Display for Metrics { } /// A buffer of text that is shaped and laid out -pub struct Buffer<'a> { - font_system: &'a FontSystem, +pub struct Buffer { /// [BufferLine]s (or paragraphs) of text in the buffer pub lines: Vec, metrics: Metrics, @@ -309,17 +311,16 @@ pub struct Buffer<'a> { wrap: Wrap, } -impl<'a> Buffer<'a> { +impl Buffer { /// Create a new [`Buffer`] with the provided [`FontSystem`] and [`Metrics`] /// /// # Panics /// /// Will panic if `metrics.line_height` is zero. - pub fn new(font_system: &'a 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 { - font_system, lines: Vec::new(), metrics, width: 0.0, @@ -328,23 +329,29 @@ impl<'a> Buffer<'a> { redraw: false, wrap: Wrap::Word, }; - buffer.set_text("", Attrs::new()); + buffer.set_text(font_system, "", Attrs::new()); buffer } - fn relayout(&mut self) { + /// Mutably borrows the buffer together with an [`FontSystem`] for more convenient methods + pub fn borrow_with<'a>( + &'a mut self, + font_system: &'a mut FontSystem, + ) -> BorrowedWithFontSystem<'a, Buffer> { + BorrowedWithFontSystem { + inner: self, + font_system, + } + } + + fn relayout(&mut self, font_system: &mut FontSystem) { #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let instant = std::time::Instant::now(); for line in &mut self.lines { if line.shape_opt().is_some() { line.reset_layout(); - line.layout( - self.font_system, - self.metrics.font_size, - self.width, - self.wrap, - ); + line.layout(font_system, self.metrics.font_size, self.width, self.wrap); } } @@ -355,7 +362,7 @@ impl<'a> Buffer<'a> { } /// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines - pub fn shape_until(&mut self, lines: i32) -> i32 { + pub 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(); @@ -369,12 +376,7 @@ impl<'a> Buffer<'a> { if line.shape_opt().is_none() { reshaped += 1; } - let layout = line.layout( - self.font_system, - self.metrics.font_size, - self.width, - self.wrap, - ); + let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap); total_layout += layout.len() as i32; } @@ -388,7 +390,7 @@ impl<'a> Buffer<'a> { } /// Shape lines until cursor, also scrolling to include cursor in view - pub fn shape_until_cursor(&mut self, cursor: Cursor) { + pub 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(); @@ -402,12 +404,7 @@ impl<'a> Buffer<'a> { if line.shape_opt().is_none() { reshaped += 1; } - let layout = line.layout( - self.font_system, - self.metrics.font_size, - self.width, - self.wrap, - ); + let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap); if line_i == cursor.line { let layout_cursor = self.layout_cursor(&cursor); layout_i += layout_cursor.layout as i32; @@ -430,15 +427,15 @@ impl<'a> Buffer<'a> { self.scroll = layout_i - (lines - 1); } - self.shape_until_scroll(); + self.shape_until_scroll(font_system); } /// Shape lines until scroll - pub fn shape_until_scroll(&mut self) { + pub fn shape_until_scroll(&mut self, font_system: &mut FontSystem) { let lines = self.visible_lines(); let scroll_end = self.scroll + lines; - let total_layout = self.shape_until(scroll_end); + let total_layout = self.shape_until(font_system, scroll_end); self.scroll = cmp::max(0, cmp::min(total_layout - (lines - 1), self.scroll)); } @@ -473,26 +470,24 @@ impl<'a> Buffer<'a> { LayoutCursor::new(cursor.line, 0, 0) } - /// Get [`FontSystem`] used by this [`Buffer`] - pub fn font_system(&self) -> &'a FontSystem { - self.font_system - } - /// Shape the provided line index and return the result - pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> { + pub fn line_shape( + &mut self, + font_system: &mut FontSystem, + line_i: usize, + ) -> Option<&ShapeLine> { let line = self.lines.get_mut(line_i)?; - Some(line.shape(self.font_system)) + Some(line.shape(font_system)) } /// Lay out the provided line index and return the result - pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> { + pub fn line_layout( + &mut self, + font_system: &mut FontSystem, + line_i: usize, + ) -> Option<&[LayoutLine]> { let line = self.lines.get_mut(line_i)?; - Some(line.layout( - self.font_system, - self.metrics.font_size, - self.width, - self.wrap, - )) + Some(line.layout(font_system, self.metrics.font_size, self.width, self.wrap)) } /// Get the current [`Metrics`] @@ -505,12 +500,12 @@ impl<'a> Buffer<'a> { /// # Panics /// /// Will panic if `metrics.font_size` is zero. - pub fn set_metrics(&mut self, metrics: Metrics) { + pub 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; - self.relayout(); - self.shape_until_scroll(); + self.relayout(font_system); + self.shape_until_scroll(font_system); } } @@ -520,11 +515,11 @@ impl<'a> Buffer<'a> { } /// Set the current [`Wrap`] - pub fn set_wrap(&mut self, wrap: Wrap) { + pub fn set_wrap(&mut self, font_system: &mut FontSystem, wrap: Wrap) { if wrap != self.wrap { self.wrap = wrap; - self.relayout(); - self.shape_until_scroll(); + self.relayout(font_system); + self.shape_until_scroll(font_system); } } @@ -534,15 +529,15 @@ impl<'a> Buffer<'a> { } /// Set the current buffer dimensions - pub fn set_size(&mut self, width: f32, height: f32) { + pub 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); if clamped_width != self.width || clamped_height != self.height { self.width = clamped_width; self.height = clamped_height; - self.relayout(); - self.shape_until_scroll(); + self.relayout(font_system); + self.shape_until_scroll(font_system); } } @@ -565,7 +560,7 @@ impl<'a> Buffer<'a> { } /// Set text of buffer, using provided attributes for each line by default - pub fn set_text(&mut self, text: &str, attrs: Attrs<'a>) { + pub fn set_text(&mut self, font_system: &mut FontSystem, text: &str, attrs: Attrs) { self.lines.clear(); for line in text.lines() { self.lines @@ -579,7 +574,7 @@ impl<'a> Buffer<'a> { self.scroll = 0; - self.shape_until_scroll(); + self.shape_until_scroll(font_system); } /// True if a redraw is needed @@ -593,7 +588,7 @@ impl<'a> Buffer<'a> { } /// Get the visible layout runs for rendering and other tasks - pub fn layout_runs<'b>(&'b self) -> LayoutRunIter<'a, 'b> { + pub fn layout_runs(&self) -> LayoutRunIter { LayoutRunIter::new(self) } @@ -700,8 +695,13 @@ impl<'a> Buffer<'a> { /// Draw the buffer #[cfg(feature = "swash")] - pub fn draw(&self, cache: &mut crate::SwashCache, color: Color, mut f: F) - where + pub fn draw( + &self, + font_system: &mut FontSystem, + cache: &mut crate::SwashCache, + color: Color, + mut f: F, + ) where F: FnMut(i32, i32, u32, u32, Color), { for run in self.layout_runs() { @@ -713,10 +713,70 @@ impl<'a> Buffer<'a> { None => color, }; - cache.with_pixels(self.font_system, cache_key, glyph_color, |x, y, color| { + cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| { f(x_int + x, run.line_y as i32 + y_int + y, 1, 1, color); }); } } } } + +impl<'a> BorrowedWithFontSystem<'a, Buffer> { + /// Pre-shape lines in the buffer, up to `lines`, return actual number of layout lines + pub fn shape_until(&mut self, lines: i32) -> i32 { + self.inner.shape_until(self.font_system, lines) + } + + /// Shape lines until cursor, also scrolling to include cursor in view + pub fn shape_until_cursor(&mut self, cursor: Cursor) { + self.inner.shape_until_cursor(self.font_system, cursor); + } + + /// Shape lines until scroll + pub fn shape_until_scroll(&mut self) { + self.inner.shape_until_scroll(self.font_system); + } + + /// Shape the provided line index and return the result + pub fn line_shape(&mut self, line_i: usize) -> Option<&ShapeLine> { + self.inner.line_shape(self.font_system, line_i) + } + + /// Lay out the provided line index and return the result + pub fn line_layout(&mut self, line_i: usize) -> Option<&[LayoutLine]> { + self.inner.line_layout(self.font_system, line_i) + } + + /// Set the current [`Metrics`] + /// + /// # Panics + /// + /// Will panic if `metrics.font_size` is zero. + pub fn set_metrics(&mut self, metrics: Metrics) { + self.inner.set_metrics(self.font_system, metrics); + } + + /// Set the current [`Wrap`] + pub fn set_wrap(&mut self, wrap: Wrap) { + self.inner.set_wrap(self.font_system, wrap); + } + + /// Set the current buffer dimensions + pub fn set_size(&mut self, width: f32, height: f32) { + self.inner.set_size(self.font_system, width, height); + } + + /// Set text of buffer, using provided attributes for each line by default + pub fn set_text(&mut self, text: &str, attrs: Attrs) { + self.inner.set_text(self.font_system, text, attrs); + } + + /// Draw the buffer + #[cfg(feature = "swash")] + pub fn draw(&mut self, cache: &mut crate::SwashCache, color: Color, f: F) + where + F: FnMut(i32, i32, u32, u32, Color), + { + self.inner.draw(self.font_system, cache, color, f); + } +} 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 5d0325f..1b82018 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -10,20 +10,22 @@ use unicode_segmentation::UnicodeSegmentation; #[cfg(feature = "swash")] use crate::Color; -use crate::{Action, Affinity, AttrsList, Buffer, BufferLine, Cursor, Edit, LayoutCursor}; +use crate::{ + Action, Affinity, AttrsList, Buffer, BufferLine, Cursor, Edit, FontSystem, LayoutCursor, +}; /// A wrapper of [`Buffer`] for easy editing -pub struct Editor<'a> { - buffer: Buffer<'a>, +pub struct Editor { + buffer: Buffer, cursor: Cursor, cursor_x_opt: Option, select_opt: Option, cursor_moved: bool, } -impl<'a> Editor<'a> { +impl Editor { /// Create a new [`Editor`] with the provided [`Buffer`] - pub fn new(buffer: Buffer<'a>) -> Self { + pub fn new(buffer: Buffer) -> Self { Self { buffer, cursor: Cursor::default(), @@ -33,10 +35,10 @@ impl<'a> Editor<'a> { } } - fn set_layout_cursor(&mut self, cursor: LayoutCursor) { + fn set_layout_cursor(&mut self, font_system: &mut FontSystem, cursor: LayoutCursor) { let layout = self .buffer - .line_layout(cursor.line) + .line_layout(font_system, cursor.line) .expect("layout not found"); let layout_line = match layout.get(cursor.layout) { @@ -68,12 +70,12 @@ impl<'a> Editor<'a> { } } -impl<'a> Edit<'a> for Editor<'a> { - fn buffer(&self) -> &Buffer<'a> { +impl Edit for Editor { + fn buffer(&self) -> &Buffer { &self.buffer } - fn buffer_mut(&mut self) -> &mut Buffer<'a> { + fn buffer_mut(&mut self) -> &mut Buffer { &mut self.buffer } @@ -92,12 +94,12 @@ impl<'a> Edit<'a> for Editor<'a> { } } - fn shape_as_needed(&mut self) { + fn shape_as_needed(&mut self, font_system: &mut FontSystem) { if self.cursor_moved { - self.buffer.shape_until_cursor(self.cursor); + self.buffer.shape_until_cursor(font_system, self.cursor); self.cursor_moved = false; } else { - self.buffer.shape_until_scroll(); + self.buffer.shape_until_scroll(font_system); } } @@ -279,7 +281,7 @@ impl<'a> Edit<'a> for Editor<'a> { self.cursor.index = self.buffer.lines[self.cursor.line].text().len() - after_len; } - fn action(&mut self, action: Action) { + fn action(&mut self, font_system: &mut FontSystem, action: Action) { let old_cursor = self.cursor; match action { @@ -333,9 +335,9 @@ impl<'a> Edit<'a> for Editor<'a> { .map(|shape| shape.rtl); if let Some(rtl) = rtl_opt { if rtl { - self.action(Action::Next); + self.action(font_system, Action::Next); } else { - self.action(Action::Previous); + self.action(font_system, Action::Previous); } } } @@ -346,9 +348,9 @@ impl<'a> Edit<'a> for Editor<'a> { .map(|shape| shape.rtl); if let Some(rtl) = rtl_opt { if rtl { - self.action(Action::Previous); + self.action(font_system, Action::Previous); } else { - self.action(Action::Next); + self.action(font_system, Action::Next); } } } @@ -373,7 +375,7 @@ impl<'a> Edit<'a> for Editor<'a> { cursor.glyph = cursor_x as usize; //TODO: glyph x position } - self.set_layout_cursor(cursor); + self.set_layout_cursor(font_system, cursor); } Action::Down => { //TODO: make this preserve X as best as possible! @@ -381,7 +383,7 @@ impl<'a> Edit<'a> for Editor<'a> { let layout_len = self .buffer - .line_layout(cursor.line) + .line_layout(font_system, cursor.line) .expect("layout not found") .len(); @@ -402,18 +404,18 @@ impl<'a> Edit<'a> for Editor<'a> { cursor.glyph = cursor_x as usize; //TODO: glyph x position } - self.set_layout_cursor(cursor); + self.set_layout_cursor(font_system, cursor); } Action::Home => { let mut cursor = self.buffer.layout_cursor(&self.cursor); cursor.glyph = 0; - self.set_layout_cursor(cursor); + self.set_layout_cursor(font_system, cursor); self.cursor_x_opt = None; } Action::End => { let mut cursor = self.buffer.layout_cursor(&self.cursor); cursor.glyph = usize::max_value(); - self.set_layout_cursor(cursor); + self.set_layout_cursor(font_system, cursor); self.cursor_x_opt = None; } Action::ParagraphStart => { @@ -427,10 +429,10 @@ impl<'a> Edit<'a> for Editor<'a> { self.buffer.set_redraw(true); } Action::PageUp => { - self.action(Action::Vertical(-self.buffer.size().1 as i32)); + self.action(font_system, Action::Vertical(-self.buffer.size().1 as i32)); } Action::PageDown => { - self.action(Action::Vertical(self.buffer.size().1 as i32)); + self.action(font_system, Action::Vertical(self.buffer.size().1 as i32)); } Action::Vertical(px) => { // TODO more efficient @@ -438,12 +440,12 @@ impl<'a> Edit<'a> for Editor<'a> { match lines.cmp(&0) { Ordering::Less => { for _ in 0..-lines { - self.action(Action::Up); + self.action(font_system, Action::Up); } } Ordering::Greater => { for _ in 0..lines { - self.action(Action::Down); + self.action(font_system, Action::Down); } } Ordering::Equal => {} @@ -459,7 +461,7 @@ impl<'a> Edit<'a> for Editor<'a> { // Filter out special chars (except for tab), use Action instead log::debug!("Refusing to insert control character {:?}", character); } else if character == '\n' { - self.action(Action::Enter); + self.action(font_system, Action::Enter); } else { let mut str_buf = [0u8; 8]; let str_ref = character.encode_utf8(&mut str_buf); @@ -619,9 +621,9 @@ impl<'a> Edit<'a> for Editor<'a> { .map(|shape| shape.rtl); if let Some(rtl) = rtl_opt { if rtl { - self.action(Action::NextWord); + self.action(font_system, Action::NextWord); } else { - self.action(Action::PreviousWord); + self.action(font_system, Action::PreviousWord); } } } @@ -632,9 +634,9 @@ impl<'a> Edit<'a> for Editor<'a> { .map(|shape| shape.rtl); if let Some(rtl) = rtl_opt { if rtl { - self.action(Action::PreviousWord); + self.action(font_system, Action::PreviousWord); } else { - self.action(Action::NextWord); + self.action(font_system, Action::NextWord); } } } @@ -673,8 +675,13 @@ impl<'a> Edit<'a> for Editor<'a> { /// Draw the editor #[cfg(feature = "swash")] - fn draw(&self, cache: &mut crate::SwashCache, color: Color, mut f: F) - where + fn draw( + &self, + font_system: &mut FontSystem, + cache: &mut crate::SwashCache, + color: Color, + mut f: F, + ) where F: FnMut(i32, i32, u32, u32, Color), { let font_size = self.buffer.metrics().font_size; @@ -833,14 +840,9 @@ impl<'a> Edit<'a> for Editor<'a> { None => color, }; - cache.with_pixels( - self.buffer.font_system(), - cache_key, - glyph_color, - |x, y, color| { - f(x_int + x, line_y as i32 + y_int + y, 1, 1, color); - }, - ); + cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| { + f(x_int + x, line_y as i32 + y_int + y, 1, 1, color); + }); } } } diff --git a/src/edit/mod.rs b/src/edit/mod.rs index 43f7f8d..15ed8f3 100644 --- a/src/edit/mod.rs +++ b/src/edit/mod.rs @@ -3,7 +3,7 @@ use alloc::string::String; #[cfg(feature = "swash")] use crate::Color; -use crate::{AttrsList, Buffer, Cursor}; +use crate::{AttrsList, BorrowedWithFontSystem, Buffer, Cursor, FontSystem}; pub use self::editor::*; mod editor; @@ -78,12 +78,26 @@ pub enum Action { } /// A trait to allow easy replacements of [`Editor`], like `SyntaxEditor` -pub trait Edit<'a> { +pub trait Edit { + /// Mutably borrows `self` together with an [`FontSystem`] for more convenient methods + fn borrow_with<'a>( + &'a mut self, + font_system: &'a mut FontSystem, + ) -> BorrowedWithFontSystem<'a, Self> + where + Self: Sized, + { + BorrowedWithFontSystem { + inner: self, + font_system, + } + } + /// Get the internal [`Buffer`] - fn buffer(&self) -> &Buffer<'a>; + fn buffer(&self) -> &Buffer; /// Get the internal [`Buffer`], mutably - fn buffer_mut(&mut self) -> &mut Buffer<'a>; + fn buffer_mut(&mut self) -> &mut Buffer; /// Get the current cursor position fn cursor(&self) -> Cursor; @@ -95,7 +109,7 @@ pub trait Edit<'a> { 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); + fn shape_as_needed(&mut self, font_system: &mut FontSystem); /// Copy selection fn copy_selection(&mut self) -> Option; @@ -109,11 +123,45 @@ pub trait Edit<'a> { fn insert_string(&mut self, data: &str, attrs_list: Option); /// Perform an [Action] on the editor - fn action(&mut self, action: Action); + fn action(&mut self, font_system: &mut FontSystem, action: Action); /// Draw the editor #[cfg(feature = "swash")] - fn draw(&self, 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); } + +impl<'a, T: Edit> BorrowedWithFontSystem<'a, T> { + /// Get the internal [`Buffer`], mutably + pub fn buffer_mut(&mut self) -> BorrowedWithFontSystem { + BorrowedWithFontSystem { + inner: self.inner.buffer_mut(), + font_system: self.font_system, + } + } + + /// Shape lines until scroll, after adjusting scroll if the cursor moved + pub fn shape_as_needed(&mut self) { + self.inner.shape_as_needed(self.font_system); + } + + /// Perform an [Action] on the editor + pub fn action(&mut self, action: Action) { + self.inner.action(self.font_system, action); + } + + /// Draw the editor + #[cfg(feature = "swash")] + pub fn draw(&mut self, cache: &mut crate::SwashCache, color: Color, f: F) + where + F: FnMut(i32, i32, u32, u32, Color), + { + self.inner.draw(self.font_system, cache, color, f); + } +} diff --git a/src/edit/syntect.rs b/src/edit/syntect.rs index 14a41ee..f454285 100644 --- a/src/edit/syntect.rs +++ b/src/edit/syntect.rs @@ -7,7 +7,10 @@ use syntect::highlighting::{ }; use syntect::parsing::{ParseState, ScopeStack, SyntaxReference, SyntaxSet}; -use crate::{Action, AttrsList, Buffer, Color, Cursor, Edit, Editor, Style, Weight, Wrap}; +use crate::{ + Action, AttrsList, BorrowedWithFontSystem, Buffer, Color, Cursor, Edit, Editor, FontSystem, + Style, Weight, Wrap, +}; pub struct SyntaxSystem { pub syntax_set: SyntaxSet, @@ -27,7 +30,7 @@ impl SyntaxSystem { /// A wrapper of [`Editor`] with syntax highlighting provided by [`SyntaxSystem`] pub struct SyntaxEditor<'a> { - editor: Editor<'a>, + editor: Editor, syntax_system: &'a SyntaxSystem, syntax: &'a SyntaxReference, theme: &'a Theme, @@ -41,11 +44,7 @@ impl<'a> SyntaxEditor<'a> { /// A good default theme name is "base16-eighties.dark". /// /// Returns None if theme not found - pub fn new( - buffer: Buffer<'a>, - syntax_system: &'a SyntaxSystem, - theme_name: &str, - ) -> Option { + pub fn new(buffer: Buffer, syntax_system: &'a SyntaxSystem, theme_name: &str) -> Option { let editor = Editor::new(buffer); let syntax = syntax_system.syntax_set.find_syntax_plain_text(); let theme = syntax_system.theme_set.themes.get(theme_name)?; @@ -69,13 +68,14 @@ impl<'a> SyntaxEditor<'a> { #[cfg(feature = "std")] pub fn load_text>( &mut self, + font_system: &mut FontSystem, path: P, - attrs: crate::Attrs<'a>, + attrs: crate::Attrs, ) -> io::Result<()> { let path = path.as_ref(); let text = fs::read_to_string(path)?; - self.editor.buffer_mut().set_text(&text, attrs); + self.editor.buffer_mut().set_text(font_system, &text, attrs); //TODO: re-use text self.syntax = match self.syntax_system.syntax_set.find_syntax_for_file(path) { @@ -115,12 +115,12 @@ impl<'a> SyntaxEditor<'a> { } } -impl<'a> Edit<'a> for SyntaxEditor<'a> { - fn buffer(&self) -> &Buffer<'a> { +impl<'a> Edit for SyntaxEditor<'a> { + fn buffer(&self) -> &Buffer { self.editor.buffer() } - fn buffer_mut(&mut self) -> &mut Buffer<'a> { + fn buffer_mut(&mut self) -> &mut Buffer { self.editor.buffer_mut() } @@ -136,7 +136,7 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> { self.editor.set_select_opt(select_opt); } - fn shape_as_needed(&mut self) { + fn shape_as_needed(&mut self, font_system: &mut FontSystem) { #[cfg(feature = "std")] let now = std::time::Instant::now(); @@ -201,7 +201,7 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> { line.set_wrap(Wrap::Word); //TODO: efficiently do syntax highlighting without having to shape whole buffer - buffer.line_shape(line_i); + buffer.line_shape(font_system, line_i); let cache_item = (parse_state.clone(), highlight_state.clone()); if line_i < self.syntax_cache.len() { @@ -226,7 +226,7 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> { ); } - self.editor.shape_as_needed(); + self.editor.shape_as_needed(font_system); } fn copy_selection(&mut self) -> Option { @@ -241,18 +241,36 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> { self.editor.insert_string(data, attrs_list); } - fn action(&mut self, action: Action) { - self.editor.action(action); + fn action(&mut self, font_system: &mut FontSystem, action: Action) { + self.editor.action(font_system, action); } /// Draw the editor #[cfg(feature = "swash")] - fn draw(&self, cache: &mut crate::SwashCache, _color: Color, mut f: F) - where + fn draw( + &self, + font_system: &mut FontSystem, + cache: &mut crate::SwashCache, + _color: Color, + mut f: F, + ) where F: FnMut(i32, i32, u32, u32, Color), { let size = self.buffer().size(); f(0, 0, size.0 as u32, size.1 as u32, self.background_color()); - self.editor.draw(cache, self.foreground_color(), f); + self.editor + .draw(font_system, cache, self.foreground_color(), f); + } +} + +impl<'a, 'b> BorrowedWithFontSystem<'b, SyntaxEditor<'a>> { + /// Load text from a file, and also set syntax to the best option + /// + /// ## Errors + /// + /// Returns an [`io::Error`] if reading the file fails + #[cfg(feature = "std")] + pub fn load_text>(&mut self, path: P, attrs: crate::Attrs) -> io::Result<()> { + self.inner.load_text(self.font_system, path, attrs) } } diff --git a/src/edit/vi.rs b/src/edit/vi.rs index 22bbc78..690edd3 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -2,7 +2,10 @@ use alloc::string::String; use core::cmp; use unicode_segmentation::UnicodeSegmentation; -use crate::{Action, AttrsList, Buffer, Color, Cursor, Edit, SyntaxEditor}; +use crate::{ + Action, AttrsList, BorrowedWithFontSystem, Buffer, Color, Cursor, Edit, FontSystem, + SyntaxEditor, +}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum Mode { @@ -30,10 +33,11 @@ impl<'a> ViEditor<'a> { #[cfg(feature = "std")] pub fn load_text>( &mut self, + font_system: &mut FontSystem, path: P, - attrs: crate::Attrs<'a>, + attrs: crate::Attrs, ) -> std::io::Result<()> { - self.editor.load_text(path, attrs) + self.editor.load_text(font_system, path, attrs) } /// Get the default background color @@ -47,12 +51,12 @@ impl<'a> ViEditor<'a> { } } -impl<'a> Edit<'a> for ViEditor<'a> { - fn buffer(&self) -> &Buffer<'a> { +impl<'a> Edit for ViEditor<'a> { + fn buffer(&self) -> &Buffer { self.editor.buffer() } - fn buffer_mut(&mut self) -> &mut Buffer<'a> { + fn buffer_mut(&mut self) -> &mut Buffer { self.editor.buffer_mut() } @@ -68,8 +72,8 @@ impl<'a> Edit<'a> for ViEditor<'a> { self.editor.set_select_opt(select_opt); } - fn shape_as_needed(&mut self) { - self.editor.shape_as_needed() + fn shape_as_needed(&mut self, font_system: &mut FontSystem) { + self.editor.shape_as_needed(font_system); } fn copy_selection(&mut self) -> Option { @@ -84,7 +88,7 @@ impl<'a> Edit<'a> for ViEditor<'a> { self.editor.insert_string(data, attrs_list); } - fn action(&mut self, action: Action) { + fn action(&mut self, font_system: &mut FontSystem, action: Action) { let old_mode = self.mode; match self.mode { @@ -92,18 +96,18 @@ impl<'a> Edit<'a> for ViEditor<'a> { Action::Insert(c) => match c { // Enter insert mode after cursor 'a' => { - self.editor.action(Action::Right); + self.editor.action(font_system, Action::Right); self.mode = Mode::Insert; } // Enter insert mode at end of line 'A' => { - self.editor.action(Action::End); + self.editor.action(font_system, Action::End); self.mode = Mode::Insert; } // Change mode 'c' => { if self.editor.select_opt().is_some() { - self.editor.action(Action::Delete); + self.editor.action(font_system, Action::Delete); self.mode = Mode::Insert; } else { //TODO: change to next cursor movement @@ -112,7 +116,7 @@ impl<'a> Edit<'a> for ViEditor<'a> { // Delete mode 'd' => { if self.editor.select_opt().is_some() { - self.editor.action(Action::Delete); + self.editor.action(font_system, Action::Delete); } else { //TODO: delete to next cursor movement } @@ -124,33 +128,33 @@ impl<'a> Edit<'a> for ViEditor<'a> { // Enter insert mode at start of line 'I' => { //TODO: soft home, skip whitespace - self.editor.action(Action::Home); + self.editor.action(font_system, Action::Home); self.mode = Mode::Insert; } // Create line after and enter insert mode 'o' => { - self.editor.action(Action::End); - self.editor.action(Action::Enter); + self.editor.action(font_system, Action::End); + self.editor.action(font_system, Action::Enter); self.mode = Mode::Insert; } // Create line before and enter insert mode 'O' => { - self.editor.action(Action::Home); - self.editor.action(Action::Enter); - self.editor.shape_as_needed(); // TODO: do not require this? - self.editor.action(Action::Up); + self.editor.action(font_system, Action::Home); + self.editor.action(font_system, Action::Enter); + self.editor.shape_as_needed(font_system); // TODO: do not require this? + self.editor.action(font_system, Action::Up); self.mode = Mode::Insert; } // Left - 'h' => self.editor.action(Action::Left), + 'h' => self.editor.action(font_system, Action::Left), // Top of screen //TODO: 'H' => self.editor.action(Action::ScreenHigh), // Down - 'j' => self.editor.action(Action::Down), + 'j' => self.editor.action(font_system, Action::Down), // Up - 'k' => self.editor.action(Action::Up), + 'k' => self.editor.action(font_system, Action::Up), // Right - 'l' => self.editor.action(Action::Right), + 'l' => self.editor.action(font_system, Action::Right), // Bottom of screen //TODO: 'L' => self.editor.action(Action::ScreenLow), // Middle of screen @@ -168,23 +172,23 @@ impl<'a> Edit<'a> for ViEditor<'a> { if self.editor.select_opt().is_some() { self.editor.set_select_opt(None); } else { - self.editor.action(Action::Home); + self.editor.action(font_system, Action::Home); self.editor.set_select_opt(Some(self.editor.cursor())); //TODO: set cursor_x_opt to max - self.editor.action(Action::End); + self.editor.action(font_system, Action::End); } } // Remove character at cursor - 'x' => self.editor.action(Action::Delete), + 'x' => self.editor.action(font_system, Action::Delete), // Remove character before cursor - 'X' => self.editor.action(Action::Backspace), + 'X' => self.editor.action(font_system, Action::Backspace), // Go to start of line - '0' => self.editor.action(Action::Home), + '0' => self.editor.action(font_system, Action::Home), // Go to end of line - '$' => self.editor.action(Action::End), + '$' => self.editor.action(font_system, Action::End), // Go to start of line after whitespace //TODO: implement this - '^' => self.editor.action(Action::Home), + '^' => self.editor.action(font_system, Action::Home), // Enter command mode ':' => { self.mode = Mode::Command; @@ -199,18 +203,18 @@ impl<'a> Edit<'a> for ViEditor<'a> { } _ => (), }, - _ => self.editor.action(action), + _ => self.editor.action(font_system, action), }, Mode::Insert => match action { Action::Escape => { let cursor = self.cursor(); let layout_cursor = self.buffer().layout_cursor(&cursor); if layout_cursor.glyph > 0 { - self.editor.action(Action::Left); + self.editor.action(font_system, Action::Left); } self.mode = Mode::Normal; } - _ => self.editor.action(action), + _ => self.editor.action(font_system, action), }, _ => { //TODO: other modes @@ -224,8 +228,13 @@ impl<'a> Edit<'a> for ViEditor<'a> { } #[cfg(feature = "swash")] - fn draw(&self, cache: &mut crate::SwashCache, color: Color, mut f: F) - where + fn draw( + &self, + font_system: &mut FontSystem, + cache: &mut crate::SwashCache, + color: Color, + mut f: F, + ) where F: FnMut(i32, i32, u32, u32, Color), { let font_size = self.buffer().metrics().font_size; @@ -421,15 +430,22 @@ impl<'a> Edit<'a> for ViEditor<'a> { None => color, }; - cache.with_pixels( - self.buffer().font_system(), - cache_key, - glyph_color, - |x, y, color| { - f(x_int + x, line_y as i32 + y_int + y, 1, 1, color); - }, - ); + cache.with_pixels(font_system, cache_key, glyph_color, |x, y, color| { + f(x_int + x, line_y as i32 + y_int + y, 1, 1, color); + }); } } } } + +impl<'a, 'b> BorrowedWithFontSystem<'b, ViEditor<'a>> { + /// Load text from a file, and also set syntax to the best option + #[cfg(feature = "std")] + pub fn load_text>( + &mut self, + path: P, + attrs: crate::Attrs, + ) -> std::io::Result<()> { + self.inner.load_text(self.font_system, path, attrs) + } +} diff --git a/src/font/fallback/mod.rs b/src/font/fallback/mod.rs index d8abf88..410dfac 100644 --- a/src/font/fallback/mod.rs +++ b/src/font/fallback/mod.rs @@ -3,9 +3,10 @@ use alloc::sync::Arc; #[cfg(not(feature = "std"))] use alloc::vec::Vec; +use fontdb::Family; use unicode_script::Script; -use crate::Font; +use crate::{Font, FontSystem}; use self::platform::*; @@ -26,11 +27,11 @@ mod platform; mod platform; pub struct FontFallbackIter<'a> { - fonts: &'a [Arc>], - default_families: &'a [&'a str], + font_system: &'a mut FontSystem, + font_ids: &'a [fontdb::ID], + default_families: &'a [&'a Family<'a>], default_i: usize, scripts: Vec