diff --git a/crates/egui/src/atomics/atom_ext.rs b/crates/egui/src/atomics/atom_ext.rs index 0c34544d8..6d008b84b 100644 --- a/crates/egui/src/atomics/atom_ext.rs +++ b/crates/egui/src/atomics/atom_ext.rs @@ -60,7 +60,7 @@ pub trait AtomExt<'a> { { let font_selection = FontSelection::default(); let font_id = font_selection.resolve(ui.style()); - let height = ui.fonts(|f| f.row_height(&font_id)); + let height = ui.fonts_mut(|f| f.row_height(&font_id)); self.atom_max_height(height) } } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 39190d7a6..c3c45dfe4 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -476,7 +476,7 @@ impl Window<'_> { let (title_bar_height_with_margin, title_content_spacing) = if with_title_bar { let style = ctx.style(); let title_bar_inner_height = ctx - .fonts(|fonts| title.font_height(fonts, &style)) + .fonts_mut(|fonts| title.font_height(fonts, &style)) .at_least(style.spacing.interact_size.y); let title_bar_inner_height = title_bar_inner_height + window_frame.inner_margin.sum().y; let half_height = (title_bar_inner_height / 2.0).round() as _; diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 8dbbc2c1d..4b08f6eeb 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -641,7 +641,7 @@ impl ContextImpl { // Preload the most common characters for the most common fonts. // This is not very important to do, but may save a few GPU operations. for font_id in self.memory.options.style().text_styles.values() { - fonts.lock().fonts.font(font_id).preload_common_characters(); + fonts.fonts.font(font_id).preload_common_characters(); } } } @@ -1060,6 +1060,22 @@ impl Context { }) } + /// Read-write access to [`Fonts`]. + /// + /// Not valid until first call to [`Context::run()`]. + /// That's because since we don't know the proper `pixels_per_point` until then. + #[inline] + pub fn fonts_mut(&self, reader: impl FnOnce(&mut Fonts) -> R) -> R { + self.write(move |ctx| { + let pixels_per_point = ctx.pixels_per_point(); + reader( + ctx.fonts + .get_mut(&pixels_per_point.into()) + .expect("No fonts available until first call to Context::run()"), + ) + }) + } + /// Read-only access to [`Options`]. #[inline] pub fn options(&self, reader: impl FnOnce(&Options) -> R) -> R { @@ -1568,9 +1584,8 @@ impl Context { } = ModifierNames::SYMBOLS; let font_id = TextStyle::Body.resolve(&self.style()); - self.fonts(|f| { - let mut lock = f.lock(); - let font = lock.fonts.font(&font_id); + self.fonts_mut(|f| { + let font = f.fonts.font(&font_id); font.has_glyphs(alt) && font.has_glyphs(ctrl) && font.has_glyphs(shift) @@ -1927,7 +1942,7 @@ impl Context { self.read(|ctx| { if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) { // NOTE: this comparison is expensive since it checks TTF data for equality - if current_fonts.lock().fonts.definitions() == &font_definitions { + if current_fonts.fonts.definitions() == &font_definitions { update_fonts = false; // no need to update } } @@ -1955,7 +1970,6 @@ impl Context { self.read(|ctx| { if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) { if current_fonts - .lock() .fonts .definitions() .font_data diff --git a/crates/egui/src/debug_text.rs b/crates/egui/src/debug_text.rs index 2cd1a2755..c3f938711 100644 --- a/crates/egui/src/debug_text.rs +++ b/crates/egui/src/debug_text.rs @@ -98,7 +98,7 @@ impl State { { // Paint location to left of `pos`: let location_galley = - ctx.fonts(|f| f.layout(location, font_id.clone(), color, f32::INFINITY)); + ctx.fonts_mut(|f| f.layout(location, font_id.clone(), color, f32::INFINITY)); let location_rect = Align2::RIGHT_TOP.anchor_size(pos - 4.0 * Vec2::X, location_galley.size()); painter.galley(location_rect.min, location_galley, color); diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index fe273970e..cbb36b09e 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -149,6 +149,14 @@ impl Painter { self.ctx.fonts(reader) } + /// Read-write access to the shared [`Fonts`]. + /// + /// See [`Context`] documentation for how locks work. + #[inline] + pub fn fonts_mut(&self, reader: impl FnOnce(&mut Fonts) -> R) -> R { + self.ctx.fonts_mut(reader) + } + /// Where we paint #[inline] pub fn layer_id(&self) -> LayerId { @@ -525,7 +533,7 @@ impl Painter { color: crate::Color32, wrap_width: f32, ) -> Arc { - self.fonts(|f| f.layout(text, font_id, color, wrap_width)) + self.fonts_mut(|f| f.layout(text, font_id, color, wrap_width)) } /// Will line break at `\n`. @@ -539,7 +547,7 @@ impl Painter { font_id: FontId, color: crate::Color32, ) -> Arc { - self.fonts(|f| f.layout(text, font_id, color, f32::INFINITY)) + self.fonts_mut(|f| f.layout(text, font_id, color, f32::INFINITY)) } /// Lay out this text layut job in a galley. @@ -548,7 +556,7 @@ impl Painter { #[inline] #[must_use] pub fn layout_job(&self, layout_job: LayoutJob) -> Arc { - self.fonts(|f| f.layout_job(layout_job)) + self.fonts_mut(|f| f.layout_job(layout_job)) } /// Paint text that has already been laid out in a [`Galley`]. diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index f595469b4..532302339 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -735,7 +735,7 @@ impl Ui { /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. pub fn text_style_height(&self, style: &TextStyle) -> f32 { - self.fonts(|f| f.row_height(&style.resolve(self.style()))) + self.fonts_mut(|f| f.row_height(&style.resolve(self.style()))) } /// Screen-space rectangle for clipping what we paint in this ui. @@ -852,6 +852,12 @@ impl Ui { pub fn fonts(&self, reader: impl FnOnce(&Fonts) -> R) -> R { self.ctx().fonts(reader) } + + /// Read-write access to [`Fonts`]. + #[inline] + pub fn fonts_mut(&self, reader: impl FnOnce(&mut Fonts) -> R) -> R { + self.ctx().fonts_mut(reader) + } } // ------------------------------------------------------------------------ diff --git a/crates/egui/src/widget_text.rs b/crates/egui/src/widget_text.rs index eb0111a76..a7aaf0e07 100644 --- a/crates/egui/src/widget_text.rs +++ b/crates/egui/src/widget_text.rs @@ -307,7 +307,7 @@ impl RichText { /// Read the font height of the selected text style. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - pub fn font_height(&self, fonts: &epaint::Fonts, style: &Style) -> f32 { + pub fn font_height(&self, fonts: &mut epaint::Fonts, style: &Style) -> f32 { let mut font_id = self.text_style.as_ref().map_or_else( || FontSelection::Default.resolve(style), |text_style| text_style.resolve(style), @@ -676,7 +676,7 @@ impl WidgetText { } /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - pub(crate) fn font_height(&self, fonts: &epaint::Fonts, style: &Style) -> f32 { + pub(crate) fn font_height(&self, fonts: &mut epaint::Fonts, style: &Style) -> f32 { match self { Self::Text(_) => fonts.row_height(&FontSelection::Default.resolve(style)), Self::RichText(text) => text.font_height(fonts, style), @@ -762,7 +762,7 @@ impl WidgetText { }, ); layout_job.wrap = text_wrapping; - ctx.fonts(|f| f.layout_job(layout_job)) + ctx.fonts_mut(|f| f.layout_job(layout_job)) } Self::RichText(text) => { let mut layout_job = Arc::unwrap_or_clone(text).into_layout_job( @@ -771,12 +771,12 @@ impl WidgetText { default_valign, ); layout_job.wrap = text_wrapping; - ctx.fonts(|f| f.layout_job(layout_job)) + ctx.fonts_mut(|f| f.layout_job(layout_job)) } Self::LayoutJob(job) => { let mut job = Arc::unwrap_or_clone(job); job.wrap = text_wrapping; - ctx.fonts(|f| f.layout_job(job)) + ctx.fonts_mut(|f| f.layout_job(job)) } Self::Galley(galley) => galley, } diff --git a/crates/egui/src/widgets/label.rs b/crates/egui/src/widgets/label.rs index 007a1291a..992c3a786 100644 --- a/crates/egui/src/widgets/label.rs +++ b/crates/egui/src/widgets/label.rs @@ -211,7 +211,7 @@ impl Label { if let Some(first_section) = layout_job.sections.first_mut() { first_section.leading_space = first_row_indentation; } - let galley = ui.fonts(|fonts| fonts.layout_job(layout_job)); + let galley = ui.fonts_mut(|fonts| fonts.layout_job(layout_job)); let pos = pos2(ui.max_rect().left(), ui.cursor().top()); assert!(!galley.rows.is_empty(), "Galleys are never empty"); @@ -252,7 +252,7 @@ impl Label { layout_job.justify = ui.layout().horizontal_justify(); } - let galley = ui.fonts(|fonts| fonts.layout_job(layout_job)); + let galley = ui.fonts_mut(|fonts| fonts.layout_job(layout_job)); let (rect, mut response) = ui.allocate_exact_size(galley.size(), sense); response.intrinsic_size = Some(galley.intrinsic_size()); let galley_pos = match galley.job.halign { diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 63dec9238..fa8cffe96 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -504,7 +504,7 @@ impl TextEdit<'_> { let hint_text_str = hint_text.text().to_owned(); let font_id = font_selection.resolve(ui.style()); - let row_height = ui.fonts(|f| f.row_height(&font_id)); + let row_height = ui.fonts_mut(|f| f.row_height(&font_id)); const MIN_WIDTH: f32 = 24.0; // Never make a [`TextEdit`] more narrow than this. let available_width = (ui.available_width() - margin.sum().x).at_least(MIN_WIDTH); let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width); @@ -522,7 +522,7 @@ impl TextEdit<'_> { } else { LayoutJob::simple_singleline(text, font_id_clone.clone(), text_color) }; - ui.fonts(|f| f.layout_job(layout_job)) + ui.fonts_mut(|f| f.layout_job(layout_job)) }; let layouter = layouter.unwrap_or(&mut default_layouter); diff --git a/crates/egui_demo_app/src/apps/http_app.rs b/crates/egui_demo_app/src/apps/http_app.rs index 2aed2adb7..f16aa5969 100644 --- a/crates/egui_demo_app/src/apps/http_app.rs +++ b/crates/egui_demo_app/src/apps/http_app.rs @@ -238,7 +238,7 @@ impl ColoredText { pub fn ui(&self, ui: &mut egui::Ui) { let mut job = self.0.clone(); job.wrap.max_width = ui.available_width(); - let galley = ui.fonts(|f| f.layout_job(job)); + let galley = ui.fonts_mut(|f| f.layout_job(job)); ui.add(egui::Label::new(galley).selectable(true)); } } diff --git a/crates/egui_demo_app/src/frame_history.rs b/crates/egui_demo_app/src/frame_history.rs index 0b34f858a..52ff8342e 100644 --- a/crates/egui_demo_app/src/frame_history.rs +++ b/crates/egui_demo_app/src/frame_history.rs @@ -90,7 +90,7 @@ impl FrameHistory { )); let cpu_usage = to_screen.inverse().transform_pos(pointer_pos).y; let text = format!("{:.1} ms", 1e3 * cpu_usage); - shapes.push(ui.fonts(|f| { + shapes.push(ui.fonts_mut(|f| { Shape::text( f, pos2(rect.left(), y), diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index 02f098e67..d3345c2e5 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -165,14 +165,13 @@ pub fn criterion_benchmark(c: &mut Criterion) { let wrap_width = 512.0; let font_id = egui::FontId::default(); let text_color = egui::Color32::WHITE; - let fonts = egui::epaint::text::Fonts::new( + let mut fonts = egui::epaint::text::Fonts::new( pixels_per_point, max_texture_side, egui::epaint::AlphaFromCoverage::default(), egui::FontDefinitions::default(), ); { - let mut locked_fonts = fonts.lock(); c.bench_function("text_layout_uncached", |b| { b.iter(|| { use egui::epaint::text::{LayoutJob, layout}; @@ -183,7 +182,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { text_color, wrap_width, ); - layout(&mut locked_fonts.fonts, job.into()) + layout(&mut fonts.fonts, job.into()) }); }); } diff --git a/crates/egui_demo_lib/src/demo/code_editor.rs b/crates/egui_demo_lib/src/demo/code_editor.rs index 2d67f7d46..6a4720311 100644 --- a/crates/egui_demo_lib/src/demo/code_editor.rs +++ b/crates/egui_demo_lib/src/demo/code_editor.rs @@ -85,7 +85,7 @@ impl crate::View for CodeEditor { language, ); layout_job.wrap.max_width = wrap_width; - ui.fonts(|f| f.layout_job(layout_job)) + ui.fonts_mut(|f| f.layout_job(layout_job)) }; egui::ScrollArea::vertical().show(ui, |ui| { diff --git a/crates/egui_demo_lib/src/demo/code_example.rs b/crates/egui_demo_lib/src/demo/code_example.rs index 52cafad0c..23f561506 100644 --- a/crates/egui_demo_lib/src/demo/code_example.rs +++ b/crates/egui_demo_lib/src/demo/code_example.rs @@ -85,7 +85,7 @@ impl CodeExample { ui.horizontal(|ui| { let font_id = egui::TextStyle::Monospace.resolve(ui.style()); - let indentation = 2.0 * 4.0 * ui.fonts(|f| f.glyph_width(&font_id, ' ')); + let indentation = 2.0 * 4.0 * ui.fonts_mut(|f| f.glyph_width(&font_id, ' ')); ui.add_space(indentation); egui::Grid::new("code_samples") diff --git a/crates/egui_demo_lib/src/demo/font_book.rs b/crates/egui_demo_lib/src/demo/font_book.rs index 1ef9867f9..c2f606176 100644 --- a/crates/egui_demo_lib/src/demo/font_book.rs +++ b/crates/egui_demo_lib/src/demo/font_book.rs @@ -141,9 +141,8 @@ fn char_info_ui(ui: &mut egui::Ui, chr: char, glyph_info: &GlyphInfo, font_id: e } fn available_characters(ui: &egui::Ui, family: egui::FontFamily) -> BTreeMap { - ui.fonts(|f| { - f.lock() - .fonts + ui.fonts_mut(|f| { + f.fonts .font(&egui::FontId::new(10.0, family)) // size is arbitrary for getting the characters .characters() .iter() diff --git a/crates/egui_demo_lib/src/demo/misc_demo_window.rs b/crates/egui_demo_lib/src/demo/misc_demo_window.rs index b5a2402b7..bb62f1822 100644 --- a/crates/egui_demo_lib/src/demo/misc_demo_window.rs +++ b/crates/egui_demo_lib/src/demo/misc_demo_window.rs @@ -213,7 +213,7 @@ fn label_ui(ui: &mut egui::Ui) { ui.horizontal_wrapped(|ui| { // Trick so we don't have to add spaces in the text below: - let width = ui.fonts(|f|f.glyph_width(&TextStyle::Body.resolve(ui.style()), ' ')); + let width = ui.fonts_mut(|f|f.glyph_width(&TextStyle::Body.resolve(ui.style()), ' ')); ui.spacing_mut().item_spacing.x = width; ui.label(RichText::new("Text can have").color(Color32::from_rgb(110, 255, 110))); @@ -792,7 +792,7 @@ impl TextRotation { let start_pos = self.size / 2.0; - let s = ui.ctx().fonts(|f| { + let s = ui.ctx().fonts_mut(|f| { let mut t = egui::Shape::text( f, rect.min + start_pos, diff --git a/crates/egui_demo_lib/src/demo/scrolling.rs b/crates/egui_demo_lib/src/demo/scrolling.rs index ca3f6e90c..63fc81dbb 100644 --- a/crates/egui_demo_lib/src/demo/scrolling.rs +++ b/crates/egui_demo_lib/src/demo/scrolling.rs @@ -191,7 +191,7 @@ fn huge_content_painter(ui: &mut egui::Ui) { ui.add_space(4.0); let font_id = TextStyle::Body.resolve(ui.style()); - let row_height = ui.fonts(|f| f.row_height(&font_id)) + ui.spacing().item_spacing.y; + let row_height = ui.fonts_mut(|f| f.row_height(&font_id)) + ui.spacing().item_spacing.y; let num_rows = 10_000; ScrollArea::vertical() diff --git a/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs b/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs index 47d0beeaf..976bdd394 100644 --- a/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs +++ b/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs @@ -83,7 +83,7 @@ impl EasyMarkEditor { let mut layouter = |ui: &egui::Ui, easymark: &dyn TextBuffer, wrap_width: f32| { let mut layout_job = highlighter.highlight(ui.style(), easymark.as_str()); layout_job.wrap.max_width = wrap_width; - ui.fonts(|f| f.layout_job(layout_job)) + ui.fonts_mut(|f| f.layout_job(layout_job)) }; ui.add( diff --git a/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs b/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs index 41d99fb8a..f9d078b28 100644 --- a/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs +++ b/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs @@ -162,7 +162,7 @@ fn bullet_point(ui: &mut Ui, width: f32) -> Response { fn numbered_point(ui: &mut Ui, width: f32, number: &str) -> Response { let font_id = TextStyle::Body.resolve(ui.style()); - let row_height = ui.fonts(|f| f.row_height(&font_id)); + let row_height = ui.fonts_mut(|f| f.row_height(&font_id)); let (rect, response) = ui.allocate_exact_size(vec2(width, row_height), Sense::hover()); let text = format!("{number}."); let text_color = ui.visuals().strong_text_color(); diff --git a/crates/epaint/src/shapes/shape.rs b/crates/epaint/src/shapes/shape.rs index 10de38d15..c3868f335 100644 --- a/crates/epaint/src/shapes/shape.rs +++ b/crates/epaint/src/shapes/shape.rs @@ -299,7 +299,7 @@ impl Shape { #[expect(clippy::needless_pass_by_value)] pub fn text( - fonts: &Fonts, + fonts: &mut Fonts, pos: Pos2, anchor: Align2, text: impl ToString, diff --git a/crates/epaint/src/shapes/text_shape.rs b/crates/epaint/src/shapes/text_shape.rs index 9505dc49b..d8d059dd2 100644 --- a/crates/epaint/src/shapes/text_shape.rs +++ b/crates/epaint/src/shapes/text_shape.rs @@ -181,7 +181,7 @@ mod tests { #[test] fn text_bounding_box_under_rotation() { - let fonts = Fonts::new( + let mut fonts = Fonts::new( 1.0, 1024, AlphaFromCoverage::default(), @@ -190,7 +190,7 @@ mod tests { let font = FontId::monospace(12.0); let mut t = crate::Shape::text( - &fonts, + &mut fonts, Pos2::ZERO, emath::Align2::CENTER_CENTER, "testing123", diff --git a/crates/epaint/src/text/fonts.rs b/crates/epaint/src/text/fonts.rs index f9c1f4f8d..ac56a0f4e 100644 --- a/crates/epaint/src/text/fonts.rs +++ b/crates/epaint/src/text/fonts.rs @@ -2,7 +2,7 @@ use std::{collections::BTreeMap, sync::Arc}; use crate::{ AlphaFromCoverage, TextureAtlas, - mutex::{Mutex, MutexGuard}, + mutex::Mutex, text::{ Galley, LayoutJob, LayoutSection, font::{Font, FontImpl}, @@ -418,8 +418,10 @@ impl FontDefinitions { /// If you are using `egui`, use `egui::Context::set_fonts` and `egui::Context::fonts`. /// /// You need to call [`Self::begin_pass`] and [`Self::font_image_delta`] once every frame. -#[derive(Clone)] -pub struct Fonts(Arc>); +pub struct Fonts { + pub fonts: FontsImpl, + galley_cache: GalleyCache, +} impl Fonts { /// Create a new [`Fonts`] for text layout. @@ -433,7 +435,7 @@ impl Fonts { text_alpha_from_coverage: AlphaFromCoverage, definitions: FontDefinitions, ) -> Self { - let fonts_and_cache = FontsAndCache { + Self { fonts: FontsImpl::new( pixels_per_point, max_texture_side, @@ -441,8 +443,7 @@ impl Fonts { definitions, ), galley_cache: Default::default(), - }; - Self(Arc::new(Mutex::new(fonts_and_cache))) + } } /// Call at the start of each frame with the latest known @@ -453,27 +454,25 @@ impl Fonts { /// This function will react to changes in `pixels_per_point`, `max_texture_side`, and `text_alpha_from_coverage`, /// as well as notice when the font atlas is getting full, and handle that. pub fn begin_pass( - &self, + &mut self, pixels_per_point: f32, max_texture_side: usize, text_alpha_from_coverage: AlphaFromCoverage, ) { - let mut fonts_and_cache = self.0.lock(); - - let pixels_per_point_changed = fonts_and_cache.fonts.pixels_per_point != pixels_per_point; - let max_texture_side_changed = fonts_and_cache.fonts.max_texture_side != max_texture_side; + let pixels_per_point_changed = self.fonts.pixels_per_point != pixels_per_point; + let max_texture_side_changed = self.fonts.max_texture_side != max_texture_side; let text_alpha_from_coverage_changed = - fonts_and_cache.fonts.atlas.lock().text_alpha_from_coverage != text_alpha_from_coverage; - let font_atlas_almost_full = fonts_and_cache.fonts.atlas.lock().fill_ratio() > 0.8; + self.fonts.atlas.lock().text_alpha_from_coverage != text_alpha_from_coverage; + let font_atlas_almost_full = self.fonts.atlas.lock().fill_ratio() > 0.8; let needs_recreate = pixels_per_point_changed || max_texture_side_changed || text_alpha_from_coverage_changed || font_atlas_almost_full; if needs_recreate { - let definitions = fonts_and_cache.fonts.definitions.clone(); + let definitions = self.fonts.definitions.clone(); - *fonts_and_cache = FontsAndCache { + *self = Self { fonts: FontsImpl::new( pixels_per_point, max_texture_side, @@ -484,83 +483,70 @@ impl Fonts { }; } - fonts_and_cache.galley_cache.flush_cache(); + self.galley_cache.flush_cache(); } /// Call at the end of each frame (before painting) to get the change to the font texture since last call. pub fn font_image_delta(&self) -> Option { - self.lock().fonts.atlas.lock().take_delta() - } - - /// Access the underlying [`FontsAndCache`]. - #[doc(hidden)] - #[inline] - pub fn lock(&self) -> MutexGuard<'_, FontsAndCache> { - self.0.lock() + self.fonts.atlas.lock().take_delta() } #[inline] pub fn pixels_per_point(&self) -> f32 { - self.lock().fonts.pixels_per_point + self.fonts.pixels_per_point } #[inline] pub fn max_texture_side(&self) -> usize { - self.lock().fonts.max_texture_side + self.fonts.max_texture_side } /// The font atlas. /// Pass this to [`crate::Tessellator`]. pub fn texture_atlas(&self) -> Arc> { - self.lock().fonts.atlas.clone() + self.fonts.atlas.clone() } /// The full font atlas image. #[inline] pub fn image(&self) -> crate::ColorImage { - self.lock().fonts.atlas.lock().image().clone() + self.fonts.atlas.lock().image().clone() } /// Current size of the font image. /// Pass this to [`crate::Tessellator`]. pub fn font_image_size(&self) -> [usize; 2] { - self.lock().fonts.atlas.lock().size() + self.fonts.atlas.lock().size() } /// Width of this character in points. #[inline] - pub fn glyph_width(&self, font_id: &FontId, c: char) -> f32 { - self.lock().fonts.glyph_width(font_id, c) + pub fn glyph_width(&mut self, font_id: &FontId, c: char) -> f32 { + self.fonts.glyph_width(font_id, c) } /// Can we display this glyph? #[inline] - pub fn has_glyph(&self, font_id: &FontId, c: char) -> bool { - self.lock().fonts.has_glyph(font_id, c) + pub fn has_glyph(&mut self, font_id: &FontId, c: char) -> bool { + self.fonts.has_glyph(font_id, c) } /// Can we display all the glyphs in this text? - pub fn has_glyphs(&self, font_id: &FontId, s: &str) -> bool { - self.lock().fonts.has_glyphs(font_id, s) + pub fn has_glyphs(&mut self, font_id: &FontId, s: &str) -> bool { + self.fonts.has_glyphs(font_id, s) } /// Height of one row of text in points. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. #[inline] - pub fn row_height(&self, font_id: &FontId) -> f32 { - self.lock().fonts.row_height(font_id) + pub fn row_height(&mut self, font_id: &FontId) -> f32 { + self.fonts.row_height(font_id) } /// List of all known font families. pub fn families(&self) -> Vec { - self.lock() - .fonts - .definitions - .families - .keys() - .cloned() - .collect() + self.fonts.definitions.families.keys().cloned().collect() } /// Layout some text. @@ -571,12 +557,14 @@ impl Fonts { /// /// The implementation uses memoization so repeated calls are cheap. #[inline] - pub fn layout_job(&self, job: LayoutJob) -> Arc { - self.lock().layout_job(job) + pub fn layout_job(&mut self, job: LayoutJob) -> Arc { + let allow_split_paragraphs = true; // Optimization for editing text with many paragraphs. + self.galley_cache + .layout(&mut self.fonts, job, allow_split_paragraphs) } pub fn num_galleys_in_cache(&self) -> usize { - self.lock().galley_cache.num_galleys_in_cache() + self.galley_cache.num_galleys_in_cache() } /// How full is the font atlas? @@ -584,14 +572,14 @@ impl Fonts { /// This increases as new fonts and/or glyphs are used, /// but can also decrease in a call to [`Self::begin_pass`]. pub fn font_atlas_fill_ratio(&self) -> f32 { - self.lock().fonts.atlas.lock().fill_ratio() + self.fonts.atlas.lock().fill_ratio() } /// Will wrap text at the given width and line break at `\n`. /// /// The implementation uses memoization so repeated calls are cheap. pub fn layout( - &self, + &mut self, text: String, font_id: FontId, color: crate::Color32, @@ -605,7 +593,7 @@ impl Fonts { /// /// The implementation uses memoization so repeated calls are cheap. pub fn layout_no_wrap( - &self, + &mut self, text: String, font_id: FontId, color: crate::Color32, @@ -618,7 +606,7 @@ impl Fonts { /// /// The implementation uses memoization so repeated calls are cheap. pub fn layout_delayed_color( - &self, + &mut self, text: String, font_id: FontId, wrap_width: f32, @@ -629,19 +617,6 @@ impl Fonts { // ---------------------------------------------------------------------------- -pub struct FontsAndCache { - pub fonts: FontsImpl, - galley_cache: GalleyCache, -} - -impl FontsAndCache { - fn layout_job(&mut self, job: LayoutJob) -> Arc { - let allow_split_paragraphs = true; // Optimization for editing text with many paragraphs. - self.galley_cache - .layout(&mut self.fonts, job, allow_split_paragraphs) - } -} - // ---------------------------------------------------------------------------- /// The collection of fonts used by `epaint`. diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index 7635dcede..d82db524c 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -184,7 +184,7 @@ impl LayoutJob { /// The height of the tallest font used in the job. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - pub fn font_height(&self, fonts: &crate::Fonts) -> f32 { + pub fn font_height(&self, fonts: &mut crate::Fonts) -> f32 { let mut max_height = 0.0_f32; for section in &self.sections { max_height = max_height.max(fonts.row_height(§ion.format.font_id));