Browse Source

Pass around Arc<Galley> to avoid copying a lot of data

pull/275/head
Emil Ernerfeldt 4 years ago
parent
commit
1c60dc8d66
  1. 2
      egui/src/containers/window.rs
  2. 4
      egui/src/painter.rs
  3. 27
      egui/src/widgets/label.rs
  4. 5
      egui_demo_lib/benches/benchmark.rs
  5. 2
      epaint/src/shape.rs
  6. 13
      epaint/src/text/fonts.rs

2
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<Galley>,
min_rect: Rect,
rect: Rect,
}

4
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<Galley>, color: Color32) {
self.galley_with_italics(pos, galley, color, false)
}
pub fn galley_with_italics(
&self,
pos: Pos2,
galley: Galley,
galley: std::sync::Arc<Galley>,
color: Color32,
fake_italics: bool,
) {

27
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<Galley> {
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<Galley> {
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<Galley>) {
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<Galley>, 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<Galley>,
) -> Arc<Galley> {
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);

5
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());

2
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<Galley>,
/// Text color (foreground).
color: Color32,
/// If true, tilt the letters for a hacky italics effect.

13
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<Galley> {
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<Galley> {
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<Galley> {
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<Galley> {
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<Galley>,
}
#[derive(Default)]
@ -388,7 +388,7 @@ struct GalleyCache {
}
impl GalleyCache {
fn layout(&mut self, fonts: &BTreeMap<TextStyle, Font>, job: LayoutJob) -> Galley {
fn layout(&mut self, fonts: &BTreeMap<TextStyle, Font>, job: LayoutJob) -> Arc<Galley> {
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 {

Loading…
Cancel
Save