diff --git a/src/buffer.rs b/src/buffer.rs index fd85c74..227b228 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -10,7 +10,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::{ Attrs, AttrsList, BidiParagraphs, BorrowedWithFontSystem, BufferLine, Color, FontSystem, - LayoutGlyph, LayoutLine, ShapeLine, Shaping, Wrap, + LayoutGlyph, LayoutLine, ShapeBuffer, ShapeLine, Shaping, Wrap, }; /// Current cursor location @@ -330,6 +330,9 @@ pub struct Buffer { /// True if a redraw is requires. Set to false after processing redraw: bool, wrap: Wrap, + + /// Scratch buffer for shaping and laying out. + scratch: ShapeBuffer, } impl Buffer { @@ -354,6 +357,7 @@ impl Buffer { scroll: 0, redraw: false, wrap: Wrap::Word, + scratch: ShapeBuffer::default(), } } @@ -411,7 +415,13 @@ impl Buffer { if line.shape_opt().is_none() { reshaped += 1; } - let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap); + let layout = line.layout_in_buffer( + &mut self.scratch, + font_system, + self.metrics.font_size, + self.width, + self.wrap, + ); total_layout += layout.len() as i32; } @@ -439,7 +449,13 @@ impl Buffer { if line.shape_opt().is_none() { reshaped += 1; } - let layout = line.layout(font_system, self.metrics.font_size, self.width, self.wrap); + let layout = line.layout_in_buffer( + &mut self.scratch, + 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; diff --git a/src/buffer_line.rs b/src/buffer_line.rs index ae8d149..667cc80 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; -use crate::{Align, AttrsList, FontSystem, LayoutLine, ShapeLine, Shaping, Wrap}; +use crate::{Align, AttrsList, FontSystem, LayoutLine, ShapeBuffer, ShapeLine, Shaping, Wrap}; /// A line (or paragraph) of text that is shaped and laid out #[derive(Debug)] @@ -169,8 +169,18 @@ impl BufferLine { /// Shape line, will cache results pub fn shape(&mut self, font_system: &mut FontSystem) -> &ShapeLine { + self.shape_in_buffer(&mut ShapeBuffer::default(), font_system) + } + + /// Shape a line using a pre-existing shape buffer. + pub fn shape_in_buffer( + &mut self, + scratch: &mut ShapeBuffer, + font_system: &mut FontSystem, + ) -> &ShapeLine { if self.shape_opt.is_none() { - self.shape_opt = Some(ShapeLine::new( + self.shape_opt = Some(ShapeLine::new_in_buffer( + scratch, font_system, &self.text, &self.attrs_list, @@ -204,6 +214,26 @@ impl BufferLine { self.layout_opt.as_ref().expect("layout not found") } + /// Layout a line using a pre-existing shape buffer. + pub fn layout_in_buffer( + &mut self, + scratch: &mut ShapeBuffer, + font_system: &mut FontSystem, + font_size: f32, + width: f32, + wrap: Wrap, + ) -> &[LayoutLine] { + if self.layout_opt.is_none() { + self.wrap = wrap; + let align = self.align; + let shape = self.shape_in_buffer(scratch, font_system); + let mut layout = Vec::with_capacity(1); + shape.layout_to_buffer(scratch, font_size, width, wrap, align, &mut layout); + self.layout_opt = Some(layout); + } + self.layout_opt.as_ref().expect("layout not found") + } + /// Get line layout cache pub fn layout_opt(&self) -> &Option> { &self.layout_opt diff --git a/src/font/fallback/mod.rs b/src/font/fallback/mod.rs index dbabcee..4cf4382 100644 --- a/src/font/fallback/mod.rs +++ b/src/font/fallback/mod.rs @@ -36,7 +36,7 @@ pub struct FontFallbackIter<'a> { font_ids: &'a [fontdb::ID], default_families: &'a [&'a Family<'a>], default_i: usize, - scripts: Vec