diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index 496ed2136..1512f0ed5 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -673,7 +673,7 @@ fn paint_frame_interaction( struct TitleBar { id: Id, title_label: Label, - title_galley: Galley, + title_galley: std::sync::Arc, min_rect: Rect, rect: Rect, } diff --git a/egui/src/painter.rs b/egui/src/painter.rs index f4b85c4dd..27f2ec8a5 100644 --- a/egui/src/painter.rs +++ b/egui/src/painter.rs @@ -302,14 +302,14 @@ impl Painter { } /// Paint text that has already been layed out in a `Galley`. - pub fn galley(&self, pos: Pos2, galley: Galley, color: Color32) { + pub fn galley(&self, pos: Pos2, galley: std::sync::Arc, color: Color32) { self.galley_with_italics(pos, galley, color, false) } pub fn galley_with_italics( &self, pos: Pos2, - galley: Galley, + galley: std::sync::Arc, color: Color32, fake_italics: bool, ) { diff --git a/egui/src/widgets/label.rs b/egui/src/widgets/label.rs index e3f0f1b9a..bc7dab49a 100644 --- a/egui/src/widgets/label.rs +++ b/egui/src/widgets/label.rs @@ -1,5 +1,6 @@ use crate::*; use epaint::Galley; +use std::sync::Arc; /// Static text. /// @@ -143,12 +144,12 @@ impl Label { } impl Label { - pub fn layout(&self, ui: &Ui) -> Galley { + pub fn layout(&self, ui: &Ui) -> Arc { let max_width = ui.available_width(); self.layout_width(ui, max_width) } - pub fn layout_width(&self, ui: &Ui, max_width: f32) -> Galley { + pub fn layout_width(&self, ui: &Ui, max_width: f32) -> Arc { let text_style = self.text_style_or_default(ui.style()); let wrap_width = if self.should_wrap(ui) { max_width @@ -174,11 +175,11 @@ impl Label { // TODO: a paint method for painting anywhere in a ui. // This should be the easiest method of putting text anywhere. - pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: Galley) { + pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: Arc) { self.paint_galley_focus(ui, pos, galley, false) } - fn paint_galley_focus(&self, ui: &mut Ui, pos: Pos2, galley: Galley, focus: bool) { + fn paint_galley_focus(&self, ui: &mut Ui, pos: Pos2, galley: Arc, focus: bool) { let Self { mut background_color, code, @@ -256,7 +257,12 @@ impl Label { }) } - fn valign_galley(&self, ui: &Ui, text_style: TextStyle, mut galley: Galley) -> Galley { + fn valign_galley( + &self, + ui: &Ui, + text_style: TextStyle, + mut galley: Arc, + ) -> Arc { if text_style == TextStyle::Small { // Hacky McHackface strikes again: let dy = if self.raised { @@ -269,8 +275,10 @@ impl Label { // normal_text_heigth - font_height // align bottom }; - for row in &mut galley.rows { - row.translate_y(dy); + if dy != 0.0 { + for row in &mut Arc::make_mut(&mut galley).rows { + row.translate_y(dy); + } } } galley @@ -293,12 +301,13 @@ impl Widget for Label { let first_row_indentation = max_width - ui.available_size_before_wrap().x; let text_style = self.text_style_or_default(ui.style()); - let mut galley = ui.fonts().layout_multiline_with_indentation_and_max_width( + let galley = ui.fonts().layout_multiline_with_indentation_and_max_width( text_style, self.text.clone(), first_row_indentation, max_width, ); + let mut galley: Galley = (*galley).clone(); let pos = pos2(ui.max_rect().left(), ui.cursor().top()); @@ -321,7 +330,7 @@ impl Widget for Label { } } - let galley = self.valign_galley(ui, text_style, galley); + let galley = self.valign_galley(ui, text_style, Arc::new(galley)); let rect = galley.rows[0].rect().translate(vec2(pos.x, pos.y)); let mut response = ui.allocate_rect(rect, sense); diff --git a/egui_demo_lib/benches/benchmark.rs b/egui_demo_lib/benches/benchmark.rs index 1390ca433..46c24dae1 100644 --- a/egui_demo_lib/benches/benchmark.rs +++ b/egui_demo_lib/benches/benchmark.rs @@ -75,9 +75,12 @@ pub fn criterion_benchmark(c: &mut Criterion) { egui::FontDefinitions::default(), ); let font = &fonts[text_style]; - c.bench_function("text layout", |b| { + c.bench_function("text layout (uncached)", |b| { b.iter(|| font.layout_multiline(LOREM_IPSUM_LONG.to_owned(), wrap_width)) }); + c.bench_function("text layout (cached)", |b| { + b.iter(|| fonts.layout_multiline(text_style, LOREM_IPSUM_LONG.to_owned(), wrap_width)) + }); let galley = font.layout_multiline(LOREM_IPSUM_LONG.to_owned(), wrap_width); let mut tessellator = egui::epaint::Tessellator::from_options(Default::default()); diff --git a/epaint/src/shape.rs b/epaint/src/shape.rs index 357064e26..de99f8e23 100644 --- a/epaint/src/shape.rs +++ b/epaint/src/shape.rs @@ -43,7 +43,7 @@ pub enum Shape { /// Top left corner of the first character.. pos: Pos2, /// The layed out text. - galley: Galley, + galley: std::sync::Arc, /// Text color (foreground). color: Color32, /// If true, tilt the letters for a hacky italics effect. diff --git a/epaint/src/text/fonts.rs b/epaint/src/text/fonts.rs index 4aeef40e4..6d36d0e52 100644 --- a/epaint/src/text/fonts.rs +++ b/epaint/src/text/fonts.rs @@ -278,7 +278,7 @@ impl Fonts { /// Always returns at least one row. /// Will line break at `\n`. - pub fn layout_no_wrap(&self, text_style: TextStyle, text: String) -> Galley { + pub fn layout_no_wrap(&self, text_style: TextStyle, text: String) -> Arc { self.layout_multiline(text_style, text, f32::INFINITY) } @@ -288,7 +288,7 @@ impl Fonts { /// /// Most often you probably want `\n` to produce a new row, /// and so [`Self::layout_no_wrap`] may be a better choice. - pub fn layout_single_line(&self, text_style: TextStyle, text: String) -> Galley { + pub fn layout_single_line(&self, text_style: TextStyle, text: String) -> Arc { self.galley_cache.lock().layout( &self.fonts, LayoutJob { @@ -306,7 +306,7 @@ impl Fonts { text_style: TextStyle, text: String, max_width_in_points: f32, - ) -> Galley { + ) -> Arc { self.layout_multiline_with_indentation_and_max_width( text_style, text, @@ -324,7 +324,7 @@ impl Fonts { text: String, first_row_indentation: f32, max_width_in_points: f32, - ) -> Galley { + ) -> Arc { self.galley_cache.lock().layout( &self.fonts, LayoutJob { @@ -377,7 +377,7 @@ struct LayoutJob { struct CachedGalley { /// When it was last used last_used: u32, - galley: Galley, // TODO: use an Arc instead! + galley: Arc, } #[derive(Default)] @@ -388,7 +388,7 @@ struct GalleyCache { } impl GalleyCache { - fn layout(&mut self, fonts: &BTreeMap, job: LayoutJob) -> Galley { + fn layout(&mut self, fonts: &BTreeMap, job: LayoutJob) -> Arc { if let Some(cached) = self.cache.get_mut(&job) { cached.last_used = self.generation; cached.galley.clone() @@ -410,6 +410,7 @@ impl GalleyCache { max_width_in_points.into_inner(), ), }; + let galley = Arc::new(galley); self.cache.insert( job, CachedGalley {