From d5869bfeaf0a76a70a0abb723f340aa06fff618a Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 21 Nov 2025 20:22:01 +0100 Subject: [PATCH 01/26] Remove some uses of top-level panels in our examples (#7729) We're phasing out top-level panels (panels that use `Context` directly, instead of being inside another `Ui`). As a first step, stop using them in our demo library and application. * Part of https://github.com/emilk/egui/issues/3524 --- crates/egui/src/containers/panel.rs | 14 ++- .../egui_demo_app/src/apps/custom3d_glow.rs | 39 ++++---- .../egui_demo_app/src/apps/custom3d_wgpu.rs | 39 ++++---- crates/egui_demo_app/src/apps/http_app.rs | 10 +-- crates/egui_demo_app/src/apps/image_viewer.rs | 12 +-- crates/egui_demo_app/src/lib.rs | 8 ++ crates/egui_demo_app/src/wrap_app.rs | 88 +++++++++---------- crates/egui_demo_lib/benches/benchmark.rs | 16 +++- .../src/demo/demo_app_windows.rs | 56 ++++++------ crates/egui_demo_lib/src/demo/panels.rs | 1 + .../src/easy_mark/easy_mark_editor.rs | 6 +- crates/egui_demo_lib/src/lib.rs | 8 +- examples/hello_android/src/lib.rs | 4 +- 13 files changed, 165 insertions(+), 136 deletions(-) diff --git a/crates/egui/src/containers/panel.rs b/crates/egui/src/containers/panel.rs index eb60f5f21..670e4758b 100644 --- a/crates/egui/src/containers/panel.rs +++ b/crates/egui/src/containers/panel.rs @@ -976,15 +976,25 @@ pub struct CentralPanel { } impl CentralPanel { + /// A central panel with no margin or background color + pub fn no_frame() -> Self { + Self { + frame: Some(Frame::NONE), + } + } + + /// A central panel with a background color and some inner margins + pub fn default_margins() -> Self { + Self { frame: None } + } + /// Change the background color, margins, etc. #[inline] pub fn frame(mut self, frame: Frame) -> Self { self.frame = Some(frame); self } -} -impl CentralPanel { /// Show the panel inside a [`Ui`]. pub fn show_inside( self, diff --git a/crates/egui_demo_app/src/apps/custom3d_glow.rs b/crates/egui_demo_app/src/apps/custom3d_glow.rs index 803f6156f..30380e31f 100644 --- a/crates/egui_demo_app/src/apps/custom3d_glow.rs +++ b/crates/egui_demo_app/src/apps/custom3d_glow.rs @@ -22,26 +22,27 @@ impl Custom3d { } } -impl eframe::App for Custom3d { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |ui| { - egui::ScrollArea::both() - .auto_shrink(false) - .show(ui, |ui| { - ui.horizontal(|ui| { - ui.spacing_mut().item_spacing.x = 0.0; - ui.label("The triangle is being painted using "); - ui.hyperlink_to("glow", "https://github.com/grovesNL/glow"); - ui.label(" (OpenGL)."); - }); - ui.label("It's not a very impressive demo, but it shows you can embed 3D inside of egui."); - - egui::Frame::canvas(ui.style()).show(ui, |ui| { - self.custom_painting(ui); - }); - ui.label("Drag to rotate!"); - ui.add(egui_demo_lib::egui_github_link_file!()); +impl crate::DemoApp for Custom3d { + fn demo_ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + // TODO(emilk): Use `ScrollArea::inner_margin` + egui::CentralPanel::default().show_inside(ui, |ui| { + egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| { + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.label("The triangle is being painted using "); + ui.hyperlink_to("glow", "https://github.com/grovesNL/glow"); + ui.label(" (OpenGL)."); }); + ui.label( + "It's not a very impressive demo, but it shows you can embed 3D inside of egui.", + ); + + egui::Frame::canvas(ui.style()).show(ui, |ui| { + self.custom_painting(ui); + }); + ui.label("Drag to rotate!"); + ui.add(egui_demo_lib::egui_github_link_file!()); + }); }); } diff --git a/crates/egui_demo_app/src/apps/custom3d_wgpu.rs b/crates/egui_demo_app/src/apps/custom3d_wgpu.rs index d3b10d480..0be1ed19b 100644 --- a/crates/egui_demo_app/src/apps/custom3d_wgpu.rs +++ b/crates/egui_demo_app/src/apps/custom3d_wgpu.rs @@ -98,26 +98,27 @@ impl Custom3d { } } -impl eframe::App for Custom3d { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |ui| { - egui::ScrollArea::both() - .auto_shrink(false) - .show(ui, |ui| { - ui.horizontal(|ui| { - ui.spacing_mut().item_spacing.x = 0.0; - ui.label("The triangle is being painted using "); - ui.hyperlink_to("WGPU", "https://wgpu.rs"); - ui.label(" (Portable Rust graphics API awesomeness)"); - }); - ui.label("It's not a very impressive demo, but it shows you can embed 3D inside of egui."); - - egui::Frame::canvas(ui.style()).show(ui, |ui| { - self.custom_painting(ui); - }); - ui.label("Drag to rotate!"); - ui.add(egui_demo_lib::egui_github_link_file!()); +impl crate::DemoApp for Custom3d { + fn demo_ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + // TODO(emilk): Use `ScrollArea::inner_margin` + egui::CentralPanel::default().show_inside(ui, |ui| { + egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| { + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.label("The triangle is being painted using "); + ui.hyperlink_to("WGPU", "https://wgpu.rs"); + ui.label(" (Portable Rust graphics API awesomeness)"); }); + ui.label( + "It's not a very impressive demo, but it shows you can embed 3D inside of egui.", + ); + + egui::Frame::canvas(ui.style()).show(ui, |ui| { + self.custom_painting(ui); + }); + ui.label("Drag to rotate!"); + ui.add(egui_demo_lib::egui_github_link_file!()); + }); }); } } diff --git a/crates/egui_demo_app/src/apps/http_app.rs b/crates/egui_demo_app/src/apps/http_app.rs index 2630fa862..8953f09e7 100644 --- a/crates/egui_demo_app/src/apps/http_app.rs +++ b/crates/egui_demo_app/src/apps/http_app.rs @@ -59,16 +59,16 @@ impl Default for HttpApp { } } -impl eframe::App for HttpApp { - fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { - egui::Panel::bottom("http_bottom").show(ctx, |ui| { +impl crate::DemoApp for HttpApp { + fn demo_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { + egui::Panel::bottom("http_bottom").show_inside(ui, |ui| { let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| { ui.add(egui_demo_lib::egui_github_link_file!()) }) }); - egui::CentralPanel::default().show(ctx, |ui| { + egui::CentralPanel::default().show_inside(ui, |ui| { let prev_url = self.url.clone(); let trigger_fetch = ui_url(ui, frame, &mut self.url); @@ -80,7 +80,7 @@ impl eframe::App for HttpApp { }); if trigger_fetch { - let ctx = ctx.clone(); + let ctx = ui.ctx().clone(); let (sender, promise) = Promise::new(); let request = ehttp::Request::get(&self.url); ehttp::fetch(request, move |response| { diff --git a/crates/egui_demo_app/src/apps/image_viewer.rs b/crates/egui_demo_app/src/apps/image_viewer.rs index 052996eef..11cc68b6b 100644 --- a/crates/egui_demo_app/src/apps/image_viewer.rs +++ b/crates/egui_demo_app/src/apps/image_viewer.rs @@ -48,15 +48,15 @@ impl Default for ImageViewer { } } -impl eframe::App for ImageViewer { - fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) { - egui::Panel::top("url bar").show(ctx, |ui| { +impl crate::DemoApp for ImageViewer { + fn demo_ui(&mut self, ui: &mut egui::Ui, _: &mut eframe::Frame) { + egui::Panel::top("url bar").show_inside(ui, |ui| { ui.horizontal_centered(|ui| { let label = ui.label("URI:"); ui.text_edit_singleline(&mut self.uri_edit_text) .labelled_by(label.id); if ui.small_button("✔").clicked() { - ctx.forget_image(&self.current_uri); + ui.ctx().forget_image(&self.current_uri); self.uri_edit_text = self.uri_edit_text.trim().to_owned(); self.current_uri = self.uri_edit_text.clone(); } @@ -71,7 +71,7 @@ impl eframe::App for ImageViewer { }); }); - egui::Panel::left("controls").show(ctx, |ui| { + egui::Panel::left("controls").show_inside(ui, |ui| { // uv ui.label("UV"); ui.add(Slider::new(&mut self.image_options.uv.min.x, 0.0..=1.0).text("min x")); @@ -197,7 +197,7 @@ impl eframe::App for ImageViewer { } }); - egui::CentralPanel::default().show(ctx, |ui| { + egui::CentralPanel::default().show_inside(ui, |ui| { egui::ScrollArea::both().show(ui, |ui| { let mut image = egui::Image::from_uri(&self.current_uri); image = image.uv(self.image_options.uv); diff --git a/crates/egui_demo_app/src/lib.rs b/crates/egui_demo_app/src/lib.rs index 05b3c4bd6..40264fd8e 100644 --- a/crates/egui_demo_app/src/lib.rs +++ b/crates/egui_demo_app/src/lib.rs @@ -15,6 +15,14 @@ pub(crate) fn seconds_since_midnight() -> f64 { time.num_seconds_from_midnight() as f64 + 1e-9 * (time.nanosecond() as f64) } +/// Trait that wraps different parts of the demo app. +pub trait DemoApp { + fn demo_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame); + + #[cfg(feature = "glow")] + fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {} +} + // ---------------------------------------------------------------------------- #[cfg(feature = "accessibility_inspector")] pub mod accessibility_inspector; diff --git a/crates/egui_demo_app/src/wrap_app.rs b/crates/egui_demo_app/src/wrap_app.rs index c118f280c..1d0a2390e 100644 --- a/crates/egui_demo_app/src/wrap_app.rs +++ b/crates/egui_demo_app/src/wrap_app.rs @@ -1,4 +1,4 @@ -use egui_demo_lib::is_mobile; +use egui_demo_lib::{DemoWindows, is_mobile}; #[cfg(feature = "glow")] use eframe::glow; @@ -6,29 +6,25 @@ use eframe::glow; #[cfg(target_arch = "wasm32")] use core::any::Any; +use crate::DemoApp; + #[derive(Default)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] struct EasyMarkApp { editor: egui_demo_lib::easy_mark::EasyMarkEditor, } -impl eframe::App for EasyMarkApp { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - self.editor.panels(ctx); +impl DemoApp for EasyMarkApp { + fn demo_ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + self.editor.panels(ui); } } // ---------------------------------------------------------------------------- -#[derive(Default)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -pub struct DemoApp { - demo_windows: egui_demo_lib::DemoWindows, -} - -impl eframe::App for DemoApp { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - self.demo_windows.ui(ctx); +impl DemoApp for DemoWindows { + fn demo_ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + self.ui(ui); } } @@ -41,15 +37,12 @@ pub struct FractalClockApp { pub mock_time: Option, } -impl eframe::App for FractalClockApp { - fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default() - .frame( - egui::Frame::dark_canvas(&ctx.style()) - .stroke(egui::Stroke::NONE) - .corner_radius(0), - ) - .show(ctx, |ui| { +impl DemoApp for FractalClockApp { + fn demo_ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + egui::Frame::dark_canvas(ui.style()) + .stroke(egui::Stroke::NONE) + .corner_radius(0) + .show(ui, |ui| { self.fractal_clock .ui(ui, self.mock_time.or(Some(crate::seconds_since_midnight()))); }); @@ -64,13 +57,13 @@ pub struct ColorTestApp { color_test: egui_demo_lib::ColorTest, } -impl eframe::App for ColorTestApp { - fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |ui| { +impl DemoApp for ColorTestApp { + fn demo_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { + egui::CentralPanel::default().show_inside(ui, |ui| { if frame.is_web() { ui.label( - "NOTE: Some old browsers stuck on WebGL1 without sRGB support will not pass the color test.", - ); + "NOTE: Some old browsers stuck on WebGL1 without sRGB support will not pass the color test.", + ); ui.separator(); } egui::ScrollArea::both().auto_shrink(false).show(ui, |ui| { @@ -155,7 +148,7 @@ enum Command { #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] pub struct State { - demo: DemoApp, + demo: DemoWindows, easy_mark_editor: EasyMarkApp, #[cfg(feature = "http")] http: crate::apps::HttpApp, @@ -209,34 +202,34 @@ impl WrapApp { pub fn apps_iter_mut( &mut self, - ) -> impl Iterator { + ) -> impl Iterator { let mut vec = vec![ ( "✨ Demos", Anchor::Demo, - &mut self.state.demo as &mut dyn eframe::App, + &mut self.state.demo as &mut dyn DemoApp, ), ( "🖹 EasyMark editor", Anchor::EasyMarkEditor, - &mut self.state.easy_mark_editor as &mut dyn eframe::App, + &mut self.state.easy_mark_editor as &mut dyn DemoApp, ), #[cfg(feature = "http")] ( "⬇ HTTP", Anchor::Http, - &mut self.state.http as &mut dyn eframe::App, + &mut self.state.http as &mut dyn DemoApp, ), ( "🕑 Fractal Clock", Anchor::Clock, - &mut self.state.clock as &mut dyn eframe::App, + &mut self.state.clock as &mut dyn DemoApp, ), #[cfg(feature = "image_viewer")] ( "🖼 Image Viewer", Anchor::ImageViewer, - &mut self.state.image_viewer as &mut dyn eframe::App, + &mut self.state.image_viewer as &mut dyn DemoApp, ), ]; @@ -245,14 +238,14 @@ impl WrapApp { vec.push(( "🔺 3D painting", Anchor::Custom3d, - custom3d as &mut dyn eframe::App, + custom3d as &mut dyn DemoApp, )); } vec.push(( "🎨 Rendering test", Anchor::Rendering, - &mut self.state.rendering_test as &mut dyn eframe::App, + &mut self.state.rendering_test as &mut dyn DemoApp, )); vec.into_iter() @@ -306,11 +299,13 @@ impl eframe::App for WrapApp { self.state.backend_panel.update(ctx, frame); - if !is_mobile(ctx) { - cmd = self.backend_panel(ctx, frame); - } + egui::CentralPanel::no_frame().show(ctx, |ui| { + if !is_mobile(ctx) { + cmd = self.backend_panel(ui, frame); + } - self.show_selected_app(ctx, frame); + self.show_selected_app(ui, frame); + }); self.state.backend_panel.end_of_frame(ctx); @@ -333,17 +328,16 @@ impl eframe::App for WrapApp { } impl WrapApp { - fn backend_panel(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) -> Command { + fn backend_panel(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) -> Command { // The backend-panel can be toggled on/off. // We show a little animation when the user switches it. - let is_open = - self.state.backend_panel.open || ctx.memory(|mem| mem.everything_is_visible()); + let is_open = self.state.backend_panel.open || ui.memory(|mem| mem.everything_is_visible()); let mut cmd = Command::Nothing; egui::Panel::left("backend_panel") .resizable(false) - .show_animated(ctx, is_open, |ui| { + .show_animated_inside(ui, is_open, |ui| { ui.add_space(4.0); ui.vertical_centered(|ui| { ui.heading("💻 Backend"); @@ -393,11 +387,11 @@ impl WrapApp { }); } - fn show_selected_app(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + fn show_selected_app(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { let selected_anchor = self.state.selected_anchor; for (_name, anchor, app) in self.apps_iter_mut() { - if anchor == selected_anchor || ctx.memory(|mem| mem.everything_is_visible()) { - app.update(ctx, frame); + if anchor == selected_anchor || ui.memory(|mem| mem.everything_is_visible()) { + app.demo_ui(ui, frame); } } } diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index 48e7d5207..90468770b 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -29,7 +29,9 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_with_tessellate__realistic", |b| { b.iter(|| { let full_output = ctx.run(RawInput::default(), |ctx| { - demo_windows.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + demo_windows.ui(ui); + }); }); ctx.tessellate(full_output.shapes, full_output.pixels_per_point) }); @@ -38,13 +40,17 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_no_tessellate", |b| { b.iter(|| { ctx.run(RawInput::default(), |ctx| { - demo_windows.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + demo_windows.ui(ui); + }); }) }); }); let full_output = ctx.run(RawInput::default(), |ctx| { - demo_windows.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + demo_windows.ui(ui); + }); }); c.bench_function("demo_only_tessellate", |b| { b.iter(|| ctx.tessellate(full_output.shapes.clone(), full_output.pixels_per_point)); @@ -58,7 +64,9 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_full_no_tessellate", |b| { b.iter(|| { ctx.run(RawInput::default(), |ctx| { - demo_windows.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + demo_windows.ui(ui); + }); }) }); }); diff --git a/crates/egui_demo_lib/src/demo/demo_app_windows.rs b/crates/egui_demo_lib/src/demo/demo_app_windows.rs index 179543680..d6f92b284 100644 --- a/crates/egui_demo_lib/src/demo/demo_app_windows.rs +++ b/crates/egui_demo_lib/src/demo/demo_app_windows.rs @@ -195,11 +195,11 @@ impl Default for DemoWindows { impl DemoWindows { /// Show the app ui (menu bar and windows). - pub fn ui(&mut self, ctx: &Context) { - if is_mobile(ctx) { - self.mobile_ui(ctx); + pub fn ui(&mut self, ui: &mut egui::Ui) { + if is_mobile(ui.ctx()) { + self.mobile_ui(ui); } else { - self.desktop_ui(ctx); + self.desktop_ui(ui); } } @@ -207,36 +207,36 @@ impl DemoWindows { self.open.contains(About::default().name()) } - fn mobile_ui(&mut self, ctx: &Context) { + fn mobile_ui(&mut self, ui: &mut egui::Ui) { if self.about_is_open() { let mut close = false; - egui::CentralPanel::default().show(ctx, |ui| { - egui::ScrollArea::vertical() - .auto_shrink(false) - .show(ui, |ui| { - self.groups.about.ui(ui); - ui.add_space(12.0); - ui.vertical_centered_justified(|ui| { - if ui - .button(egui::RichText::new("Continue to the demo!").size(20.0)) - .clicked() - { - close = true; - } - }); + + egui::ScrollArea::vertical() + .auto_shrink(false) + .show(ui, |ui| { + self.groups.about.ui(ui); + ui.add_space(12.0); + ui.vertical_centered_justified(|ui| { + if ui + .button(egui::RichText::new("Continue to the demo!").size(20.0)) + .clicked() + { + close = true; + } }); - }); + }); + if close { set_open(&mut self.open, About::default().name(), false); } } else { - self.mobile_top_bar(ctx); - self.groups.windows(ctx, &mut self.open); + self.mobile_top_bar(ui); + self.groups.windows(ui.ctx(), &mut self.open); } } - fn mobile_top_bar(&mut self, ctx: &Context) { - egui::Panel::top("menu_bar").show(ctx, |ui| { + fn mobile_top_bar(&mut self, ui: &mut egui::Ui) { + egui::Panel::top("menu_bar").show_inside(ui, |ui| { menu::MenuBar::new() .config(menu::MenuConfig::new().style(StyleModifier::default())) .ui(ui, |ui| { @@ -261,12 +261,12 @@ impl DemoWindows { }); } - fn desktop_ui(&mut self, ctx: &Context) { + fn desktop_ui(&mut self, ui: &mut egui::Ui) { egui::Panel::right("egui_demo_panel") .resizable(false) .default_size(160.0) .min_size(160.0) - .show(ctx, |ui| { + .show_inside(ui, |ui| { ui.add_space(4.0); ui.vertical_centered(|ui| { ui.heading("✒ egui demos"); @@ -289,13 +289,13 @@ impl DemoWindows { self.demo_list_ui(ui); }); - egui::Panel::top("menu_bar").show(ctx, |ui| { + egui::Panel::top("menu_bar").show_inside(ui, |ui| { menu::MenuBar::new().ui(ui, |ui| { file_menu_button(ui); }); }); - self.groups.windows(ctx, &mut self.open); + self.groups.windows(ui.ctx(), &mut self.open); } fn demo_list_ui(&mut self, ui: &mut egui::Ui) { diff --git a/crates/egui_demo_lib/src/demo/panels.rs b/crates/egui_demo_lib/src/demo/panels.rs index 55771c1a1..957166c4f 100644 --- a/crates/egui_demo_lib/src/demo/panels.rs +++ b/crates/egui_demo_lib/src/demo/panels.rs @@ -72,6 +72,7 @@ impl crate::View for Panels { }); }); + // TODO(emilk): This extra panel is superfluous - just use what's left of `ui` instead egui::CentralPanel::default().show_inside(ui, |ui| { ui.vertical_centered(|ui| { ui.heading("Central Panel"); 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 28e12630e..2969c6d3d 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 @@ -32,15 +32,15 @@ impl Default for EasyMarkEditor { } impl EasyMarkEditor { - pub fn panels(&mut self, ctx: &egui::Context) { - egui::Panel::bottom("easy_mark_bottom").show(ctx, |ui| { + pub fn panels(&mut self, ui: &mut egui::Ui) { + egui::Panel::bottom("easy_mark_bottom").show_inside(ui, |ui| { let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| { ui.add(crate::egui_github_link_file!()) }) }); - egui::CentralPanel::default().show(ctx, |ui| { + egui::CentralPanel::default().show_inside(ui, |ui| { self.ui(ui); }); } diff --git a/crates/egui_demo_lib/src/lib.rs b/crates/egui_demo_lib/src/lib.rs index 76be28859..7ba48b0d8 100644 --- a/crates/egui_demo_lib/src/lib.rs +++ b/crates/egui_demo_lib/src/lib.rs @@ -74,7 +74,9 @@ fn test_egui_e2e() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { let full_output = ctx.run(raw_input.clone(), |ctx| { - demo_windows.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + demo_windows.ui(ui); + }); }); let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point); assert!(!clipped_primitives.is_empty()); @@ -93,7 +95,9 @@ fn test_egui_zero_window_size() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { let full_output = ctx.run(raw_input.clone(), |ctx| { - demo_windows.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + demo_windows.ui(ui); + }); }); let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point); assert!( diff --git a/examples/hello_android/src/lib.rs b/examples/hello_android/src/lib.rs index 1de7684f5..87007c110 100644 --- a/examples/hello_android/src/lib.rs +++ b/examples/hello_android/src/lib.rs @@ -45,6 +45,8 @@ impl eframe::App for MyApp { ui.set_height(32.0); }); - self.demo.ui(ctx); + egui::CentralPanel::default().show(ctx, |ui| { + self.demo.ui(ui); + }); } } From 8d3539b6da372e966b6d57a474e3a9683c7818f8 Mon Sep 17 00:00:00 2001 From: Yichi Zhang <109252977+YichiZhang0613@users.noreply.github.com> Date: Mon, 24 Nov 2025 16:56:24 +0800 Subject: [PATCH 02/26] test_viewports: fix assertion (#7693) * [x] I have followed the instructions in the PR template These assertions allows col == COLS, while when col == COLS, array may be out of bounds. In `fn init`, `for i in 0..COLS {self.insert(...` confirms the assertions' predicate col <= COLS should be changed into col < COLS. --------- Co-authored-by: Emil Ernerfeldt --- tests/test_viewports/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_viewports/src/main.rs b/tests/test_viewports/src/main.rs index a862dbd32..49b212e4b 100644 --- a/tests/test_viewports/src/main.rs +++ b/tests/test_viewports/src/main.rs @@ -339,7 +339,7 @@ fn drag_and_drop_test(ui: &mut egui::Ui) { } fn insert(&mut self, container: Id, col: usize, value: impl Into) { - assert!(col <= COLS, "The coll should be less then: {COLS}"); + assert!(col < COLS, "The coll should be less than: {COLS}"); let value: String = value.into(); let id = Id::new(format!("%{}% {}", self.counter, &value)); @@ -355,7 +355,7 @@ fn drag_and_drop_test(ui: &mut egui::Ui) { } fn cols(&self, container: Id, col: usize) -> Vec<(Id, String)> { - assert!(col <= COLS, "The col should be less then: {COLS}"); + assert!(col < COLS, "The col should be less than: {COLS}"); let container_data = &self.containers_data[&container]; container_data[col] .iter() @@ -368,7 +368,7 @@ fn drag_and_drop_test(ui: &mut egui::Ui) { let Some(id) = self.is_dragged.take() else { return; }; - assert!(col <= COLS, "The col should be less then: {COLS}"); + assert!(col < COLS, "The col should be less than: {COLS}"); // Should be a better way to do this! #[expect(clippy::iter_over_hash_type)] From a624f37e2da32da4b166f71bc95b3d68836673fe Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 25 Nov 2025 08:52:16 +0100 Subject: [PATCH 03/26] Add `Context::run_ui` (#7736) * Part of https://github.com/emilk/egui/issues/3524 Adds `Context::run_ui` as a convenience wrapper around `Context::run`. This on the path to deprecate `run` and use a top-level `Ui` as the entry-point for all of egui. --- crates/egui/src/context.rs | 51 ++++++++++++++++++++++- crates/egui/src/lib.rs | 10 ++--- crates/egui_demo_lib/benches/benchmark.rs | 24 ++++------- crates/egui_demo_lib/src/lib.rs | 12 ++---- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 2ca7af4fc..d644b9610 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -758,6 +758,47 @@ impl Context { writer(&mut self.0.write()) } + /// Run the ui code for one frame. + /// + /// At most [`Options::max_passes`] calls will be issued to `run_ui`, + /// and only on the rare occasion that [`Context::request_discard`] is called. + /// Usually, it `run_ui` will only be called once. + /// + /// The [`Ui`] given to the callback will cover the entire [`Self::content_rect`], + /// with no margin or background color. Use [`crate::Frame`] to add that. + /// + /// You can organize your GUI using [`crate::Panel`]. + /// + /// Instead of calling `run_ui`, you can alternatively use [`Self::begin_pass`] and [`Context::end_pass`]. + /// + /// ``` + /// // One egui context that you keep reusing: + /// let mut ctx = egui::Context::default(); + /// + /// // Each frame: + /// let input = egui::RawInput::default(); + /// let full_output = ctx.run_ui(input, |ui| { + /// ui.label("Hello egui!"); + /// }); + /// // handle full_output + /// ``` + /// + /// ## See also + /// * [`Self::run`] + #[must_use] + pub fn run_ui(&self, new_input: RawInput, mut run_ui: impl FnMut(&mut Ui)) -> FullOutput { + self.run_ui_dyn(new_input, &mut run_ui) + } + + #[must_use] + fn run_ui_dyn(&self, new_input: RawInput, run_ui: &mut dyn FnMut(&mut Ui)) -> FullOutput { + self.run(new_input, |ctx| { + crate::CentralPanel::no_frame().show(ctx, |ui| { + run_ui(ui); + }); + }) + } + /// Run the ui code for one frame. /// /// At most [`Options::max_passes`] calls will be issued to `run_ui`, @@ -781,8 +822,16 @@ impl Context { /// }); /// // handle full_output /// ``` + /// + /// ## See also + /// * [`Self::run_ui`] #[must_use] - pub fn run(&self, mut new_input: RawInput, mut run_ui: impl FnMut(&Self)) -> FullOutput { + pub fn run(&self, new_input: RawInput, mut run_ui: impl FnMut(&Self)) -> FullOutput { + self.run_dyn(new_input, &mut run_ui) + } + + #[must_use] + fn run_dyn(&self, mut new_input: RawInput, run_ui: &mut dyn FnMut(&Self)) -> FullOutput { profiling::function_scope!(); let viewport_id = new_input.viewport_id; let max_passes = self.write(|ctx| ctx.memory.options.max_passes.get()); diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index bd4319f0b..d756caf75 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -691,8 +691,8 @@ pub enum WidgetType { pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) { let ctx = Context::default(); ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) - let _ = ctx.run(Default::default(), |ctx| { - run_ui(ctx); + let _ = ctx.run_ui(Default::default(), |ui| { + run_ui(ui.ctx()); }); } @@ -700,10 +700,8 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) { pub fn __run_test_ui(add_contents: impl Fn(&mut Ui)) { let ctx = Context::default(); ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) - let _ = ctx.run(Default::default(), |ctx| { - crate::CentralPanel::default().show(ctx, |ui| { - add_contents(ui); - }); + let _ = ctx.run_ui(Default::default(), |ui| { + add_contents(ui); }); } diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index 90468770b..1d791cd6d 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -28,10 +28,8 @@ pub fn criterion_benchmark(c: &mut Criterion) { // The most end-to-end benchmark. c.bench_function("demo_with_tessellate__realistic", |b| { b.iter(|| { - let full_output = ctx.run(RawInput::default(), |ctx| { - egui::CentralPanel::default().show(ctx, |ui| { - demo_windows.ui(ui); - }); + let full_output = ctx.run_ui(RawInput::default(), |ui| { + demo_windows.ui(ui); }); ctx.tessellate(full_output.shapes, full_output.pixels_per_point) }); @@ -39,18 +37,14 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_no_tessellate", |b| { b.iter(|| { - ctx.run(RawInput::default(), |ctx| { - egui::CentralPanel::default().show(ctx, |ui| { - demo_windows.ui(ui); - }); + ctx.run_ui(RawInput::default(), |ui| { + demo_windows.ui(ui); }) }); }); - let full_output = ctx.run(RawInput::default(), |ctx| { - egui::CentralPanel::default().show(ctx, |ui| { - demo_windows.ui(ui); - }); + let full_output = ctx.run_ui(RawInput::default(), |ui| { + demo_windows.ui(ui); }); c.bench_function("demo_only_tessellate", |b| { b.iter(|| ctx.tessellate(full_output.shapes.clone(), full_output.pixels_per_point)); @@ -63,10 +57,8 @@ pub fn criterion_benchmark(c: &mut Criterion) { let mut demo_windows = egui_demo_lib::DemoWindows::default(); c.bench_function("demo_full_no_tessellate", |b| { b.iter(|| { - ctx.run(RawInput::default(), |ctx| { - egui::CentralPanel::default().show(ctx, |ui| { - demo_windows.ui(ui); - }); + ctx.run_ui(RawInput::default(), |ui| { + demo_windows.ui(ui); }) }); }); diff --git a/crates/egui_demo_lib/src/lib.rs b/crates/egui_demo_lib/src/lib.rs index 7ba48b0d8..e0a257224 100644 --- a/crates/egui_demo_lib/src/lib.rs +++ b/crates/egui_demo_lib/src/lib.rs @@ -73,10 +73,8 @@ fn test_egui_e2e() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { - let full_output = ctx.run(raw_input.clone(), |ctx| { - egui::CentralPanel::default().show(ctx, |ui| { - demo_windows.ui(ui); - }); + let full_output = ctx.run_ui(raw_input.clone(), |ui| { + demo_windows.ui(ui); }); let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point); assert!(!clipped_primitives.is_empty()); @@ -94,10 +92,8 @@ fn test_egui_zero_window_size() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { - let full_output = ctx.run(raw_input.clone(), |ctx| { - egui::CentralPanel::default().show(ctx, |ui| { - demo_windows.ui(ui); - }); + let full_output = ctx.run_ui(raw_input.clone(), |ui| { + demo_windows.ui(ui); }); let clipped_primitives = ctx.tessellate(full_output.shapes, full_output.pixels_per_point); assert!( From 8b8595b45b4c283a2a654ada081342079170e3ab Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 25 Nov 2025 13:15:28 +0100 Subject: [PATCH 04/26] Treat `.` as a word-splitter in text navigation (#7741) When using option + arrow keys (Mac) or ctrl + arrow keys (Windows), you navigate a full word. Previously egui would ignore `.` in the text, so that `www.example.com` would be considered a full word. This is inconsistent with how the rest of macOS works. With this PR, cursor navigation in `www.example.com` will move the cursor between the dots. This makes editing code with egui a lot nicer. --- .../src/text_selection/text_cursor_state.rs | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/crates/egui/src/text_selection/text_cursor_state.rs b/crates/egui/src/text_selection/text_cursor_state.rs index 2a02e4577..9c9b0a263 100644 --- a/crates/egui/src/text_selection/text_cursor_state.rs +++ b/crates/egui/src/text_selection/text_cursor_state.rs @@ -208,25 +208,33 @@ fn ccursor_previous_line(text: &str, ccursor: CCursor) -> CCursor { } } -fn next_word_boundary_char_index(text: &str, index: usize) -> usize { - for word in text.split_word_bound_indices() { +fn next_word_boundary_char_index(text: &str, cursor_ci: usize) -> usize { + for (word_byte_index, word) in text.split_word_bound_indices() { + let word_ci = char_index_from_byte_index(text, word_byte_index); + + // We consider `.` a word boundary. + // At least that's how Mac works when navigating something like `www.example.com`. + for (dot_ci_offset, chr) in word.chars().enumerate() { + let dot_ci = word_ci + dot_ci_offset; + if chr == '.' && cursor_ci < dot_ci { + return dot_ci; + } + } + // Splitting considers contiguous whitespace as one word, such words must be skipped, // this handles cases for example ' abc' (a space and a word), the cursor is at the beginning // (before space) - this jumps at the end of 'abc' (this is consistent with text editors // or browsers) - let ci = char_index_from_byte_index(text, word.0); - if ci > index && !skip_word(word.1) { - return ci; + if cursor_ci < word_ci && !all_word_chars(word) { + return word_ci; } } char_index_from_byte_index(text, text.len()) } -fn skip_word(text: &str) -> bool { - // skip words that contain anything other than alphanumeric characters and underscore - // (i.e. whitespace, dashes, etc.) - !text.chars().any(|c| !is_word_char(c)) +fn all_word_chars(text: &str) -> bool { + text.chars().all(is_word_char) } fn next_line_boundary_char_index(it: impl Iterator, mut index: usize) -> usize { @@ -337,6 +345,12 @@ mod test { assert_eq!(next_word_boundary_char_index("", 0), 0); assert_eq!(next_word_boundary_char_index("", 1), 0); + // ASCII only + let text = "abc.def.ghi"; + assert_eq!(next_word_boundary_char_index(text, 1), 3); + assert_eq!(next_word_boundary_char_index(text, 3), 7); + assert_eq!(next_word_boundary_char_index(text, 7), 11); + // Unicode graphemes, some of which consist of multiple Unicode characters, // !!! Unicode character is not always what is tranditionally considered a character, // the values below are correct despite not seeming that way on the first look, From a19629ef4ac55e36fbaf82ccb871f0a4407b3a84 Mon Sep 17 00:00:00 2001 From: Lucas Meurer Date: Tue, 25 Nov 2025 14:51:18 +0100 Subject: [PATCH 05/26] Add `kittest.toml` config file (#7643) * part of https://github.com/rerun-io/rerun/issues/10991 --------- Co-authored-by: lucasmerlin <8009393+lucasmerlin@users.noreply.github.com> --- Cargo.lock | 32 +++- Cargo.toml | 1 + .../snapshots/rendering_test/dpi_1.67.png | 4 +- crates/egui_kittest/Cargo.toml | 6 +- crates/egui_kittest/README.md | 27 +++ crates/egui_kittest/src/config.rs | 154 ++++++++++++++++++ crates/egui_kittest/src/lib.rs | 1 + crates/egui_kittest/src/snapshot.rs | 55 +++++-- kittest.toml | 10 ++ 9 files changed, 273 insertions(+), 17 deletions(-) create mode 100644 crates/egui_kittest/src/config.rs create mode 100644 kittest.toml diff --git a/Cargo.lock b/Cargo.lock index 61bf459b5..404f3563c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1457,7 +1457,9 @@ dependencies = [ "kittest", "open", "pollster", + "serde", "tempfile", + "toml", "wgpu", ] @@ -4036,6 +4038,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serial_windows" version = "0.1.0" @@ -4491,11 +4502,26 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "toml" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -4504,6 +4530,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -5645,9 +5673,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index b33ca445c..b9a3432ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -131,6 +131,7 @@ syntect = { version = "5.3.0", default-features = false } tempfile = "3.23.0" thiserror = "2.0.17" tokio = "1.47.1" +toml = "0.8" type-map = "0.5.1" unicode_names2 = { version = "2.0.0", default-features = false } unicode-segmentation = "1.12.0" diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png index 1344edcfb..0fc009f8a 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9b7d7e290b97a8042af3af3cd9ceb274950cf607dd7e9cd6c71d5a113d3b57a5 -size 1206155 +oid sha256:3a3a9aa8383abfe4580be2cc9987f8123aeabf36bf8ec06029a9af64b9500ec9 +size 1206157 diff --git a/crates/egui_kittest/Cargo.toml b/crates/egui_kittest/Cargo.toml index 1de8ce7ac..33c895617 100644 --- a/crates/egui_kittest/Cargo.toml +++ b/crates/egui_kittest/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "egui_kittest" version.workspace = true -authors = ["Lucas Meurer ", "Emil Ernerfeldt "] +authors = ["Lucas Meurer ", "Emil Ernerfeldt "] description = "Testing library for egui based on kittest and AccessKit" edition.workspace = true rust-version.workspace = true @@ -34,9 +34,11 @@ x11 = ["eframe?/x11"] [dependencies] -kittest.workspace = true egui.workspace = true eframe = { workspace = true, optional = true } +kittest.workspace = true +serde.workspace = true +toml.workspace = true # wgpu dependencies egui-wgpu = { workspace = true, optional = true } diff --git a/crates/egui_kittest/README.md b/crates/egui_kittest/README.md index b774572f6..8c3c4bc30 100644 --- a/crates/egui_kittest/README.md +++ b/crates/egui_kittest/README.md @@ -38,6 +38,33 @@ fn main() { } ``` +## Configuration + +You can configure test settings via a `kittest.toml` file in your workspace root. +All possible settings and their defaults: +```toml +# path to the snapshot directory +output_path = "tests/snapshots" + +# default threshold for image comparison tests +threshold = 0.6 + +# default failed_pixel_count_threshold +failed_pixel_count_threshold = 0 + +[windows] +threshold = 0.6 +failed_pixel_count_threshold = 0 + +[macos] +threshold = 0.6 +failed_pixel_count_threshold = 0 + +[linux] +threshold = 0.6 +failed_pixel_count_threshold = 0 +``` + ## Snapshot testing There is a snapshot testing feature. To create snapshot tests, enable the `snapshot` and `wgpu` features. Once enabled, you can call `Harness::snapshot` to render the ui and save the image to the `tests/snapshots` directory. diff --git a/crates/egui_kittest/src/config.rs b/crates/egui_kittest/src/config.rs new file mode 100644 index 000000000..2565ceabf --- /dev/null +++ b/crates/egui_kittest/src/config.rs @@ -0,0 +1,154 @@ +use std::io; +use std::path::PathBuf; + +/// Configuration for `egui_kittest`. +/// +/// It's loaded once (per process) by searching for a `kittest.toml` file in the project root +/// (the directory containing `Cargo.lock`). +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(default, deny_unknown_fields)] +pub struct Config { + /// The output path for image snapshots. + /// + /// Default is "tests/snapshots" (relative to the working directory / crate root). + output_path: PathBuf, + + /// The per-pixel threshold. + /// + /// Default is 0.6. + threshold: f32, + + /// The number of pixels that can differ before the test is considered failed. + /// + /// Default is 0. + failed_pixel_count_threshold: usize, + + windows: OsConfig, + mac: OsConfig, + linux: OsConfig, +} + +impl Default for Config { + fn default() -> Self { + Self { + output_path: PathBuf::from("tests/snapshots"), + threshold: 0.6, + failed_pixel_count_threshold: 0, + windows: Default::default(), + mac: Default::default(), + linux: Default::default(), + } + } +} +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(default, deny_unknown_fields)] +pub struct OsConfig { + /// Override the per-pixel threshold for this OS. + threshold: Option, + + /// Override the failed pixel count threshold for this OS. + failed_pixel_count_threshold: Option, +} + +fn find_kittest_toml() -> io::Result { + let mut current_dir = std::env::current_dir()?; + + loop { + let current_kittest = current_dir.join("kittest.toml"); + // Check if Cargo.toml exists in this directory + if current_kittest.exists() { + return Ok(current_kittest); + } + + // Move up one directory + if !current_dir.pop() { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "kittest.toml not found", + )); + } + } +} + +fn load_config() -> Config { + if let Ok(config_path) = find_kittest_toml() { + match std::fs::read_to_string(&config_path) { + Ok(config_str) => match toml::from_str(&config_str) { + Ok(config) => config, + Err(e) => panic!("Failed to parse {}: {e}", &config_path.display()), + }, + Err(err) => { + panic!("Failed to read {}: {}", config_path.display(), err); + } + } + } else { + Config::default() + } +} + +/// Get the global configuration. +/// +/// See [`Config::global`] for details. +pub fn config() -> &'static Config { + Config::global() +} + +impl Config { + /// Get or load the global configuration. + /// + /// This is either + /// - Based on a `kittest.toml`, found by searching from the current working directory + /// (for tests that is the crate root) upwards. + /// - The default [Config], if no `kittest.toml` is found. + pub fn global() -> &'static Self { + static INSTANCE: std::sync::LazyLock = std::sync::LazyLock::new(load_config); + &INSTANCE + } + + /// The output path for image snapshots. + /// + /// Default is "tests/snapshots". + pub fn output_path(&self) -> PathBuf { + self.output_path.clone() + } +} + +#[cfg(feature = "snapshot")] +impl Config { + pub fn os_threshold(&self) -> crate::OsThreshold { + let fallback = self.threshold; + crate::OsThreshold { + windows: self.windows.threshold.unwrap_or(fallback), + macos: self.mac.threshold.unwrap_or(fallback), + linux: self.linux.threshold.unwrap_or(fallback), + fallback, + } + } + + pub fn os_failed_pixel_count_threshold(&self) -> crate::OsThreshold { + let fallback = self.failed_pixel_count_threshold; + crate::OsThreshold { + windows: self + .windows + .failed_pixel_count_threshold + .unwrap_or(fallback), + macos: self.mac.failed_pixel_count_threshold.unwrap_or(fallback), + linux: self.linux.failed_pixel_count_threshold.unwrap_or(fallback), + fallback, + } + } + + /// The threshold. + /// + /// Default is 1.0. + pub fn threshold(&self) -> f32 { + self.os_threshold().threshold() + } + + /// The number of pixels that can differ before the test is considered failed. + /// + /// Default is 0. + pub fn failed_pixel_count_threshold(&self) -> usize { + self.os_failed_pixel_count_threshold().threshold() + } +} diff --git a/crates/egui_kittest/src/lib.rs b/crates/egui_kittest/src/lib.rs index fc8b8efbc..6b196484a 100644 --- a/crates/egui_kittest/src/lib.rs +++ b/crates/egui_kittest/src/lib.rs @@ -11,6 +11,7 @@ mod snapshot; pub use crate::snapshot::*; mod app_kind; +mod config; mod node; mod renderer; #[cfg(feature = "wgpu")] diff --git a/crates/egui_kittest/src/snapshot.rs b/crates/egui_kittest/src/snapshot.rs index f6511c451..f26741323 100644 --- a/crates/egui_kittest/src/snapshot.rs +++ b/crates/egui_kittest/src/snapshot.rs @@ -1,28 +1,35 @@ -use crate::Harness; -use image::ImageError; use std::fmt::Display; use std::io::ErrorKind; use std::path::PathBuf; +use image::ImageError; + +use crate::{Harness, config::config}; + pub type SnapshotResult = Result<(), SnapshotError>; #[non_exhaustive] #[derive(Clone, Debug)] pub struct SnapshotOptions { /// The threshold for the image comparison. - /// The default is `0.6` (which is enough for most egui tests to pass across different - /// wgpu backends). + /// + /// Can be configured via kittest.toml. The fallback is `0.6` (which is enough for most egui + /// tests to pass across different wgpu backends). pub threshold: f32, /// The number of pixels that can differ before the snapshot is considered a failure. + /// /// Preferably, you should use `threshold` to control the sensitivity of the image comparison. /// As a last resort, you can use this to allow a certain number of pixels to differ. - /// If `None`, the default is `0` (meaning no pixels can differ). - /// If `Some`, the value can be set per OS + /// Can be configured via kittest.toml. The fallback is `0` (meaning no pixels can differ). pub failed_pixel_count_threshold: usize, /// The path where the snapshots will be saved. - /// The default is `tests/snapshots`. + /// + /// This is relative to the current working directory (usually the crate root when + /// running tests). + /// + /// Can be configured via kittest.toml. The fallback is `tests/snapshots`. pub output_path: PathBuf, } @@ -30,7 +37,9 @@ pub struct SnapshotOptions { /// /// This is useful if you want to set different thresholds for different operating systems. /// -/// The default values are 0 / 0.0 +/// [`OsThreshold::default`] gets the default from the config file (`kittest.toml`). +/// For `usize`, it's the `failed_pixel_count_threshold` value. +/// For `f32`, it's the `threshold` value. /// /// Example usage: /// ```no_run @@ -53,12 +62,36 @@ pub struct OsThreshold { pub fallback: T, } +impl Default for OsThreshold { + /// Returns the default `failed_pixel_count_threshold` as configured in `kittest.toml` + /// + /// The fallback is `0`. + fn default() -> Self { + config().os_failed_pixel_count_threshold() + } +} + +impl Default for OsThreshold { + /// Returns the default `threshold` as configured in `kittest.toml` + /// + /// The fallback is `0.6`. + fn default() -> Self { + config().os_threshold() + } +} + impl From for OsThreshold { fn from(value: usize) -> Self { Self::new(value) } } +impl From for OsThreshold { + fn from(value: f32) -> Self { + Self::new(value) + } +} + impl OsThreshold where T: Copy, @@ -123,9 +156,9 @@ impl From> for f32 { impl Default for SnapshotOptions { fn default() -> Self { Self { - threshold: 0.6, - output_path: PathBuf::from("tests/snapshots"), - failed_pixel_count_threshold: 0, // Default is 0, meaning no pixels can differ + threshold: config().threshold(), + output_path: config().output_path(), + failed_pixel_count_threshold: config().failed_pixel_count_threshold(), } } } diff --git a/kittest.toml b/kittest.toml new file mode 100644 index 000000000..4c9076b66 --- /dev/null +++ b/kittest.toml @@ -0,0 +1,10 @@ +output_path = "tests/snapshots" + +# Other OSes get a higher threshold so they can still run tests locally without failures due to small rendering +# differences. +# To update snapshots, update them via ./scripts/update_snapshots_from_ci.sh or via kitdiff +threshold = 2.0 + +[mac] +# Since our CI runs snapshot tests on macOS, this is our source of truth. +threshold = 0.6 From de907612b7dc09351d3e8c3b150fdfcf40f12cbd Mon Sep 17 00:00:00 2001 From: Lucas Meurer Date: Wed, 26 Nov 2025 14:56:19 +0100 Subject: [PATCH 06/26] Enforce consistent snapshot updates (#7744) * Closes https://github.com/emilk/egui/issues/7647 This collects SnapshotResults within the Harness and adds a check to enforce snapshot results are merged in case multiple Harnesses are constructed within a test. This should make snapshot updates via kitdiff/accept_snapshots.sh way more useful since it should now always update all snapshots instead of only the first one per test. --- .../src/demo/tests/tessellation_test.rs | 3 + .../egui_demo_lib/src/demo/widget_gallery.rs | 5 +- crates/egui_demo_lib/tests/image_blending.rs | 2 + crates/egui_demo_lib/tests/misc.rs | 4 + crates/egui_kittest/src/builder.rs | 5 ++ crates/egui_kittest/src/lib.rs | 11 +++ crates/egui_kittest/src/snapshot.rs | 87 +++++++++++++++---- 7 files changed, 100 insertions(+), 17 deletions(-) diff --git a/crates/egui_demo_lib/src/demo/tests/tessellation_test.rs b/crates/egui_demo_lib/src/demo/tests/tessellation_test.rs index cb08cf24e..78af853ef 100644 --- a/crates/egui_demo_lib/src/demo/tests/tessellation_test.rs +++ b/crates/egui_demo_lib/src/demo/tests/tessellation_test.rs @@ -357,11 +357,13 @@ fn rect_shape_ui(ui: &mut egui::Ui, shape: &mut RectShape) { #[cfg(test)] mod tests { use crate::View as _; + use egui_kittest::SnapshotResults; use super::*; #[test] fn snapshot_tessellation_test() { + let mut results = SnapshotResults::new(); for (name, shape) in TessellationTest::interesting_shapes() { let mut test = TessellationTest { shape, @@ -375,6 +377,7 @@ mod tests { harness.run(); harness.snapshot(format!("tessellation_test/{name}")); + results.extend_harness(&mut harness); } } } diff --git a/crates/egui_demo_lib/src/demo/widget_gallery.rs b/crates/egui_demo_lib/src/demo/widget_gallery.rs index 214646d49..b277b6d12 100644 --- a/crates/egui_demo_lib/src/demo/widget_gallery.rs +++ b/crates/egui_demo_lib/src/demo/widget_gallery.rs @@ -310,7 +310,7 @@ mod tests { use super::*; use crate::View as _; use egui::Vec2; - use egui_kittest::Harness; + use egui_kittest::{Harness, SnapshotResults}; #[test] pub fn should_match_screenshot() { @@ -320,6 +320,8 @@ mod tests { ..Default::default() }; + let mut results = SnapshotResults::new(); + for pixels_per_point in [1, 2] { for theme in [egui::Theme::Light, egui::Theme::Dark] { let mut harness = Harness::builder() @@ -339,6 +341,7 @@ mod tests { }; let image_name = format!("widget_gallery_{theme_name}_x{pixels_per_point}"); harness.snapshot(&image_name); + results.extend_harness(&mut harness); } } } diff --git a/crates/egui_demo_lib/tests/image_blending.rs b/crates/egui_demo_lib/tests/image_blending.rs index c8e5775a8..5cf129efc 100644 --- a/crates/egui_demo_lib/tests/image_blending.rs +++ b/crates/egui_demo_lib/tests/image_blending.rs @@ -3,6 +3,7 @@ use egui_kittest::Harness; #[test] fn test_image_blending() { + let mut results = egui_kittest::SnapshotResults::new(); for pixels_per_point in [1.0, 2.0] { let mut harness = Harness::builder() .with_pixels_per_point(pixels_per_point) @@ -21,5 +22,6 @@ fn test_image_blending() { harness.run(); harness.fit_contents(); harness.snapshot(format!("image_blending/image_x{pixels_per_point}")); + results.extend_harness(&mut harness); } } diff --git a/crates/egui_demo_lib/tests/misc.rs b/crates/egui_demo_lib/tests/misc.rs index af8858bca..8abc69d19 100644 --- a/crates/egui_demo_lib/tests/misc.rs +++ b/crates/egui_demo_lib/tests/misc.rs @@ -3,6 +3,7 @@ use egui_kittest::{Harness, kittest::Queryable as _}; #[test] fn test_kerning() { + let mut results = egui_kittest::SnapshotResults::new(); for pixels_per_point in [1.0, 2.0] { for theme in [egui::Theme::Dark, egui::Theme::Light] { let mut harness = Harness::builder() @@ -24,12 +25,14 @@ fn test_kerning() { egui::Theme::Light => "light", } )); + results.extend_harness(&mut harness); } } } #[test] fn test_italics() { + let mut results = egui_kittest::SnapshotResults::new(); for pixels_per_point in [1.0, 2.0_f32.sqrt(), 2.0] { for theme in [egui::Theme::Dark, egui::Theme::Light] { let mut harness = Harness::builder() @@ -49,6 +52,7 @@ fn test_italics() { egui::Theme::Light => "light", } )); + results.extend_harness(&mut harness); } } } diff --git a/crates/egui_kittest/src/builder.rs b/crates/egui_kittest/src/builder.rs index 09b91d26d..87b199c6d 100644 --- a/crates/egui_kittest/src/builder.rs +++ b/crates/egui_kittest/src/builder.rs @@ -166,6 +166,7 @@ impl HarnessBuilder { /// /// assert_eq!(*harness.state(), true); /// ``` + #[track_caller] pub fn build_state<'a>( self, app: impl FnMut(&egui::Context, &mut State) + 'a, @@ -195,6 +196,7 @@ impl HarnessBuilder { /// /// assert_eq!(*harness.state(), true); /// ``` + #[track_caller] pub fn build_ui_state<'a>( self, app: impl FnMut(&mut egui::Ui, &mut State) + 'a, @@ -206,6 +208,7 @@ impl HarnessBuilder { /// Create a new [Harness] from the given eframe creation closure. /// The app can be accessed via the [`Harness::state`] / [`Harness::state_mut`] methods. #[cfg(feature = "eframe")] + #[track_caller] pub fn build_eframe<'a>( self, build: impl FnOnce(&mut eframe::CreationContext<'a>) -> State, @@ -247,6 +250,7 @@ impl HarnessBuilder { /// }); /// ``` #[must_use] + #[track_caller] pub fn build<'a>(self, app: impl FnMut(&egui::Context) + 'a) -> Harness<'a> { Harness::from_builder(self, AppKind::Context(Box::new(app)), (), None) } @@ -267,6 +271,7 @@ impl HarnessBuilder { /// }); /// ``` #[must_use] + #[track_caller] pub fn build_ui<'a>(self, app: impl FnMut(&mut egui::Ui) + 'a) -> Harness<'a> { Harness::from_builder(self, AppKind::Ui(Box::new(app)), (), None) } diff --git a/crates/egui_kittest/src/lib.rs b/crates/egui_kittest/src/lib.rs index 6b196484a..71312c352 100644 --- a/crates/egui_kittest/src/lib.rs +++ b/crates/egui_kittest/src/lib.rs @@ -84,6 +84,8 @@ pub struct Harness<'a, State = ()> { #[cfg(feature = "snapshot")] default_snapshot_options: SnapshotOptions, + #[cfg(feature = "snapshot")] + snapshot_results: SnapshotResults, } impl Debug for Harness<'_, State> { @@ -93,6 +95,7 @@ impl Debug for Harness<'_, State> { } impl<'a, State> Harness<'a, State> { + #[track_caller] pub(crate) fn from_builder( builder: HarnessBuilder, mut app: AppKind<'a, State>, @@ -162,6 +165,9 @@ impl<'a, State> Harness<'a, State> { #[cfg(feature = "snapshot")] default_snapshot_options, + + #[cfg(feature = "snapshot")] + snapshot_results: SnapshotResults::default(), }; // Run the harness until it is stable, ensuring that all Areas are shown and animations are done harness.run_ok(); @@ -197,6 +203,7 @@ impl<'a, State> Harness<'a, State> { /// /// assert_eq!(*harness.state(), true); /// ``` + #[track_caller] pub fn new_state(app: impl FnMut(&egui::Context, &mut State) + 'a, state: State) -> Self { Self::builder().build_state(app, state) } @@ -222,12 +229,14 @@ impl<'a, State> Harness<'a, State> { /// /// assert_eq!(*harness.state(), true); /// ``` + #[track_caller] pub fn new_ui_state(app: impl FnMut(&mut egui::Ui, &mut State) + 'a, state: State) -> Self { Self::builder().build_ui_state(app, state) } /// Create a new [Harness] from the given eframe creation closure. #[cfg(feature = "eframe")] + #[track_caller] pub fn new_eframe(builder: impl FnOnce(&mut eframe::CreationContext<'a>) -> State) -> Self where State: eframe::App, @@ -725,6 +734,7 @@ impl<'a> Harness<'a> { /// }); /// }); /// ``` + #[track_caller] pub fn new(app: impl FnMut(&egui::Context) + 'a) -> Self { Self::builder().build(app) } @@ -745,6 +755,7 @@ impl<'a> Harness<'a> { /// ui.label("Hello, world!"); /// }); /// ``` + #[track_caller] pub fn new_ui(app: impl FnMut(&mut egui::Ui) + 'a) -> Self { Self::builder().build_ui(app) } diff --git a/crates/egui_kittest/src/snapshot.rs b/crates/egui_kittest/src/snapshot.rs index f26741323..ede19e5bf 100644 --- a/crates/egui_kittest/src/snapshot.rs +++ b/crates/egui_kittest/src/snapshot.rs @@ -663,16 +663,16 @@ impl Harness<'_, State> { /// If the new image didn't match the snapshot, a diff image will be saved under `{output_path}/{name}.diff.png`. /// /// # Panics - /// Panics if the image does not match the snapshot, if there was an error reading or writing the + /// The result is added to the [`Harness`]'s internal [`SnapshotResults`]. + /// + /// The harness will panic when dropped if there were any snapshot errors. + /// + /// Errors happen if the image does not match the snapshot, if there was an error reading or writing the /// snapshot, if the rendering fails or if no default renderer is available. #[track_caller] pub fn snapshot_options(&mut self, name: impl Into, options: &SnapshotOptions) { - match self.try_snapshot_options(name, options) { - Ok(_) => {} - Err(err) => { - panic!("{err}"); - } - } + let result = self.try_snapshot_options(name, options); + self.snapshot_results.add(result); } /// Render an image using the setup [`crate::TestRenderer`] and compare it to the snapshot. @@ -688,12 +688,8 @@ impl Harness<'_, State> { /// snapshot, if the rendering fails or if no default renderer is available. #[track_caller] pub fn snapshot(&mut self, name: impl Into) { - match self.try_snapshot(name) { - Ok(_) => {} - Err(err) => { - panic!("{err}"); - } - } + let result = self.try_snapshot(name); + self.snapshot_results.add(result); } /// Render a snapshot, save it to a temp file and open it in the default image viewer. @@ -739,6 +735,12 @@ impl Harness<'_, State> { } } } + + /// This removes the snapshot results from the harness. Useful if you e.g. want to merge it + /// with the results from another harness (using [`SnapshotResults::add`]). + pub fn take_snapshot_results(&mut self) -> SnapshotResults { + std::mem::take(&mut self.snapshot_results) + } } /// Utility to collect snapshot errors and display them at the end of the test. @@ -765,9 +767,22 @@ impl Harness<'_, State> { /// Panics if there are any errors when dropped (this way it is impossible to forget to call `unwrap`). /// If you don't want to panic, you can use [`SnapshotResults::into_result`] or [`SnapshotResults::into_inner`]. /// If you want to panic early, you can use [`SnapshotResults::unwrap`]. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct SnapshotResults { errors: Vec, + handled: bool, + location: std::panic::Location<'static>, +} + +impl Default for SnapshotResults { + #[track_caller] + fn default() -> Self { + Self { + errors: Vec::new(), + handled: true, // If no snapshots were added, we should consider this handled. + location: *std::panic::Location::caller(), + } + } } impl Display for SnapshotResults { @@ -785,17 +800,30 @@ impl Display for SnapshotResults { } impl SnapshotResults { + #[track_caller] pub fn new() -> Self { Default::default() } /// Check if the result is an error and add it to the list of errors. pub fn add(&mut self, result: SnapshotResult) { + self.handled = false; if let Err(err) = result { self.errors.push(err); } } + /// Add all errors from another `SnapshotResults`. + pub fn extend(&mut self, other: Self) { + self.handled = false; + self.errors.extend(other.into_inner()); + } + + /// Add all errors from a [`Harness`]. + pub fn extend_harness(&mut self, harness: &mut Harness<'_, T>) { + self.extend(harness.take_snapshot_results()); + } + /// Check if there are any errors. pub fn has_errors(&self) -> bool { !self.errors.is_empty() @@ -807,13 +835,14 @@ impl SnapshotResults { if self.has_errors() { Err(self) } else { Ok(()) } } + /// Consume this and return the list of errors. pub fn into_inner(mut self) -> Vec { + self.handled = true; std::mem::take(&mut self.errors) } /// Panics if there are any errors, displaying each. #[expect(clippy::unused_self)] - #[track_caller] pub fn unwrap(self) { // Panic is handled in drop } @@ -826,7 +855,6 @@ impl From for Vec { } impl Drop for SnapshotResults { - #[track_caller] fn drop(&mut self) { // Don't panic if we are already panicking (the test probably failed for another reason) if std::thread::panicking() { @@ -836,5 +864,32 @@ impl Drop for SnapshotResults { if self.has_errors() { panic!("{}", self); } + + thread_local! { + static UNHANDLED_SNAPSHOT_RESULTS_COUNTER: std::cell::RefCell = const { std::cell::RefCell::new(0) }; + } + + if !self.handled { + let count = UNHANDLED_SNAPSHOT_RESULTS_COUNTER.with(|counter| { + let mut count = counter.borrow_mut(); + *count += 1; + *count + }); + + #[expect(clippy::manual_assert)] + if count >= 2 { + panic!( + r#" +Multiple SnapshotResults were dropped without being handled. + +In order to allow consistent snapshot updates, all snapshot results within a test should be merged in a single SnapshotResults instance. +Usually this is handled internally in a harness. If you have multiple harnesses, you can merge the results using `Harness::take_snapshot_results` and `SnapshotResults::extend`. + +The SnapshotResult was constructed at {} + "#, + self.location + ); + } + } } } From 3fcdab4ebd8a5985c969780880eb003367820a16 Mon Sep 17 00:00:00 2001 From: Ryan Date: Fri, 5 Dec 2025 02:44:06 -0700 Subject: [PATCH 07/26] Typo fix in drag-and-drop documentation (#7750) * [x] I have followed the instructions in the PR template Adding periods to the end of sentences and fixes a grammar mistake on documentation for the drag-and-drop code to become consistent with the rest of the documentation. The documentation for `Ui::dnd_drop_zone` could've used the word "its" instead of "the" to replace "it", but I think "the" more clearly refers to the `Frame` since "its" has been used to refer to the drop-zone already. --- crates/egui/src/context.rs | 4 ++-- crates/egui/src/response.rs | 2 +- crates/egui/src/ui.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index d644b9610..1369ef616 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -4057,7 +4057,7 @@ impl Context { /// Is this specific widget being dragged? /// /// A widget that sense both clicks and drags is only marked as "dragged" - /// when the mouse has moved a bit + /// when the mouse has moved a bit. /// /// See also: [`crate::Response::dragged`]. pub fn is_being_dragged(&self, id: Id) -> bool { @@ -4071,7 +4071,7 @@ impl Context { self.interaction_snapshot(|i| i.drag_started) } - /// This widget was being dragged, but was released this pass + /// This widget was being dragged, but was released this pass. pub fn drag_stopped_id(&self) -> Option { self.interaction_snapshot(|i| i.drag_stopped) } diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index e89cb5252..6b5daead0 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -472,7 +472,7 @@ impl Response { /// /// Only returns something if [`Self::contains_pointer`] is true, /// the user is drag-dropping something of this type, - /// and they released it this frame + /// and they released it this frame. #[doc(alias = "drag and drop")] pub fn dnd_release_payload(&self) -> Option> { // NOTE: we use `response.contains_pointer` here instead of `hovered`, because diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 3c7fca2f3..07bd512d1 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -3004,7 +3004,7 @@ impl Ui { /// /// Returns the dropped item, if it was released this frame. /// - /// The given frame is used for its margins, but it color is ignored. + /// The given frame is used for its margins, but the color is ignored. #[doc(alias = "drag and drop")] pub fn dnd_drop_zone( &mut self, From 2dbfe3a0838ac23b69a5e051cf0b30448d042486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20G=C3=B6rtler?= Date: Fri, 5 Dec 2025 10:46:34 +0100 Subject: [PATCH 08/26] Enable `or_fun_call` lint to avoid unnecessary allocations (#7754) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What From the [lint description](https://rust-lang.github.io/rust-clippy/master/index.html?search=or_fu#or_fun_call): > The function will always be called. This is only bad if it allocates or does some non-trivial amount of work. But also: > If the function has side-effects, not calling it will change the semantic of the program, but you shouldn’t rely on that. > > The lint also cannot figure out whether the function you call is actually expensive to call or not. Still worth it to keep our happy paths clean, imo. --- Cargo.toml | 1 + crates/eframe/src/native/glow_integration.rs | 8 ++++---- crates/egui/src/atomics/atom_kind.rs | 2 +- crates/egui/src/atomics/atom_layout.rs | 4 ++-- crates/egui/src/containers/panel.rs | 2 +- crates/egui/src/containers/popup.rs | 3 ++- crates/egui/src/context.rs | 2 +- crates/egui/src/response.rs | 2 +- crates/egui/src/ui.rs | 8 ++++---- crates/egui/src/widgets/image.rs | 2 +- crates/egui/src/widgets/label.rs | 4 +++- crates/egui/src/widgets/progress_bar.rs | 2 +- crates/egui/src/widgets/text_edit/builder.rs | 4 ++-- crates/egui_demo_app/src/accessibility_inspector.rs | 4 ++-- crates/egui_demo_app/src/wrap_app.rs | 7 +++++-- crates/egui_extras/src/table.rs | 4 ++-- crates/egui_kittest/src/snapshot.rs | 7 ++++--- crates/egui_kittest/src/wgpu.rs | 2 +- crates/epaint/src/shapes/bezier_shape.rs | 9 ++++++--- 19 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b9a3432ba..0a78d4354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -278,6 +278,7 @@ non_zero_suggestions = "warn" nonstandard_macro_braces = "warn" option_as_ref_cloned = "warn" option_option = "warn" +or_fun_call = "warn" path_buf_push_overwrite = "warn" pathbuf_init_then_push = "warn" precedence_bits = "warn" diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index c5358527a..e448c6c19 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -719,11 +719,11 @@ impl GlowWinitRunning<'_> { // vsync - don't count as frame-time: frame_timer.pause(); profiling::scope!("swap_buffers"); - let context = current_gl_context - .as_ref() - .ok_or(egui_glow::PainterError::from( + let context = current_gl_context.as_ref().ok_or_else(|| { + egui_glow::PainterError::from( "failed to get current context to swap buffers".to_owned(), - ))?; + ) + })?; gl_surface.swap_buffers(context)?; frame_timer.resume(); diff --git a/crates/egui/src/atomics/atom_kind.rs b/crates/egui/src/atomics/atom_kind.rs index 3c54c496b..10ca3353b 100644 --- a/crates/egui/src/atomics/atom_kind.rs +++ b/crates/egui/src/atomics/atom_kind.rs @@ -82,7 +82,7 @@ impl<'a> AtomKind<'a> { ) -> (Vec2, SizedAtomKind<'a>) { match self { AtomKind::Text(text) => { - let wrap_mode = wrap_mode.unwrap_or(ui.wrap_mode()); + let wrap_mode = wrap_mode.unwrap_or_else(|| ui.wrap_mode()); let galley = text.into_galley(ui, Some(wrap_mode), available_size.x, fallback_font); (galley.intrinsic_size(), SizedAtomKind::Text(galley)) } diff --git a/crates/egui/src/atomics/atom_layout.rs b/crates/egui/src/atomics/atom_layout.rs index 1df890250..8132a7dc9 100644 --- a/crates/egui/src/atomics/atom_layout.rs +++ b/crates/egui/src/atomics/atom_layout.rs @@ -168,7 +168,7 @@ impl<'a> AtomLayout<'a> { let fallback_font = fallback_font.unwrap_or_default(); - let wrap_mode = wrap_mode.unwrap_or(ui.wrap_mode()); + let wrap_mode = wrap_mode.unwrap_or_else(|| ui.wrap_mode()); // If the TextWrapMode is not Extend, ensure there is some item marked as `shrink`. // If none is found, mark the first text item as `shrink`. @@ -188,7 +188,7 @@ impl<'a> AtomLayout<'a> { let fallback_text_color = fallback_text_color.unwrap_or_else(|| ui.style().visuals.text_color()); - let gap = gap.unwrap_or(ui.spacing().icon_spacing); + let gap = gap.unwrap_or_else(|| ui.spacing().icon_spacing); // The size available for the content let available_inner_size = ui.available_size() - frame.total_margin().sum(); diff --git a/crates/egui/src/containers/panel.rs b/crates/egui/src/containers/panel.rs index 670e4758b..3c52f63a3 100644 --- a/crates/egui/src/containers/panel.rs +++ b/crates/egui/src/containers/panel.rs @@ -941,7 +941,7 @@ impl Panel { PanelState::load(ctx, panel.id) .map(get_rect_state_size) .or(panel.default_size) - .unwrap_or(get_spacing_size()) + .unwrap_or_else(get_spacing_size) } } diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index a9c00661d..0fb2a9f2a 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -465,7 +465,7 @@ impl<'a> Popup<'a> { pub fn get_best_align(&self) -> RectAlign { let expected_popup_size = self .get_expected_size() - .unwrap_or(vec2(self.width.unwrap_or(0.0), 0.0)); + .unwrap_or_else(|| vec2(self.width.unwrap_or(0.0), 0.0)); let Some(anchor_rect) = self.anchor.rect(self.id, &self.ctx) else { return self.rect_align; @@ -473,6 +473,7 @@ impl<'a> Popup<'a> { RectAlign::find_best_align( #[expect(clippy::iter_on_empty_collections)] + #[expect(clippy::or_fun_call)] once(self.rect_align).chain( self.alternative_aligns // Need the empty slice so the iters have the same type so we can unwrap_or diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 1369ef616..9d9d4b53f 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -611,7 +611,7 @@ impl ContextImpl { } let parent_id = find_accesskit_parent(&state.parent_map, builders, id) - .unwrap_or(crate::accesskit_root_id()); + .unwrap_or_else(crate::accesskit_root_id); let parent_builder = builders.get_mut(&parent_id).unwrap(); parent_builder.push_child(id.accesskit_id()); diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 6b5daead0..8190f0006 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -433,7 +433,7 @@ impl Response { pub fn drag_motion(&self) -> Vec2 { if self.dragged() { self.ctx - .input(|i| i.pointer.motion().unwrap_or(i.pointer.delta())) + .input(|i| i.pointer.motion().unwrap_or_else(|| i.pointer.delta())) } else { Vec2::ZERO } diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 07bd512d1..d230ed736 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -136,7 +136,7 @@ impl Ui { accessibility_parent, } = ui_builder; - let layer_id = layer_id.unwrap_or(LayerId::background()); + let layer_id = layer_id.unwrap_or_else(LayerId::background); debug_assert!( id_salt.is_none(), @@ -148,7 +148,7 @@ impl Ui { let layout = layout.unwrap_or_default(); let disabled = disabled || invisible; let style = style.unwrap_or_else(|| ctx.style()); - let sense = sense.unwrap_or(Sense::hover()); + let sense = sense.unwrap_or_else(Sense::hover); let placer = Placer::new(max_rect, layout); let ui_stack = UiStack { @@ -277,7 +277,7 @@ impl Ui { let id_salt = id_salt.unwrap_or_else(|| Id::from("child")); let max_rect = max_rect.unwrap_or_else(|| self.available_rect_before_wrap()); - let mut layout = layout.unwrap_or(*self.layout()); + let mut layout = layout.unwrap_or_else(|| *self.layout()); let enabled = self.enabled && !disabled && !invisible; if let Some(layer_id) = layer_id { painter.set_layer_id(layer_id); @@ -287,7 +287,7 @@ impl Ui { } let sizing_pass = self.sizing_pass || sizing_pass; let style = style.unwrap_or_else(|| self.style.clone()); - let sense = sense.unwrap_or(Sense::hover()); + let sense = sense.unwrap_or_else(Sense::hover); if sizing_pass { // During the sizing pass we want widgets to use up as little space as possible, diff --git a/crates/egui/src/widgets/image.rs b/crates/egui/src/widgets/image.rs index 167920adc..8a7c49209 100644 --- a/crates/egui/src/widgets/image.rs +++ b/crates/egui/src/widgets/image.rs @@ -681,7 +681,7 @@ pub fn paint_texture_load_result( } Ok(TexturePoll::Pending { .. }) => { let show_loading_spinner = - show_loading_spinner.unwrap_or(ui.visuals().image_loading_spinners); + show_loading_spinner.unwrap_or_else(|| ui.visuals().image_loading_spinners); if show_loading_spinner { Spinner::new().paint_at(ui, rect); } diff --git a/crates/egui/src/widgets/label.rs b/crates/egui/src/widgets/label.rs index 86259ab2a..284cfd12c 100644 --- a/crates/egui/src/widgets/label.rs +++ b/crates/egui/src/widgets/label.rs @@ -248,7 +248,9 @@ impl Label { layout_job.halign = Align::LEFT; layout_job.justify = false; } else { - layout_job.halign = self.halign.unwrap_or(ui.layout().horizontal_placement()); + layout_job.halign = self + .halign + .unwrap_or_else(|| ui.layout().horizontal_placement()); layout_job.justify = ui.layout().horizontal_justify(); } diff --git a/crates/egui/src/widgets/progress_bar.rs b/crates/egui/src/widgets/progress_bar.rs index bba6be8ef..fb7a79ffe 100644 --- a/crates/egui/src/widgets/progress_bar.rs +++ b/crates/egui/src/widgets/progress_bar.rs @@ -118,7 +118,7 @@ impl Widget for ProgressBar { let desired_width = desired_width.unwrap_or_else(|| ui.available_size_before_wrap().x.at_least(96.0)); - let height = desired_height.unwrap_or(ui.spacing().interact_size.y); + let height = desired_height.unwrap_or_else(|| ui.spacing().interact_size.y); let (outer_rect, response) = ui.allocate_exact_size(vec2(desired_width, height), Sense::hover()); diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 6f2da1baa..e364b4a00 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -496,7 +496,7 @@ impl TextEdit<'_> { } = self; let text_color = text_color - .or(ui.visuals().override_text_color) + .or_else(|| ui.visuals().override_text_color) // .unwrap_or_else(|| ui.style().interact(&response).text_color()); // too bright .unwrap_or_else(|| ui.visuals().widgets.inactive.text_color()); @@ -691,7 +691,7 @@ impl TextEdit<'_> { if ui.is_rect_visible(rect) { if text.as_str().is_empty() && !hint_text.is_empty() { let hint_text_color = ui.visuals().weak_text_color(); - let hint_text_font_id = hint_text_font.unwrap_or(font_id.into()); + let hint_text_font_id = hint_text_font.unwrap_or_else(|| font_id.into()); let galley = if multiline { hint_text.into_galley( ui, diff --git a/crates/egui_demo_app/src/accessibility_inspector.rs b/crates/egui_demo_app/src/accessibility_inspector.rs index 9ba3a8082..ab8b9270d 100644 --- a/crates/egui_demo_app/src/accessibility_inspector.rs +++ b/crates/egui_demo_app/src/accessibility_inspector.rs @@ -199,8 +199,8 @@ impl AccessibilityInspectorPlugin { } let label = node .label() - .or(node.value()) - .unwrap_or(node.id().0.to_string()); + .or_else(|| node.value()) + .unwrap_or_else(|| node.id().0.to_string()); let label = format!("({:?}) {}", node.role(), label); // Safety: This is safe since the `accesskit::NodeId` was created from an `egui::Id`. diff --git a/crates/egui_demo_app/src/wrap_app.rs b/crates/egui_demo_app/src/wrap_app.rs index 1d0a2390e..87394b503 100644 --- a/crates/egui_demo_app/src/wrap_app.rs +++ b/crates/egui_demo_app/src/wrap_app.rs @@ -43,8 +43,11 @@ impl DemoApp for FractalClockApp { .stroke(egui::Stroke::NONE) .corner_radius(0) .show(ui, |ui| { - self.fractal_clock - .ui(ui, self.mock_time.or(Some(crate::seconds_since_midnight()))); + self.fractal_clock.ui( + ui, + self.mock_time + .or_else(|| Some(crate::seconds_since_midnight())), + ); }); } } diff --git a/crates/egui_extras/src/table.rs b/crates/egui_extras/src/table.rs index a984226ae..f2a42b850 100644 --- a/crates/egui_extras/src/table.rs +++ b/crates/egui_extras/src/table.rs @@ -479,7 +479,7 @@ impl<'a> TableBuilder<'a> { } } - let striped = striped.unwrap_or(ui.visuals().striped); + let striped = striped.unwrap_or_else(|| ui.visuals().striped); let state_id = ui.id().with(id_salt); @@ -548,7 +548,7 @@ impl<'a> TableBuilder<'a> { sense, } = self; - let striped = striped.unwrap_or(ui.visuals().striped); + let striped = striped.unwrap_or_else(|| ui.visuals().striped); let state_id = ui.id().with(id_salt); diff --git a/crates/egui_kittest/src/snapshot.rs b/crates/egui_kittest/src/snapshot.rs index ede19e5bf..4d139fcbb 100644 --- a/crates/egui_kittest/src/snapshot.rs +++ b/crates/egui_kittest/src/snapshot.rs @@ -264,7 +264,8 @@ impl Display for SnapshotError { diff, diff_path, } => { - let diff_path = std::path::absolute(diff_path).unwrap_or(diff_path.clone()); + let diff_path = + std::path::absolute(diff_path).unwrap_or_else(|_| diff_path.clone()); write!( f, "'{name}' Image did not match snapshot. Diff: {diff}, {}. {HOW_TO_UPDATE_SCREENSHOTS}", @@ -272,7 +273,7 @@ impl Display for SnapshotError { ) } Self::OpenSnapshot { path, err } => { - let path = std::path::absolute(path).unwrap_or(path.clone()); + let path = std::path::absolute(path).unwrap_or_else(|_| path.clone()); match err { ImageError::IoError(io) => match io.kind() { ErrorKind::NotFound => { @@ -310,7 +311,7 @@ impl Display for SnapshotError { ) } Self::WriteSnapshot { path, err } => { - let path = std::path::absolute(path).unwrap_or(path.clone()); + let path = std::path::absolute(path).unwrap_or_else(|_| path.clone()); write!(f, "Error writing snapshot: {err}\nAt: {}", path.display()) } Self::RenderError { err } => { diff --git a/crates/egui_kittest/src/wgpu.rs b/crates/egui_kittest/src/wgpu.rs index ae773095d..3f97e0036 100644 --- a/crates/egui_kittest/src/wgpu.rs +++ b/crates/egui_kittest/src/wgpu.rs @@ -51,7 +51,7 @@ pub fn default_wgpu_setup() -> egui_wgpu::WgpuSetup { adapters .first() .map(|a| (*a).clone()) - .ok_or("No adapter found".to_owned()) + .ok_or_else(|| "No adapter found".to_owned()) })); egui_wgpu::WgpuSetup::CreateNew(setup) diff --git a/crates/epaint/src/shapes/bezier_shape.rs b/crates/epaint/src/shapes/bezier_shape.rs index 20f7a4e18..002612dbb 100644 --- a/crates/epaint/src/shapes/bezier_shape.rs +++ b/crates/epaint/src/shapes/bezier_shape.rs @@ -298,7 +298,8 @@ impl CubicBezierShape { /// the number of points is determined by the tolerance. /// the points may not be evenly distributed in the range [0.0,1.0] (t value) pub fn flatten(&self, tolerance: Option) -> Vec { - let tolerance = tolerance.unwrap_or((self.points[0].x - self.points[3].x).abs() * 0.001); + let tolerance = + tolerance.unwrap_or_else(|| (self.points[0].x - self.points[3].x).abs() * 0.001); let mut result = vec![self.points[0]]; self.for_each_flattened_with_t(tolerance, &mut |p, _t| { result.push(p); @@ -313,7 +314,8 @@ impl CubicBezierShape { /// The result will be a vec of vec of Pos2. it will store two closed aren in different vec. /// The epsilon is used to compare a float value. pub fn flatten_closed(&self, tolerance: Option, epsilon: Option) -> Vec> { - let tolerance = tolerance.unwrap_or((self.points[0].x - self.points[3].x).abs() * 0.001); + let tolerance = + tolerance.unwrap_or_else(|| (self.points[0].x - self.points[3].x).abs() * 0.001); let epsilon = epsilon.unwrap_or(1.0e-5); let mut result = Vec::new(); let mut first_half = Vec::new(); @@ -519,7 +521,8 @@ impl QuadraticBezierShape { /// the number of points is determined by the tolerance. /// the points may not be evenly distributed in the range [0.0,1.0] (t value) pub fn flatten(&self, tolerance: Option) -> Vec { - let tolerance = tolerance.unwrap_or((self.points[0].x - self.points[2].x).abs() * 0.001); + let tolerance = + tolerance.unwrap_or_else(|| (self.points[0].x - self.points[2].x).abs() * 0.001); let mut result = vec![self.points[0]]; self.for_each_flattened_with_t(tolerance, &mut |p, _t| { result.push(p); From 2174b309bdc5a0b767f84839ecec4b993e8ce48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= Date: Sat, 6 Dec 2025 11:33:56 +0100 Subject: [PATCH 09/26] Bump `ehttp` to 0.6.0 (#7757) --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 404f3563c..ae8de2169 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1475,9 +1475,9 @@ dependencies = [ [[package]] name = "ehttp" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a81c221a1e4dad06cb9c9deb19aea1193a5eea084e8cd42d869068132bf876" +checksum = "04499d3c719edecfad5c9b46031726c8540905d73be6d7e4f9788c4a298da908" dependencies = [ "document-features", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 0a78d4354..c647614c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ criterion = { version = "0.7.0", default-features = false } dify = { version = "0.7.4", default-features = false } directories = "6.0.0" document-features = "0.2.11" -ehttp = { version = "0.5.0", default-features = false } +ehttp = { version = "0.6.0", default-features = false } enum-map = "2.7.3" env_logger = { version = "0.11.8", default-features = false } glow = "0.16.0" From 609dd2d28edfadd544f53cec39b38564eb4fcb75 Mon Sep 17 00:00:00 2001 From: valadaptive <79560998+valadaptive@users.noreply.github.com> Date: Sat, 6 Dec 2025 10:11:33 -0500 Subject: [PATCH 10/26] Replace ab_glyph with Skrifa + vello_cpu; enable font hinting (#7694) * Closes N/A * [x] I have followed the instructions in the PR template I'll probably come back to this and clean it up a bit. This PR reimplements ab_glyph's functionality on top of Skrifa, a somewhat lower-level font API that's being used in Chrome now. Skrifa doesn't perform rasterization itself, so I'm using [vello_cpu](https://github.com/linebender/vello) from the Linebender project for rasterization. It's still in its early days, but I believe it's already quite fast. It also supports color and gradient fills, so color emoji support will be easier. Skrifa also supports font hinting, which should make text look a bit nicer / less blurry. Here's the current ab_glyph rendering: image Here's Skrifa *without* hinting--it looks almost identical, but there are some subpixel differences, probably due to rasterizer behavior: image Here's Skrifa *with* hinting: image Hinting does make the horizontal strokes look a bit bolder, which makes me wonder once again about increasing the font weight from "light" to "regular". --------- Co-authored-by: Emil Ernerfeldt --- Cargo.lock | 128 +++++- Cargo.toml | 4 +- crates/egui/src/context.rs | 33 +- crates/egui/src/style.rs | 59 ++- .../egui_demo_app/tests/snapshots/clock.png | 4 +- .../tests/snapshots/custom3d.png | 4 +- .../tests/snapshots/easymarkeditor.png | 4 +- .../tests/snapshots/imageviewer.png | 4 +- crates/egui_demo_lib/benches/benchmark.rs | 10 +- .../tests/snapshots/demos/Bézier Curve.png | 4 +- .../tests/snapshots/demos/Clipboard Test.png | 4 +- .../tests/snapshots/demos/Code Editor.png | 4 +- .../tests/snapshots/demos/Code Example.png | 4 +- .../tests/snapshots/demos/Cursor Test.png | 4 +- .../tests/snapshots/demos/Dancing Strings.png | 4 +- .../tests/snapshots/demos/Drag and Drop.png | 4 +- .../tests/snapshots/demos/Extra Viewport.png | 4 +- .../tests/snapshots/demos/Font Book.png | 4 +- .../tests/snapshots/demos/Frame.png | 4 +- .../tests/snapshots/demos/Grid Test.png | 4 +- .../tests/snapshots/demos/Highlighting.png | 4 +- .../tests/snapshots/demos/ID Test.png | 4 +- .../snapshots/demos/Input Event History.png | 4 +- .../tests/snapshots/demos/Input Test.png | 4 +- .../snapshots/demos/Interactive Container.png | 4 +- .../tests/snapshots/demos/Layout Test.png | 4 +- .../snapshots/demos/Manual Layout Test.png | 4 +- .../tests/snapshots/demos/Misc Demos.png | 4 +- .../tests/snapshots/demos/Modals.png | 4 +- .../tests/snapshots/demos/Multi Touch.png | 4 +- .../tests/snapshots/demos/Painting.png | 4 +- .../tests/snapshots/demos/Panels.png | 4 +- .../tests/snapshots/demos/Popups.png | 4 +- .../tests/snapshots/demos/SVG Test.png | 4 +- .../tests/snapshots/demos/Scene.png | 4 +- .../tests/snapshots/demos/Screenshot.png | 4 +- .../tests/snapshots/demos/Scrolling.png | 4 +- .../tests/snapshots/demos/Sliders.png | 4 +- .../tests/snapshots/demos/Strip.png | 4 +- .../tests/snapshots/demos/Table.png | 4 +- .../snapshots/demos/Tessellation Test.png | 4 +- .../tests/snapshots/demos/Text Layout.png | 4 +- .../tests/snapshots/demos/TextEdit.png | 4 +- .../tests/snapshots/demos/Tooltips.png | 4 +- .../tests/snapshots/demos/Undo Redo.png | 4 +- .../tests/snapshots/demos/Window Options.png | 4 +- .../snapshots/demos/Window Resize Test.png | 4 +- .../snapshots/image_kerning/image_dark_x1.png | 4 +- .../snapshots/image_kerning/image_dark_x2.png | 4 +- .../image_kerning/image_light_x1.png | 4 +- .../image_kerning/image_light_x2.png | 4 +- .../snapshots/italics/image_dark_x1.00.png | 4 +- .../snapshots/italics/image_dark_x1.41.png | 4 +- .../snapshots/italics/image_dark_x2.00.png | 4 +- .../snapshots/italics/image_light_x1.00.png | 4 +- .../snapshots/italics/image_light_x1.41.png | 4 +- .../snapshots/italics/image_light_x2.00.png | 4 +- .../tests/snapshots/modals_1.png | 4 +- .../tests/snapshots/modals_2.png | 4 +- .../tests/snapshots/modals_3.png | 4 +- ...rop_should_prevent_focusing_lower_area.png | 4 +- .../snapshots/rendering_test/dpi_1.00.png | 4 +- .../snapshots/rendering_test/dpi_1.25.png | 4 +- .../snapshots/rendering_test/dpi_1.50.png | 4 +- .../snapshots/rendering_test/dpi_1.67.png | 4 +- .../snapshots/rendering_test/dpi_1.75.png | 4 +- .../snapshots/rendering_test/dpi_2.00.png | 4 +- .../tessellation_test/Additive rectangle.png | 4 +- .../tessellation_test/Blurred stroke.png | 4 +- .../snapshots/tessellation_test/Blurred.png | 4 +- .../tessellation_test/Minimal rounding.png | 4 +- .../snapshots/tessellation_test/Normal.png | 4 +- .../Thick stroke, minimal rounding.png | 4 +- .../tessellation_test/Thin filled.png | 4 +- .../tessellation_test/Thin stroked.png | 4 +- .../tests/snapshots/text_selection.png | 4 +- .../snapshots/widget_gallery_dark_x1.png | 4 +- .../snapshots/widget_gallery_dark_x2.png | 4 +- .../snapshots/widget_gallery_light_x1.png | 4 +- .../snapshots/widget_gallery_light_x2.png | 4 +- .../tests/snapshots/combobox_closed.png | 4 +- .../tests/snapshots/combobox_opened.png | 4 +- .../tests/snapshots/image_snapshots.png | 4 +- .../tests/snapshots/menu/closed_hovered.png | 4 +- .../tests/snapshots/menu/opened.png | 4 +- .../tests/snapshots/menu/submenu.png | 4 +- .../tests/snapshots/menu/subsubmenu.png | 4 +- .../override_text_color_interactive.png | 4 +- .../tests/snapshots/readme_example.png | 4 +- .../snapshots/should_wait_for_images.png | 4 +- .../tests/snapshots/test_masking.png | 4 +- .../tests/snapshots/test_scroll_initial.png | 4 +- .../tests/snapshots/test_scroll_scrolled.png | 4 +- .../tests/snapshots/test_shrink.png | 4 +- .../tests/snapshots/test_tooltip_hidden.png | 4 +- .../tests/snapshots/test_tooltip_shown.png | 4 +- crates/epaint/Cargo.toml | 6 +- crates/epaint/benches/benchmark.rs | 6 +- crates/epaint/src/lib.rs | 2 +- crates/epaint/src/shapes/text_shape.rs | 6 +- crates/epaint/src/text/font.rs | 409 ++++++++++++------ crates/epaint/src/text/fonts.rs | 134 +++--- crates/epaint/src/text/mod.rs | 28 ++ crates/epaint/src/text/text_layout.rs | 99 ++--- crates/epaint/src/text/text_layout_types.rs | 8 +- crates/epaint/src/texture_atlas.rs | 14 +- deny.toml | 1 + .../tests/snapshots/button_shortcut.png | 4 +- tests/egui_tests/tests/snapshots/grow_all.png | 4 +- .../hovering_should_preserve_text_format.png | 4 +- .../tests/snapshots/layout/atoms_image.png | 4 +- .../tests/snapshots/layout/atoms_minimal.png | 4 +- .../snapshots/layout/atoms_multi_grow.png | 4 +- .../tests/snapshots/layout/button.png | 4 +- .../tests/snapshots/layout/button_image.png | 4 +- .../layout/button_image_shortcut.png | 4 +- .../tests/snapshots/layout/checkbox.png | 4 +- .../snapshots/layout/checkbox_checked.png | 4 +- .../tests/snapshots/layout/drag_value.png | 4 +- .../tests/snapshots/layout/radio.png | 4 +- .../tests/snapshots/layout/radio_checked.png | 4 +- .../snapshots/layout/selectable_value.png | 4 +- .../layout/selectable_value_selected.png | 4 +- .../tests/snapshots/layout/slider.png | 4 +- .../tests/snapshots/layout/text_edit.png | 4 +- .../tests/snapshots/layout/text_edit_clip.png | 4 +- .../snapshots/layout/text_edit_no_clip.png | 4 +- .../layout/text_edit_placeholder_clip.png | 4 +- .../egui_tests/tests/snapshots/max_width.png | 4 +- .../tests/snapshots/max_width_and_grow.png | 4 +- .../tests/snapshots/shrink_first_text.png | 4 +- .../tests/snapshots/shrink_last_text.png | 4 +- .../tests/snapshots/sides/default_long.png | 4 +- .../sides/default_long_fit_contents.png | 4 +- .../tests/snapshots/sides/default_short.png | 4 +- .../sides/default_short_fit_contents.png | 4 +- .../snapshots/sides/shrink_left_long.png | 4 +- .../sides/shrink_left_long_fit_contents.png | 4 +- .../snapshots/sides/shrink_left_short.png | 4 +- .../sides/shrink_left_short_fit_contents.png | 4 +- .../snapshots/sides/shrink_right_long.png | 4 +- .../sides/shrink_right_long_fit_contents.png | 4 +- .../snapshots/sides/shrink_right_short.png | 4 +- .../sides/shrink_right_short_fit_contents.png | 4 +- .../tests/snapshots/sides/wrap_left_long.png | 4 +- .../sides/wrap_left_long_fit_contents.png | 4 +- .../tests/snapshots/sides/wrap_left_short.png | 4 +- .../sides/wrap_left_short_fit_contents.png | 4 +- .../tests/snapshots/sides/wrap_right_long.png | 4 +- .../sides/wrap_right_long_fit_contents.png | 4 +- .../snapshots/sides/wrap_right_short.png | 4 +- .../sides/wrap_right_short_fit_contents.png | 4 +- .../tests/snapshots/size_max_size.png | 4 +- .../tests/snapshots/text_edit_rtl_0.png | 4 +- .../tests/snapshots/text_edit_rtl_1.png | 4 +- .../tests/snapshots/text_edit_rtl_2.png | 4 +- .../tests/snapshots/visuals/button.png | 4 +- .../tests/snapshots/visuals/button_image.png | 4 +- .../visuals/button_image_shortcut.png | 4 +- .../button_image_shortcut_selected.png | 4 +- .../tests/snapshots/visuals/checkbox.png | 4 +- .../snapshots/visuals/checkbox_checked.png | 4 +- .../tests/snapshots/visuals/drag_value.png | 4 +- .../tests/snapshots/visuals/radio.png | 4 +- .../tests/snapshots/visuals/radio_checked.png | 4 +- .../snapshots/visuals/selectable_value.png | 4 +- .../visuals/selectable_value_selected.png | 4 +- .../tests/snapshots/visuals/slider.png | 4 +- .../tests/snapshots/visuals/text_edit.png | 4 +- .../snapshots/visuals/text_edit_clip.png | 4 +- .../snapshots/visuals/text_edit_no_clip.png | 4 +- .../visuals/text_edit_placeholder_clip.png | 4 +- 172 files changed, 928 insertions(+), 643 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae8de2169..f75e31381 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -863,6 +863,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18ef4657441fb193b65f34dc39b3781f0dfec23d3bd94d0eeb4e88cde421edb" +dependencies = [ + "bytemuck", +] + [[package]] name = "color-hex" version = "0.2.0" @@ -1595,7 +1604,6 @@ dependencies = [ name = "epaint" version = "0.33.2" dependencies = [ - "ab_glyph", "ahash", "bytemuck", "criterion", @@ -1609,8 +1617,11 @@ dependencies = [ "parking_lot", "profiling", "rayon", + "self_cell", "serde", "similar-asserts", + "skrifa", + "vello_cpu", ] [[package]] @@ -1639,6 +1650,15 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + [[package]] name = "event-listener" version = "5.3.1" @@ -1706,6 +1726,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "fearless_simd" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb2907d1f08b2b316b9223ced5b0e89d87028ba8deae9764741dba8ff7f3903" +dependencies = [ + "bytemuck", +] + [[package]] name = "file_dialog" version = "0.1.0" @@ -1749,6 +1778,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "font-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" +dependencies = [ + "bytemuck", +] + [[package]] name = "fontconfig-parser" version = "0.5.7" @@ -2528,6 +2566,17 @@ dependencies = [ "smallvec", ] +[[package]] +name = "kurbo" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32" +dependencies = [ + "arrayvec", + "euclid", + "smallvec", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2577,6 +2626,12 @@ dependencies = [ "redox_syscall 0.5.7", ] +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -3253,6 +3308,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "peniko" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3c76095c9a636173600478e0373218c7b955335048c2bcd12dc6a79657649d8" +dependencies = [ + "bytemuck", + "color", + "kurbo 0.12.0", + "linebender_resource_handle", + "smallvec", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -3383,9 +3451,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.14" +version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -3692,6 +3760,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "read-fonts" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +dependencies = [ + "bytemuck", + "font-types", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -3985,6 +4063,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "self_cell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" + [[package]] name = "serde" version = "1.0.228" @@ -4112,6 +4196,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +[[package]] +name = "skrifa" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +dependencies = [ + "bytemuck", + "read-fonts", +] + [[package]] name = "slab" version = "0.4.9" @@ -4233,7 +4327,7 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" dependencies = [ - "kurbo", + "kurbo 0.11.1", "siphasher", ] @@ -4735,7 +4829,7 @@ dependencies = [ "flate2", "fontdb", "imagesize", - "kurbo", + "kurbo 0.11.1", "log", "pico-args", "roxmltree", @@ -4763,6 +4857,30 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "vello_common" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a235ba928b3109ad9e7696270edb09445a52ae1c7c08e6d31a19b1cdd6cbc24a" +dependencies = [ + "bytemuck", + "fearless_simd", + "log", + "peniko", + "skrifa", + "smallvec", +] + +[[package]] +name = "vello_cpu" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0bd1fcf9c1814f17a491e07113623d44e3ec1125a9f3401f5e047d6d326da21" +dependencies = [ + "bytemuck", + "vello_common", +] + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index c647614c0..b1822d58a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,6 @@ eframe = { version = "0.33.2", path = "crates/eframe", default-features = false accesskit = "0.21.1" accesskit_consumer = "0.30.1" accesskit_winit = "0.29.1" -ab_glyph = "0.2.32" ahash = { version = "0.8.12", default-features = false, features = [ "no-rng", # we don't need DOS-protection, so we let users opt-in to it instead "std", @@ -122,8 +121,10 @@ rayon = "1.11.0" resvg = { version = "0.45.1", default-features = false } rfd = "0.15.4" ron = "0.11.0" +self_cell = "1.2.1" serde = { version = "1.0.228", features = ["derive"] } similar-asserts = "1.7.0" +skrifa = "0.37.0" smallvec = "1.15.1" smithay-clipboard = "0.7.2" static_assertions = "1.1.0" @@ -135,6 +136,7 @@ toml = "0.8" type-map = "0.5.1" unicode_names2 = { version = "2.0.0", default-features = false } unicode-segmentation = "1.12.0" +vello_cpu = { version = "0.0.4", default-features = false, features = ["std"] } wasm-bindgen = "0.2.100" # Keep wasm-bindgen version in sync in: setup_web.sh, Cargo.toml, Cargo.lock, rust.yml wasm-bindgen-futures = "0.4.0" wayland-cursor = { version = "0.31.11", default-features = false } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 9d9d4b53f..988226e2c 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -20,7 +20,7 @@ use crate::{ ModifierNames, Modifiers, NumExt as _, Order, Painter, RawInput, Response, RichText, SafeAreaInsets, ScrollArea, Sense, Style, TextStyle, TextureHandle, TextureOptions, Ui, ViewportBuilder, ViewportCommand, ViewportId, ViewportIdMap, ViewportIdPair, ViewportIdSet, - ViewportOutput, Widget as _, WidgetRect, WidgetText, + ViewportOutput, Visuals, Widget as _, WidgetRect, WidgetText, animation_manager::AnimationManager, containers::{self, area::AreaState}, data::output::PlatformOutput, @@ -34,8 +34,7 @@ use crate::{ os::OperatingSystem, output::FullOutput, pass_state::PassState, - plugin, - plugin::TypedPluginHandle, + plugin::{self, TypedPluginHandle}, resize, response, scroll_area, util::IdTypeMap, viewport::ViewportClass, @@ -564,7 +563,10 @@ impl ContextImpl { log::trace!("Adding new fonts"); } - let text_alpha_from_coverage = self.memory.options.style().visuals.text_alpha_from_coverage; + let Visuals { + mut text_options, .. + } = self.memory.options.style().visuals; + text_options.max_texture_side = max_texture_side; let mut is_new = false; @@ -573,16 +575,12 @@ impl ContextImpl { is_new = true; profiling::scope!("Fonts::new"); - Fonts::new( - max_texture_side, - text_alpha_from_coverage, - self.font_definitions.clone(), - ) + Fonts::new(text_options, self.font_definitions.clone()) }); { profiling::scope!("Fonts::begin_pass"); - fonts.begin_pass(max_texture_side, text_alpha_from_coverage); + fonts.begin_pass(text_options); } } @@ -2006,15 +2004,12 @@ impl Context { pub fn set_fonts(&self, font_definitions: FontDefinitions) { profiling::function_scope!(); - let mut update_fonts = true; - - self.read(|ctx| { - if let Some(current_fonts) = ctx.fonts.as_ref() { - // NOTE: this comparison is expensive since it checks TTF data for equality - if current_fonts.definitions() == &font_definitions { - update_fonts = false; // no need to update - } - } + let update_fonts = self.read(|ctx| { + // NOTE: this comparison is expensive since it checks TTF data for equality + // TODO(valadaptive): add_font only checks the *names* for equality. Change this? + ctx.fonts + .as_ref() + .is_none_or(|fonts| fonts.definitions() != &font_definitions) }); if update_fonts { diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index b77536002..b0cff0019 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -3,7 +3,7 @@ #![allow(clippy::if_same_then_else)] use emath::Align; -use epaint::{AlphaFromCoverage, CornerRadius, Shadow, Stroke, text::FontTweak}; +use epaint::{AlphaFromCoverage, CornerRadius, Shadow, Stroke, TextOptions, text::FontTweak}; use std::{collections::BTreeMap, ops::RangeInclusive, sync::Arc}; use crate::{ @@ -948,8 +948,11 @@ pub struct Visuals { /// this is more to provide a convenient summary of the rest of the settings. pub dark_mode: bool, - /// ADVANCED: Controls how we render text. - pub text_alpha_from_coverage: AlphaFromCoverage, + /// Controls how we render text. + /// + /// The [`TextOptions::max_texture_side`] is ignored and overruled by + /// [`crate::RawInput::max_texture_side`]. + pub text_options: TextOptions, /// Override default text color for all text. /// @@ -1407,7 +1410,10 @@ impl Visuals { pub fn dark() -> Self { Self { dark_mode: true, - text_alpha_from_coverage: AlphaFromCoverage::DARK_MODE_DEFAULT, + text_options: TextOptions { + alpha_from_coverage: AlphaFromCoverage::DARK_MODE_DEFAULT, + ..Default::default() + }, override_text_color: None, weak_text_alpha: 0.6, weak_text_color: None, @@ -1470,7 +1476,10 @@ impl Visuals { pub fn light() -> Self { Self { dark_mode: false, - text_alpha_from_coverage: AlphaFromCoverage::LIGHT_MODE_DEFAULT, + text_options: TextOptions { + alpha_from_coverage: AlphaFromCoverage::LIGHT_MODE_DEFAULT, + ..Default::default() + }, widgets: Widgets::light(), selection: Selection::light(), hyperlink_color: Color32::from_rgb(0, 155, 255), @@ -2107,7 +2116,7 @@ impl Visuals { pub fn ui(&mut self, ui: &mut crate::Ui) { let Self { dark_mode, - text_alpha_from_coverage, + text_options, override_text_color: _, weak_text_alpha, weak_text_color, @@ -2207,7 +2216,7 @@ impl Visuals { }); }); - ui.collapsing("Text color", |ui| { + ui.collapsing("Text rendering", |ui| { fn ui_text_color(ui: &mut Ui, color: &mut Color32, label: impl Into) { ui.label(label.into().color(*color)); ui.color_edit_button_srgba(color); @@ -2259,7 +2268,15 @@ impl Visuals { ui.add_space(4.0); - text_alpha_from_coverage_ui(ui, text_alpha_from_coverage); + let TextOptions { + max_texture_side: _, + alpha_from_coverage, + font_hinting, + } = text_options; + + text_alpha_from_coverage_ui(ui, alpha_from_coverage); + + ui.checkbox(font_hinting, "Enable font hinting"); }); ui.collapsing("Text cursor", |ui| { @@ -2370,9 +2387,9 @@ impl Visuals { } } -fn text_alpha_from_coverage_ui(ui: &mut Ui, text_alpha_from_coverage: &mut AlphaFromCoverage) { +fn text_alpha_from_coverage_ui(ui: &mut Ui, alpha_from_coverage: &mut AlphaFromCoverage) { let mut dark_mode_special = - *text_alpha_from_coverage == AlphaFromCoverage::TwoCoverageMinusCoverageSq; + *alpha_from_coverage == AlphaFromCoverage::TwoCoverageMinusCoverageSq; ui.horizontal(|ui| { ui.label("Text rendering:"); @@ -2380,9 +2397,9 @@ fn text_alpha_from_coverage_ui(ui: &mut Ui, text_alpha_from_coverage: &mut Alpha ui.checkbox(&mut dark_mode_special, "Dark-mode special"); if dark_mode_special { - *text_alpha_from_coverage = AlphaFromCoverage::TwoCoverageMinusCoverageSq; + *alpha_from_coverage = AlphaFromCoverage::DARK_MODE_DEFAULT; } else { - let mut gamma = match text_alpha_from_coverage { + let mut gamma = match alpha_from_coverage { AlphaFromCoverage::Linear => 1.0, AlphaFromCoverage::Gamma(gamma) => *gamma, AlphaFromCoverage::TwoCoverageMinusCoverageSq => 0.5, // approximately the same @@ -2396,9 +2413,9 @@ fn text_alpha_from_coverage_ui(ui: &mut Ui, text_alpha_from_coverage: &mut Alpha ); if gamma == 1.0 { - *text_alpha_from_coverage = AlphaFromCoverage::Linear; + *alpha_from_coverage = AlphaFromCoverage::Linear; } else { - *text_alpha_from_coverage = AlphaFromCoverage::Gamma(gamma); + *alpha_from_coverage = AlphaFromCoverage::Gamma(gamma); } } }); @@ -2812,6 +2829,7 @@ impl Widget for &mut FontTweak { scale, y_offset_factor, y_offset, + hinting_override, } = self; ui.label("Scale"); @@ -2827,6 +2845,19 @@ impl Widget for &mut FontTweak { ui.add(DragValue::new(y_offset).speed(-0.02)); ui.end_row(); + ui.label("hinting_override"); + ComboBox::from_id_salt("hinting_override") + .selected_text(match hinting_override { + None => "None", + Some(true) => "Enable", + Some(false) => "Disable", + }) + .show_ui(ui, |ui| { + ui.selectable_value(hinting_override, None, "None"); + ui.selectable_value(hinting_override, Some(true), "Enable"); + ui.selectable_value(hinting_override, Some(false), "Disable"); + }); + if ui.button("Reset").clicked() { *self = Default::default(); } diff --git a/crates/egui_demo_app/tests/snapshots/clock.png b/crates/egui_demo_app/tests/snapshots/clock.png index ec50255fd..dd3ef8a4f 100644 --- a/crates/egui_demo_app/tests/snapshots/clock.png +++ b/crates/egui_demo_app/tests/snapshots/clock.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:784cbcdfd8deaf61e7b663f9416d67724e6a6a189a20ba3351908aa5c5f2deff -size 336159 +oid sha256:7051c34854469652d2d953f3110ebcf6fd60f8ee9a2b0c134d9f7255ef180ce5 +size 335353 diff --git a/crates/egui_demo_app/tests/snapshots/custom3d.png b/crates/egui_demo_app/tests/snapshots/custom3d.png index 3fbf0ab56..e1974dc57 100644 --- a/crates/egui_demo_app/tests/snapshots/custom3d.png +++ b/crates/egui_demo_app/tests/snapshots/custom3d.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4cdde1dda0e64f584c769c72f5910a7035e6a4a86a074b590e88365f12570109 -size 94062 +oid sha256:49823cfa4dfba54e54d0122f2bbb246c1daad2ca3ba15071c1ca44eeb3662855 +size 92791 diff --git a/crates/egui_demo_app/tests/snapshots/easymarkeditor.png b/crates/egui_demo_app/tests/snapshots/easymarkeditor.png index b9d8b2f22..e1a204fd3 100644 --- a/crates/egui_demo_app/tests/snapshots/easymarkeditor.png +++ b/crates/egui_demo_app/tests/snapshots/easymarkeditor.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:824d941ea538fd44fc374f5df1893eee2309004c0ee5e69a97f1c84a74b2b423 -size 182128 +oid sha256:1b65b6b1a3afe41337b8fe537525677284e49bd90be29cddb837787162ee452a +size 169596 diff --git a/crates/egui_demo_app/tests/snapshots/imageviewer.png b/crates/egui_demo_app/tests/snapshots/imageviewer.png index fee7ad891..830fe723d 100644 --- a/crates/egui_demo_app/tests/snapshots/imageviewer.png +++ b/crates/egui_demo_app/tests/snapshots/imageviewer.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44ea7ac8c8e22eb51fbcb63f00c8510de0e6ae126d19ab44c5d708d979b5362b -size 100345 +oid sha256:9c3af0c37a6997abe549dd28450c41d3d18bbc99d9577997d493566fbb7f9277 +size 96709 diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index 1d791cd6d..3b660d5c6 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -161,15 +161,11 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let pixels_per_point = 1.0; - let max_texture_side = 8 * 1024; let wrap_width = 512.0; let font_id = egui::FontId::default(); let text_color = egui::Color32::WHITE; - let mut fonts = egui::epaint::text::Fonts::new( - max_texture_side, - egui::epaint::AlphaFromCoverage::default(), - egui::FontDefinitions::default(), - ); + let mut fonts = + egui::epaint::text::Fonts::new(Default::default(), egui::FontDefinitions::default()); { c.bench_function("text_layout_uncached", |b| { b.iter(|| { @@ -209,7 +205,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { let mut rng = rand::rng(); b.iter(|| { - fonts.begin_pass(max_texture_side, egui::epaint::AlphaFromCoverage::default()); + fonts.begin_pass(egui::epaint::TextOptions::default()); // Delete a random character, simulating a user making an edit in a long file: let mut new_string = string.clone(); diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png b/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png index fcab88179..80864779a 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30929184fab7e7d5975243d86bcab79cd9f7a0c5d57dd9ae827464ff6570be7b -size 31795 +oid sha256:0c6f6847df5b3bfdcb020c1f897a57ffe0971e9de1e6977b19d3909730e1b9a5 +size 30957 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png index 373adc234..34e564457 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Clipboard Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cb944eca56724f6a2106ea8db2043dc94c0ea40bdd4cdeb0e520790f97cc9598 -size 27049 +oid sha256:43ef176837f05d1795eddda2fee344e935ff6d53edc26548c97eea191d4c6ca2 +size 25839 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png b/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png index a62936ff2..331277ebc 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Code Editor.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e4a6476a2bb8980a9207868b77a253c65c0ba8433f843bb17e622856695b720 -size 27686 +oid sha256:55b899e115bbb7a17e0e40216479f8fb3a343deddf929e4af6af137a3bf6d4b8 +size 25632 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png b/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png index 22341d7b3..9e9f9953a 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Code Example.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c1951b99908326b3f05ebb72aa4d02d0f297bdd925f38ded09041fae45400c1 -size 85217 +oid sha256:8ed04e25b2e961f44e2911a037c93729b0cb4de82b2e51cab145abbcb7b4efea +size 74543 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png index 9afd1794a..7c20e243b 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Cursor Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4c303fa620a2c7bc491a0ac1f9afdf9601b352e0e5163526c5f8732edf6bd6b3 -size 63404 +oid sha256:1bc9711ea98472bae9267190a91d3240146f4ce9a0caf0cf462d322581ec96aa +size 60508 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png b/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png index 05a412548..58e0eafc7 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Dancing Strings.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0df751bac5947c9bf6f82d075cf5670a562742b80d6c512bcd642da5ed449d26 -size 25975 +oid sha256:111caa91ae0658acc17a7dd49582b780ae706ba4ac7812d2a63e09a18a0be967 +size 25585 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png b/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png index 9b1b65636..346f06675 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Drag and Drop.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e26e87f2909414b614278a1cf0b485cda425aceb5419906426615dccdcbef2b -size 20877 +oid sha256:7e34217e8a006721bc4525277b96cf99618e3275626aa054b97a8cb4c7c963ab +size 19937 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png b/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png index 69d55cd27..886077140 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Extra Viewport.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20e3050bd41c7b9d225feb71f3bea3fdd1b8f749f77c4d140b5e560f53eb32b7 -size 10731 +oid sha256:e62836d9afa18cf4e486fe2819e652bf5df160026dc258201db0b99a75bdf7f1 +size 10125 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png b/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png index 2a12a3152..22c3c4574 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Font Book.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1227636b03a7d35db3482b19f6059ec7aaf03ca795edadd5338056be6f6a8f7f -size 126724 +oid sha256:c504102299780498c6b3e463e627588653446caa10bdebc4366900d0e46b649c +size 112349 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Frame.png b/crates/egui_demo_lib/tests/snapshots/demos/Frame.png index 0385ab120..f7f2aed0e 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Frame.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Frame.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c01e96bf0aab24dbcfc05f2a6dcb0ffcddff69ec2474797de4fbce0a0670a8cd -size 24964 +oid sha256:d44e5abe3f64d5f72bbf7519b6ead816adf1f8ad22711e8ef8f34f9574223d4b +size 24152 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png index e14a4ecb5..e27747a96 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Grid Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec357eafd145194f99c36a53a149a8b331fd691c5088df43ee96282b84bc81a4 -size 99439 +oid sha256:38d3d349f3c31b6e5a5a04984d290e2e36441b2ced7ac2060b6c2311715068d9 +size 96806 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png b/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png index 99cfc8f5d..649470e27 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5c95085e3c78b3fa1cc39ebd032834bd5ab5a80c3a2cad482d8a5bcbad004b9 -size 18064 +oid sha256:1f949b6ce193d360e9624b9e29e21413021828237de944c594beb5c4c3fb60e1 +size 17320 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png b/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png index f2d914cc2..d981e7995 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/ID Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28a69a52c07344576f2b5335497151e4e923b838dfaec9791402949ffb099c12 -size 116116 +oid sha256:a61c10399c3d48d2cbbb4c6cb3beeaf5b448d4a4eb56f6709ad22e2a67b6cff0 +size 111994 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png b/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png index c100d9209..4c36acb94 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Input Event History.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1378d865af3df02e12a0c4bc087620a4e9ef0029221db3180cdd2fd34f69d7f -size 24832 +oid sha256:17027c0e50ca6f3543897420cab3d94156c514160e7c4db4ecc5db470e801ee0 +size 24014 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png index dd2d414a4..4069db0ef 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Input Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb3f7b5f790830b46d1410c2bbb5e19c6beb403f8fe979eb8d250fba4f89be3e -size 51670 +oid sha256:1525cf27432b6d50a2dac99f400550f5018ddde8f62f77364c536455529e494b +size 49780 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png b/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png index 1ef6bf0db..c53dce298 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Interactive Container.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70b00222e6c63f97bfd8c7a179c15cfaba93f8f2566702d4b03997f4714fe6cb -size 22609 +oid sha256:2777a8d4d64983512d42074129d1c9d3bde2e43ec9f3b3b929a2df5320eb01e6 +size 21650 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png index ed84d7428..512d8cad6 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Layout Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad26106a86a6236f0db1c51bed754b370530813e9bb6e36c1be2948820fbef25 -size 47827 +oid sha256:88a10a92d0fd0104c7883434b5e49f424f7100ab5013a456216c6bf5bb1e4076 +size 45904 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png index 9f42483fe..c9d616020 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Manual Layout Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afa66ba8daca5c00f9c49b1d9173ad8f5e826247d3a9369d7e7c360cbdfcb72e -size 22928 +oid sha256:48867e0418b2002c5e3f6fae69e6a30d0ef69b3d2dc98a1f7ee175064596450f +size 21879 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png b/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png index 919bdc66d..e2f75c506 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Misc Demos.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:170cee9d72a4ab59aa2faf1b77aff4a9eee64f3380aa3f1b256340d88b1dabc2 -size 66525 +oid sha256:08b787f4e579746d87338b669d5754f8fecfdd1cb7cf23f6f3dcd1e483054dcb +size 63759 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Modals.png b/crates/egui_demo_lib/tests/snapshots/demos/Modals.png index 47718fdd1..f7e790857 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Modals.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Modals.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90ab689d8a5034f5cab2ae2b44a8054d6dd815b3d295bee040c5bfcdf4564dee -size 33063 +oid sha256:2ce9633fe06a9bd63d6219f0f7764fa5459a5441a35f385234aa5051495ad48a +size 32357 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png b/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png index daa9da35a..fa4bd7e25 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Multi Touch.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bf7f0a76424a959ede7afbb0eaf777638038cc6fe208ef710d9d82638d68b4d0 -size 37848 +oid sha256:dc89d49518a6a41c346cf9146657474f5b8898fa0f53e2aedc9c350c62865c41 +size 36721 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Painting.png b/crates/egui_demo_lib/tests/snapshots/demos/Painting.png index e53f4f7af..3d4b71b39 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Painting.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Painting.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2d2370972781f15a1d602deca28bca38f1c077152801870edf2112650b8b1349 -size 17708 +oid sha256:b040b83a49b599d0833ca3ce53ba974e0672e6a2eb1e711fc87e3a59718a7d89 +size 17003 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Panels.png b/crates/egui_demo_lib/tests/snapshots/demos/Panels.png index ca9bacfca..8d5515e39 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Panels.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Panels.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7a7d0e2618b852b5966073438c95cb62901d5410c1473639920b0b0bf2ec59b -size 256913 +oid sha256:9da1fc5172d2d20ac44048f34b1cead35eb32a9bffebf8d9c031686880c767b7 +size 247070 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Popups.png b/crates/egui_demo_lib/tests/snapshots/demos/Popups.png index d00256a7e..c5b559c52 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Popups.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Popups.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8b937a8a63de6fedcd0f9748b1d04cd863331a297bec78906885a0107def32a -size 61242 +oid sha256:24088f20928106f51c38197b4c5d61d1c0d32371ca94018dc0f8b4f9e43700d0 +size 53228 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png b/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png index f96fce916..51553321b 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/SVG Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a11b0aeb8b8a7ff3acd54b99869af03cd04cc2edf13afc713ce924c52d39262d -size 24826 +oid sha256:ecfa78eda551ae362b65118b82054ec640ebd80ddcaf1eee5fbec002bba2bcde +size 24722 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Scene.png b/crates/egui_demo_lib/tests/snapshots/demos/Scene.png index 2344a3868..3efeb1d80 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Scene.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Scene.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2855bd95ab33b5232edada1f65684bbba2748025b6b64eb9ac68a5f2d10ad4bd -size 34491 +oid sha256:dbbd302b6dcd22b89567747ad791f1d05ead01292fb7146ef8ab04e99e2a6c97 +size 31886 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png b/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png index 7e49a8613..0e1bb5d90 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be599ae66323140bba4a7d63546acbf84340b57e2d82d4736bf3fe590040319d -size 23623 +oid sha256:c9d4f953f7cffc647da604e32caa8b122aec6e940b9af38756c4f8746d1a1b31 +size 22691 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png b/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png index 6de002ee4..90f904d47 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01c3cb5e8972e0cab5325328f93af8f51b35a0d61016e74969eab0f7ddea1e02 -size 176973 +oid sha256:e2fa6340b31dfb2cf9b31b88391555357d84ec4bd062cb1039838d078af07c2f +size 170465 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png b/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png index 417b183b5..05a4d4324 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2f6cedc262259d52c1fbf4283d99b4b62ec732e8688b1e2799a2581425e0564 -size 120342 +oid sha256:d1a2c686b37d7d70d09a0236ce83e4c6eed6c72f8e3cc02331a99cc376115234 +size 116410 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Strip.png b/crates/egui_demo_lib/tests/snapshots/demos/Strip.png index be51e5062..ee237957c 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Strip.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Strip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:142f65cee971f82a4917734c4f49ae233aa9a873028dca8c807d2825672bf2b2 -size 26657 +oid sha256:d3d99f7790cfe1eb9ff2e2f010756781bb5911cc8102c2d38ee3e82c04f8f944 +size 25450 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Table.png b/crates/egui_demo_lib/tests/snapshots/demos/Table.png index 188c548d8..03fa6274e 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Table.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Table.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72f4c6fe4f5ec243506152027e1150f3069caf98511ceef92b8fea4f6a1563d5 -size 77614 +oid sha256:ab7d1620779aa75f6596d9f84707533f7f6b04bb9c51d8dfea10cfb7abdb7b73 +size 73525 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png index cd8524cef..fa7ed7d65 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Tessellation Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc24f146adf0282cfb51723b56c76eceb92f2988fc67bbeefd16b93950505922 -size 70110 +oid sha256:af2373c1ff32cc520f64e14a29a0c386b14df7dba04f6c281c20b537016b98dc +size 68101 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png b/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png index 28c9f57ac..b738c6c1d 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Text Layout.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77aeaa1dcd391a571cb38732686e0b85b2d727975c02507a114d4e932f2c351b -size 65562 +oid sha256:9b6eedb91e29999e0300707f88a44ffa941c72639a89383a507ed7e8c5d80731 +size 59421 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png b/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png index 3ee3adf6e..54f2d8967 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f964939ed1b3904706592915ca4fbbb951855ac88b466c51b835cd1c7467fb0 -size 21501 +oid sha256:c050180f968ac82287212f6f12eb242dd1266fd920f249cc6d48d8c9bfa1abe6 +size 20814 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png b/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png index 265dfdc1e..2acc75577 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:415b1ce17dd6df7ca7a86fed92750c2ef811ff64720a447ae3ca6be10090666e -size 64624 +oid sha256:c105e9267e81541d11e73a10fcb92c80ae8daeba6b9c586800b07264d5143071 +size 61536 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png b/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png index fb2bd06aa..3f4d49bba 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Undo Redo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0eaf717bf0083737c4186ac39e7baf98f42fffb36b49434a6658eff1430a0ac6 -size 13187 +oid sha256:185b62db2f890b05a3fb9029dae8e4452a37e3caae5c7b993c9995aefa078eff +size 12813 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png b/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png index e782c983a..3ca4bfecd 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Window Options.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:611a2d6c793a85eebe807b2ddd4446cc0bc21e4284343dd756e64f0232fb6815 -size 35991 +oid sha256:7425b60e0064dfd9e341fe55e059cbb6a372d526433cb3b1c234a105f16fd247 +size 34520 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png b/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png index 7a042bdba..6af84f673 100644 --- a/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png +++ b/crates/egui_demo_lib/tests/snapshots/demos/Window Resize Test.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b85a2af24c3361a0008fd0996e8d7244dc3e289646ec7233e8bad39a586c871c -size 44512 +oid sha256:4731c35a62a88533940c12a06cf8d31479c59a538ef69109b3a655e2d7ef3e43 +size 42109 diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png index 3d6c3f55c..aeaa46a34 100644 --- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png +++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:67b709c116f56fba7e4e9f182018e84f46f6c6dd33a51f9d0524125dc2056b8c -size 12950 +oid sha256:89074b8dab103a419bc3dac743da4d8c47f435fa55b98d8aab71f6c9fb4d39de +size 12370 diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png index e28eaeda9..1359fd607 100644 --- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png +++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_dark_x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b0a70c0d66306edbbc6f77d03ea624aa68b846656811d4cc7d76d28572d177b -size 30723 +oid sha256:968c478d986fc71d8655492b19e833ca07bc0ab85899dc04022bc7cf1dcf782f +size 29319 diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png index 391257018..da72002a0 100644 --- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png +++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:137ba69ac73a5e9aacc6bf3bbd589e8640b41c50ccfb49edcda4e2d6efed6c09 -size 13384 +oid sha256:7bd7b54ff60859e4d4793000bef3adbec4c071063bec6bfdbde62516c4fc3478 +size 12959 diff --git a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png index f5e700ee3..80e561325 100644 --- a/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png +++ b/crates/egui_demo_lib/tests/snapshots/image_kerning/image_light_x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f798c666ad21d3f9bb57826e30f2f6ef044543bc05af8c185e0e63c8297e824 -size 33181 +oid sha256:61e59f8360c567e20bf03b401362de7bb0f87716f13e817cc8da3df742ab68bf +size 31869 diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png index 0d70d6973..5018d53c8 100644 --- a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png +++ b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44fc7d745b478fe937fa7c131871a00b26712a0317aaa027a088782533be6136 -size 7125 +oid sha256:7389e319d9153af313cc113d97b57d462da00feb0d5f99da211552af3ac7e18a +size 6704 diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png index 505c764d5..3a1b72bb3 100644 --- a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png +++ b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x1.41.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:abfa00ef9385d380bbd188d6254f92d6839a94f368100e75a2780337438f969f -size 11068 +oid sha256:d4480dd34ed36c6bdbc2084843dd136448b3934c22b3df3e40314ba6324b5b39 +size 10306 diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png index 7c040d71a..0f18eb109 100644 --- a/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png +++ b/crates/egui_demo_lib/tests/snapshots/italics/image_dark_x2.00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e5c9015e2005429ba83a407ed1f7d4dfbf30624f666152e82079c6ed3b3cda5 -size 17238 +oid sha256:624bfa884431c35cc5d852b96653f13da17e60f8545471f9fb1c3bb85b40ffc8 +size 16555 diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png index b2291e9f1..6ebc6addc 100644 --- a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png +++ b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3319a8bca1213fc3a2dd91ead155be1e25045bc614701250bc961848cfc42176 -size 7327 +oid sha256:bf665389ef43524e097a7ae4eec0aa01bb788bdbb306144f20f9133f74a64b2c +size 6941 diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png index 995789de1..54fdc064b 100644 --- a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png +++ b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x1.41.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5172aa12f07b4abf4bb217b8952b4cf5cf61b688455751964a1b54433d8c05b1 -size 11709 +oid sha256:a2480d0f49a929993de70612572b321457b2507c149a25112064cfc27840e6ee +size 11005 diff --git a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png index 8c5e7ab03..138fd8c83 100644 --- a/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png +++ b/crates/egui_demo_lib/tests/snapshots/italics/image_light_x2.00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e3eedd952d4416af73179451c0c90bcb76635c9c3c94d37f42bdd228ddbdd03 -size 18802 +oid sha256:1e0013b499934f47370a3a20b3d3a19f8a8c6db360752a35a3fb1d676d122263 +size 18068 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_1.png b/crates/egui_demo_lib/tests/snapshots/modals_1.png index a184b67dc..c2d36be22 100644 --- a/crates/egui_demo_lib/tests/snapshots/modals_1.png +++ b/crates/egui_demo_lib/tests/snapshots/modals_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60a44771c6bc9236593717236f9eca40bcb4723bac7567493cab4326f003eba3 -size 48693 +oid sha256:0054283b203602742d9819ba275c44ea40211ba18bf56fc66dca4fca766184d3 +size 47076 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_2.png b/crates/egui_demo_lib/tests/snapshots/modals_2.png index 0aa16858a..4aa3fa2f4 100644 --- a/crates/egui_demo_lib/tests/snapshots/modals_2.png +++ b/crates/egui_demo_lib/tests/snapshots/modals_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7bc441559ff2d8723cf344113ce5ff8158e41179e4c93abcacbe7b1b13b3723 -size 48998 +oid sha256:6a40e3e7314cb32398797665b2bebb237f1a9cc79e306df9c29f7f04faa3a435 +size 47715 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_3.png b/crates/egui_demo_lib/tests/snapshots/modals_3.png index eaae2a758..75810326b 100644 --- a/crates/egui_demo_lib/tests/snapshots/modals_3.png +++ b/crates/egui_demo_lib/tests/snapshots/modals_3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3e092be54efaeb700a63d9b679894647159f39a0d3062692ac7056e98242cbee -size 45364 +oid sha256:b1ddff4f50b9a245d270cc13a0ebb9ac71d3590b83d401afb10ab107439cf235 +size 43893 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png b/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png index 8b54bf99f..4b0eb7a17 100644 --- a/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png +++ b/crates/egui_demo_lib/tests/snapshots/modals_backdrop_should_prevent_focusing_lower_area.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88930779ac199e42fcc9ee25f29bd120478c129807713218370b617905340087 -size 45366 +oid sha256:50dea7c459cf291e6c0b3166354a7e622af6682842ec36f295d532df8c064b38 +size 43984 diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png index 640d84c2b..b5367f0ed 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9980486c36a0242f3b043a172c411d4fc9573543d3cd7c1c43bf020c18868a9 -size 619816 +oid sha256:db510af76578693c85ce78ca91224758a56f7bbf33db3221c9a4edca08b06600 +size 590547 diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png index df05ada25..7158a3545 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:040e2e486ae4773a084da99513a53c620e8e2bba215183ec26c6e489381d6254 -size 823086 +oid sha256:cae2b789e8afff23b7545d42a530e6c972d28736bad2bdacbc69f0e7065f85cc +size 740660 diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png index c6aa2914f..8b9cb281f 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.50.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:439a5f942a5f05b9c09685ef90be94c150a21a68d1d235af22372b9b6a7b7389 -size 1035734 +oid sha256:09d9f567ec371d60881b525ddb462d9135552db97af5921a6eb02aba40e40616 +size 971544 diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png index 0fc009f8a..9f5a69154 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.67.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a3a9aa8383abfe4580be2cc9987f8123aeabf36bf8ec06029a9af64b9500ec9 -size 1206157 +oid sha256:3c383dd89fda6094704027074a72085591339a276d60502626d78e8e527b2e10 +size 1076719 diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png index 9804e2942..74760261a 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_1.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fedd5546e36a89121c0bb0a780b0bbe081611c2c04013064872801181503fb83 -size 1231599 +oid sha256:0b4559541cf3259496c760a26f8d83e82179cb7e4576333682c5af49ee4a35a7 +size 1125331 diff --git a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png index 04d4bb4ea..a85909178 100644 --- a/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png +++ b/crates/egui_demo_lib/tests/snapshots/rendering_test/dpi_2.00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69a7040336fc92c6d7b158283aabbc5817980c2fa84a1120b788516cf437b985 -size 1461979 +oid sha256:67c8412a1e8fdbfd88f8573797fbf6fbd89c6ce783a074a8e90f7d8d9e67dd57 +size 1366351 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png index 50e84c900..0eb5ebd6a 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Additive rectangle.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a32d361afa20fc8c20122a89b01fe14b45849da42663991e589579f70fb8577 -size 46790 +oid sha256:a2b7b54a1af0f5cd31bd64f0506e3035dd423314ce3389e61730fa160434fbf3 +size 45074 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png index ca5a23f97..bd9942eb7 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred stroke.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8d55205cf4225123da33895ed45eb186e5e57184ef5928400a4bae3ab6092be -size 88548 +oid sha256:7b66a0be67ff2d684a54c2321123521b3ad06dfe5ebffd50e89260d77efcfcc4 +size 86833 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png index 41f9ef2f5..64ddf5c49 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Blurred.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:77ab9e2e18c788f8cdbec171269afe4d0a90c52abeda7063cae3766dcaa5e93b -size 120612 +oid sha256:19320291c99a23429b114a59de4636689e281e1e68766abe2aa1e56562128e50 +size 118919 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png index 85d844c79..105bbf285 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Minimal rounding.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36622a2f934503a7b60ded2f44b002e37eedde22d548dcf5a209f54c19548665 -size 53064 +oid sha256:5edf089c00715f1456fe7838e85aadcfc42b6216a3fd95b48d9c21fc8d700cba +size 51371 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png index 6e6d9f0f2..035eb931d 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Normal.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4adeb7a77a0d0fe85097fcd190a99b49858dce11bde601d30335afcb6cc3d5f6 -size 56276 +oid sha256:6cd1a10639dcb323bdc3b2c43e0c35665184fc809731ced90088ee9edb9de845 +size 54577 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png index eefbac2bb..26014a12c 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thick stroke, minimal rounding.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f45249f7cc90433a64856905c727571c4ef20468e2c7d3ac2029e18a0477932d -size 56743 +oid sha256:87e34024f701dc93f4026213ac7eb468a2cd6d3393eb0dbec382bf58007f8e61 +size 55042 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png index 08178eaa8..dcbbba2b6 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin filled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d437f68c521f3e627a1b50d46605e8b0b343c5fc3716d9669e8c4436c8992b6f -size 37602 +oid sha256:d7940ff56796efb27bec66b632ff33aa2ad390c4962a711bf520aee341f035a4 +size 35968 diff --git a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png index 13f057df9..0a3d062af 100644 --- a/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png +++ b/crates/egui_demo_lib/tests/snapshots/tessellation_test/Thin stroked.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08ba98437403a08cca825ed8e288c9f088a46d9a1081f0b0a4ed7fbb9b49bb85 -size 37640 +oid sha256:b7bbd16c8aad444f0d11aacf87cf2292d494cc80a1ca46e7e8db86ca3041d35a +size 35931 diff --git a/crates/egui_demo_lib/tests/snapshots/text_selection.png b/crates/egui_demo_lib/tests/snapshots/text_selection.png index 78ebc0dbf..63a4423a3 100644 --- a/crates/egui_demo_lib/tests/snapshots/text_selection.png +++ b/crates/egui_demo_lib/tests/snapshots/text_selection.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14f253fedc94985ff1431f1016d901d747e1f9948531cc6350f6615649f29056 -size 4862 +oid sha256:0475c5ac04ab8f79b79d43cfdb985f05b61dbe90e81f898a6dc216c308a28841 +size 4707 diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png index ab2db5eb5..112605454 100644 --- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png +++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1ed0e40d08b2b9ea978a07a4b7bf282c9e2cba8c52896f12210f396241e1b78 -size 66859 +oid sha256:bbdc4199dee2ae853b8a240cd84528482dc6762233bd0d1249f2daa296b49487 +size 64172 diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png index e84863bf4..1b5b60c8a 100644 --- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png +++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_dark_x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28f9862dd6f16b99523f5880bf90346fd9455d0d44e7bdd530d523e0b2ef2d2c -size 158892 +oid sha256:f6d38b6b47839d0e4eae530d203c83971fba8a41c9caa3d5b5d89ee7ed582613 +size 150090 diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png index 87eb5ce70..5a2b44feb 100644 --- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png +++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98c40c99a237f8388d82259fba4388d7b1759fe7b4bf657d326532934135c934 -size 61119 +oid sha256:c0635f1564d6c9707efa68003fb8c9b6eb00408aa8f24c972e33c6c79fed5bdf +size 59354 diff --git a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png index c2c4705e1..81c7452e6 100644 --- a/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png +++ b/crates/egui_demo_lib/tests/snapshots/widget_gallery_light_x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90d36311ce5b1dcf81cab22113620a3362f255059d1f52c6794c8249f960549e -size 152215 +oid sha256:4288ee4a0d2229d59c31538179cdda50035a3849f69b400127e1618efe30cdc1 +size 145224 diff --git a/crates/egui_kittest/tests/snapshots/combobox_closed.png b/crates/egui_kittest/tests/snapshots/combobox_closed.png index bb574d356..708985b14 100644 --- a/crates/egui_kittest/tests/snapshots/combobox_closed.png +++ b/crates/egui_kittest/tests/snapshots/combobox_closed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f297609dd69fd479377eaea7cd304b717e0523a650dbf76e19c6d1f1c5af1343 -size 4518 +oid sha256:3ca39801faddae7191ed054029263e8eca488d16e1fcbb40fed482d39fc89e8e +size 4520 diff --git a/crates/egui_kittest/tests/snapshots/combobox_opened.png b/crates/egui_kittest/tests/snapshots/combobox_opened.png index e45a4aed3..53a9c8ed1 100644 --- a/crates/egui_kittest/tests/snapshots/combobox_opened.png +++ b/crates/egui_kittest/tests/snapshots/combobox_opened.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:42911cbb500fa49170aac0da8e4167641c5d7c9724a6accd4d400258fc74e2d7 -size 8061 +oid sha256:bafe5d7129cd2137b8f7bc9662b894d959b7042c436443f835ecd421a0d9c33f +size 8019 diff --git a/crates/egui_kittest/tests/snapshots/image_snapshots.png b/crates/egui_kittest/tests/snapshots/image_snapshots.png index 5036d662c..75e18ba5f 100644 --- a/crates/egui_kittest/tests/snapshots/image_snapshots.png +++ b/crates/egui_kittest/tests/snapshots/image_snapshots.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de4a197f82befde31b6966f902567c35cef96c7d541fd65b4207c693ab12bace -size 2036 +oid sha256:cd2ff48cae729b3f957b1630bef23e94fb2176982c06ec3f123c1a0892fc536d +size 1959 diff --git a/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png b/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png index c30b3fdd1..ffc93c942 100644 --- a/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png +++ b/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94ba2e648c981bf4afbd9b9d01eef0708f7067be6e4cefbdfacc13aa219c6289 -size 11253 +oid sha256:27e4950f17ab7f68f7e001ca3a4f3fc18943103f4745c87715dcf6c097e92a57 +size 11131 diff --git a/crates/egui_kittest/tests/snapshots/menu/opened.png b/crates/egui_kittest/tests/snapshots/menu/opened.png index 7a2750454..990bed40e 100644 --- a/crates/egui_kittest/tests/snapshots/menu/opened.png +++ b/crates/egui_kittest/tests/snapshots/menu/opened.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:436999f511dce318f29172f0b7e2007e1f0fedae58f5e0e85e19f1d8e0bee361 -size 22273 +oid sha256:449cc473469dc80af81fe20e394dd90e67b4ae9c2033ebb7029726274d77d50c +size 21644 diff --git a/crates/egui_kittest/tests/snapshots/menu/submenu.png b/crates/egui_kittest/tests/snapshots/menu/submenu.png index 25453c8d9..7bd7c356d 100644 --- a/crates/egui_kittest/tests/snapshots/menu/submenu.png +++ b/crates/egui_kittest/tests/snapshots/menu/submenu.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28435faf5c8c6d880cd50d52050c9f4cd6b992d0c621f01ca28fb5502eed16a1 -size 29863 +oid sha256:1cbfc767ed169cbddb3c90c2b455daefd85925501e7e33c7a25a34a72fc13eac +size 28512 diff --git a/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png b/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png index c22c2b9b6..1e3b905b1 100644 --- a/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png +++ b/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9a364b4b8c4ad3e78a80b0c6825d9de28c0e0d2e18dcfcd0ff18652ca86c859 -size 34750 +oid sha256:f4397b3d86bb5fe76d661cdb109ef71d43e771093bd9267b74722660d312ec7d +size 33253 diff --git a/crates/egui_kittest/tests/snapshots/override_text_color_interactive.png b/crates/egui_kittest/tests/snapshots/override_text_color_interactive.png index 6e92f9f03..fb8887d13 100644 --- a/crates/egui_kittest/tests/snapshots/override_text_color_interactive.png +++ b/crates/egui_kittest/tests/snapshots/override_text_color_interactive.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2fa5cb5b96232d729f89be8cc92263715fe7197e72343b71e57e53a359afe181 -size 19881 +oid sha256:e8038005841dbf272375388b224dcc9fc1177b5c113d3e6f6dbc2265c88c7e60 +size 19704 diff --git a/crates/egui_kittest/tests/snapshots/readme_example.png b/crates/egui_kittest/tests/snapshots/readme_example.png index f58e6faec..f7a5dcf62 100644 --- a/crates/egui_kittest/tests/snapshots/readme_example.png +++ b/crates/egui_kittest/tests/snapshots/readme_example.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87c76a9d07174e4e24ad3d08585c1df7bf3628bdc8f183d11beb6f9e14c4b2ec -size 2325 +oid sha256:fad8b83e553ffa6bfbc4d47b955f2180859048c3789dda99b640e27665d216c7 +size 2244 diff --git a/crates/egui_kittest/tests/snapshots/should_wait_for_images.png b/crates/egui_kittest/tests/snapshots/should_wait_for_images.png index 7e33877fc..9709e159e 100644 --- a/crates/egui_kittest/tests/snapshots/should_wait_for_images.png +++ b/crates/egui_kittest/tests/snapshots/should_wait_for_images.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f038c7fdf31f35107ec6e29edc0895049160ccbe98d1577c16ae082605b58d52 -size 2207 +oid sha256:ad75a0e568e04c20d0e3b823c7e4906c39dcd0a69a086d8e30714a9e4530d031 +size 2128 diff --git a/crates/egui_kittest/tests/snapshots/test_masking.png b/crates/egui_kittest/tests/snapshots/test_masking.png index a5fb50908..a397ceda6 100644 --- a/crates/egui_kittest/tests/snapshots/test_masking.png +++ b/crates/egui_kittest/tests/snapshots/test_masking.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d94d4c3300d406fd1d93ddd90a9a46f99eac81a98a84f4d97a20fe4ef492e5d -size 5674 +oid sha256:4216258893fae554f0ab8b3a76ef0905cacb62c70af47fa811ff6f3d99f9f3ab +size 5619 diff --git a/crates/egui_kittest/tests/snapshots/test_scroll_initial.png b/crates/egui_kittest/tests/snapshots/test_scroll_initial.png index 586dc00b7..e61dc99a0 100644 --- a/crates/egui_kittest/tests/snapshots/test_scroll_initial.png +++ b/crates/egui_kittest/tests/snapshots/test_scroll_initial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:460cb2e9c91d139334c797829fd82fa77d593e9e58531e57a6b649c7e8fad228 -size 7405 +oid sha256:eb8737af84c3d3b0c054b7e2a8bcb04685243d84cb13b72a1372dc40dbfd14fb +size 7267 diff --git a/crates/egui_kittest/tests/snapshots/test_scroll_scrolled.png b/crates/egui_kittest/tests/snapshots/test_scroll_scrolled.png index 64feb6323..0cc3d6d15 100644 --- a/crates/egui_kittest/tests/snapshots/test_scroll_scrolled.png +++ b/crates/egui_kittest/tests/snapshots/test_scroll_scrolled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:996985b155bd579cc4769d8cde5aa7e87c20ed909176da6b52dddeeb78a1cfba -size 8290 +oid sha256:f1651bb1b9bbaa3c65ecd07c39c57527f4beb4c607581a5b2596a49dcf4c5db3 +size 7996 diff --git a/crates/egui_kittest/tests/snapshots/test_shrink.png b/crates/egui_kittest/tests/snapshots/test_shrink.png index c25ae0367..40f2e284d 100644 --- a/crates/egui_kittest/tests/snapshots/test_shrink.png +++ b/crates/egui_kittest/tests/snapshots/test_shrink.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:025942c144891b8862bf931385824e0484e60f4e7766f5d4401511c72ff20756 -size 2975 +oid sha256:21a92c29e27ef0fdec273ea2d94a2b3e74cdf380ec77f4783daeb008bd51db6d +size 2767 diff --git a/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png b/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png index c25ae0367..40f2e284d 100644 --- a/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png +++ b/crates/egui_kittest/tests/snapshots/test_tooltip_hidden.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:025942c144891b8862bf931385824e0484e60f4e7766f5d4401511c72ff20756 -size 2975 +oid sha256:21a92c29e27ef0fdec273ea2d94a2b3e74cdf380ec77f4783daeb008bd51db6d +size 2767 diff --git a/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png b/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png index 4d00c924a..86cc5a717 100644 --- a/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png +++ b/crates/egui_kittest/tests/snapshots/test_tooltip_shown.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e269ede9c0784d00c153d51a13566d9c8f0d61ce11565997691fa63be06ec889 -size 5075 +oid sha256:f9ca5f8081d677b8bff47813c4eb94319ca03855e780aed834ecc2f3d905a22c +size 4852 diff --git a/crates/epaint/Cargo.toml b/crates/epaint/Cargo.toml index 3ac99a97f..77facdb3f 100644 --- a/crates/epaint/Cargo.toml +++ b/crates/epaint/Cargo.toml @@ -61,12 +61,14 @@ _override_unity = [] emath.workspace = true ecolor.workspace = true -ab_glyph.workspace = true ahash.workspace = true log.workspace = true nohash-hasher.workspace = true parking_lot.workspace = true # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. -profiling = { workspace = true } +profiling.workspace = true +self_cell.workspace = true +skrifa.workspace = true +vello_cpu.workspace = true #! ### Optional dependencies bytemuck = { workspace = true, optional = true, features = ["derive"] } diff --git a/crates/epaint/benches/benchmark.rs b/crates/epaint/benches/benchmark.rs index 7b97b20a2..8fbfc65ea 100644 --- a/crates/epaint/benches/benchmark.rs +++ b/crates/epaint/benches/benchmark.rs @@ -1,8 +1,8 @@ use criterion::{Criterion, criterion_group, criterion_main}; use epaint::{ - AlphaFromCoverage, ClippedShape, Color32, Mesh, PathStroke, Pos2, Rect, Shape, Stroke, - TessellationOptions, Tessellator, TextureAtlas, Vec2, pos2, tessellator::Path, + ClippedShape, Color32, Mesh, PathStroke, Pos2, Rect, Shape, Stroke, TessellationOptions, + Tessellator, TextureAtlas, Vec2, pos2, tessellator::Path, }; use std::hint::black_box; @@ -68,7 +68,7 @@ fn tessellate_circles(c: &mut Criterion) { let pixels_per_point = 2.0; let options = TessellationOptions::default(); - let atlas = TextureAtlas::new([4096, 256], AlphaFromCoverage::default()); + let atlas = TextureAtlas::new([4096, 256], Default::default()); let font_tex_size = atlas.size(); let prepared_discs = atlas.prepared_discs(); diff --git a/crates/epaint/src/lib.rs b/crates/epaint/src/lib.rs index 1bf0285bd..942ca5452 100644 --- a/crates/epaint/src/lib.rs +++ b/crates/epaint/src/lib.rs @@ -62,7 +62,7 @@ pub use self::{ stats::PaintStats, stroke::{PathStroke, Stroke, StrokeKind}, tessellator::{TessellationOptions, Tessellator}, - text::{FontFamily, FontId, Fonts, FontsView, Galley}, + text::{FontFamily, FontId, Fonts, FontsView, Galley, TextOptions}, texture_atlas::TextureAtlas, texture_handle::TextureHandle, textures::TextureManager, diff --git a/crates/epaint/src/shapes/text_shape.rs b/crates/epaint/src/shapes/text_shape.rs index 92a0a0514..3e177db07 100644 --- a/crates/epaint/src/shapes/text_shape.rs +++ b/crates/epaint/src/shapes/text_shape.rs @@ -185,11 +185,7 @@ mod tests { #[test] fn text_bounding_box_under_rotation() { - let mut fonts = Fonts::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = Fonts::new(TextOptions::default(), FontDefinitions::default()); let font = FontId::monospace(12.0); let mut t = crate::Shape::text( diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index 4584c3457..0dbc00ddd 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -1,13 +1,20 @@ +#![allow(clippy::mem_forget)] + use std::collections::BTreeMap; -use ab_glyph::{Font as _, OutlinedGlyph, PxScale}; use emath::{GuiRounding as _, OrderedFloat, Vec2, vec2}; +use self_cell::self_cell; +use skrifa::{ + MetadataProvider as _, + raw::{TableProvider as _, tables::kern::SubtableKind}, +}; +use vello_cpu::{color, kurbo}; use crate::{ - TextureAtlas, + TextOptions, TextureAtlas, text::{ FontTweak, - fonts::{CachedFamily, FontFaceKey}, + fonts::{Blob, CachedFamily, FontFaceKey}, }, }; @@ -43,9 +50,9 @@ pub struct GlyphInfo { /// Doesn't need to be unique. /// /// Is `None` for a special "invisible" glyph. - pub(crate) id: Option, + pub(crate) id: Option, - /// In [`ab_glyph`]s "unscaled" coordinate system. + /// In [`skrifa`]s "unscaled" coordinate system. pub advance_width_unscaled: OrderedFloat, } @@ -123,8 +130,8 @@ pub struct GlyphAllocation { /// Used for pair-kerning. /// /// Doesn't need to be unique. - /// Use `ab_glyph::GlyphId(0)` if you just want to have an id, and don't care. - pub(crate) id: ab_glyph::GlyphId, + /// Use [`skrifa::GlyphId::NOTDEF`] if you just want to have an id, and don't care. + pub(crate) id: skrifa::GlyphId, /// Unit: screen pixels. pub advance_width_px: f32, @@ -139,7 +146,7 @@ struct GlyphCacheKey(u64); impl nohash_hasher::IsEnabled for GlyphCacheKey {} impl GlyphCacheKey { - fn new(glyph_id: ab_glyph::GlyphId, metrics: &ScaledMetrics, bin: SubpixelBin) -> Self { + fn new(glyph_id: skrifa::GlyphId, metrics: &ScaledMetrics, bin: SubpixelBin) -> Self { let ScaledMetrics { pixels_per_point, px_scale_factor, @@ -164,41 +171,229 @@ impl GlyphCacheKey { // ---------------------------------------------------------------------------- +struct DependentFontData<'a> { + skrifa: skrifa::FontRef<'a>, + charmap: skrifa::charmap::Charmap<'a>, + outline_glyphs: skrifa::outline::OutlineGlyphCollection<'a>, + metrics: skrifa::metrics::Metrics, + glyph_metrics: skrifa::metrics::GlyphMetrics<'a>, + hinting_instance: Option, +} + +self_cell! { + struct FontCell { + owner: Blob, + + #[covariant] + dependent: DependentFontData, + } +} + +impl FontCell { + fn px_scale_factor(&self, scale: f32) -> f32 { + let units_per_em = self.borrow_dependent().metrics.units_per_em as f32; + scale / units_per_em + } + + fn allocate_glyph_uncached( + &mut self, + atlas: &mut TextureAtlas, + metrics: &ScaledMetrics, + glyph_info: &GlyphInfo, + bin: SubpixelBin, + ) -> Option { + let glyph_id = glyph_info.id?; + + debug_assert!( + glyph_id != skrifa::GlyphId::NOTDEF, + "Can't allocate glyph for id 0" + ); + + let mut path = kurbo::BezPath::new(); + let mut pen = VelloPen { + path: &mut path, + x_offset: bin.as_float() as f64, + }; + + self.with_dependent_mut(|_, font_data| { + let outline = font_data.outline_glyphs.get(glyph_id)?; + + if let Some(hinting_instance) = &mut font_data.hinting_instance { + let size = skrifa::instance::Size::new(metrics.scale); + if hinting_instance.size() != size { + hinting_instance + .reconfigure( + &font_data.outline_glyphs, + size, + skrifa::instance::LocationRef::default(), + skrifa::outline::Target::Smooth { + mode: skrifa::outline::SmoothMode::Normal, + symmetric_rendering: true, + preserve_linear_metrics: true, + }, + ) + .ok()?; + } + let draw_settings = skrifa::outline::DrawSettings::hinted(hinting_instance, false); + outline.draw(draw_settings, &mut pen).ok()?; + } else { + let draw_settings = skrifa::outline::DrawSettings::unhinted( + skrifa::instance::Size::new(metrics.scale), + skrifa::instance::LocationRef::default(), + ); + outline.draw(draw_settings, &mut pen).ok()?; + } + + Some(()) + })?; + + let bounds = path.control_box().expand(); + let width = bounds.width() as u16; + let height = bounds.height() as u16; + + let mut ctx = vello_cpu::RenderContext::new(width, height); + ctx.set_transform(kurbo::Affine::translate((-bounds.x0, -bounds.y0))); + ctx.set_paint(color::OpaqueColor::::WHITE); + ctx.fill_path(&path); + let mut dest = vello_cpu::Pixmap::new(width, height); + ctx.render_to_pixmap(&mut dest); + let uv_rect = if width == 0 || height == 0 { + UvRect::default() + } else { + let glyph_pos = { + let alpha_from_coverage = atlas.options().alpha_from_coverage; + let (glyph_pos, image) = atlas.allocate((width as usize, height as usize)); + let pixels = dest.data_as_u8_slice(); + for y in 0..height as usize { + for x in 0..width as usize { + image[(x + glyph_pos.0, y + glyph_pos.1)] = alpha_from_coverage + .color_from_coverage( + pixels[((y * width as usize) + x) * 4 + 3] as f32 / 255.0, + ); + } + } + glyph_pos + }; + let offset_in_pixels = vec2(bounds.x0 as f32, bounds.y0 as f32); + let offset = + offset_in_pixels / metrics.pixels_per_point + metrics.y_offset_in_points * Vec2::Y; + UvRect { + offset, + size: vec2(width as f32, height as f32) / metrics.pixels_per_point, + min: [glyph_pos.0 as u16, glyph_pos.1 as u16], + max: [ + (glyph_pos.0 + width as usize) as u16, + (glyph_pos.1 + height as usize) as u16, + ], + } + }; + + Some(GlyphAllocation { + id: glyph_id, + advance_width_px: glyph_info.advance_width_unscaled.0 * metrics.px_scale_factor, + uv_rect, + }) + } +} + +struct VelloPen<'a> { + path: &'a mut kurbo::BezPath, + x_offset: f64, +} + +impl skrifa::outline::OutlinePen for VelloPen<'_> { + fn move_to(&mut self, x: f32, y: f32) { + self.path.move_to((x as f64 + self.x_offset, -y as f64)); + } + + fn line_to(&mut self, x: f32, y: f32) { + self.path.line_to((x as f64 + self.x_offset, -y as f64)); + } + + fn quad_to(&mut self, cx0: f32, cy0: f32, x: f32, y: f32) { + self.path.quad_to( + (cx0 as f64 + self.x_offset, -cy0 as f64), + (x as f64 + self.x_offset, -y as f64), + ); + } + + fn curve_to(&mut self, cx0: f32, cy0: f32, cx1: f32, cy1: f32, x: f32, y: f32) { + self.path.curve_to( + (cx0 as f64 + self.x_offset, -cy0 as f64), + (cx1 as f64 + self.x_offset, -cy1 as f64), + (x as f64 + self.x_offset, -y as f64), + ); + } + + fn close(&mut self) { + self.path.close_path(); + } +} + /// A specific font face. /// The interface uses points as the unit for everything. -pub struct FontImpl { +pub struct FontFace { name: String, - ab_glyph_font: ab_glyph::FontArc, + font: FontCell, tweak: FontTweak, glyph_info_cache: ahash::HashMap, glyph_alloc_cache: ahash::HashMap, } -trait FontExt { - fn px_scale_factor(&self, scale: f32) -> f32; -} +impl FontFace { + pub fn new( + options: TextOptions, + name: String, + font_data: Blob, + index: u32, + tweak: FontTweak, + ) -> Result> { + let font = FontCell::try_new(font_data, |font_data| { + let skrifa_font = + skrifa::FontRef::from_index(AsRef::<[u8]>::as_ref(font_data.as_ref()), index)?; -impl FontExt for T -where - T: ab_glyph::Font, -{ - fn px_scale_factor(&self, scale: f32) -> f32 { - let units_per_em = self.units_per_em().unwrap_or_else(|| { - panic!("The font unit size exceeds the expected range (16..=16384)") - }); - scale / units_per_em - } -} + let charmap = skrifa_font.charmap(); + let glyphs = skrifa_font.outline_glyphs(); + let metrics = skrifa_font.metrics( + skrifa::instance::Size::unscaled(), + skrifa::instance::LocationRef::default(), + ); + let glyph_metrics = skrifa_font.glyph_metrics( + skrifa::instance::Size::unscaled(), + skrifa::instance::LocationRef::default(), + ); -impl FontImpl { - pub fn new(name: String, ab_glyph_font: ab_glyph::FontArc, tweak: FontTweak) -> Self { - Self { + let hinting_enabled = tweak.hinting_override.unwrap_or(options.font_hinting); + let hinting_instance = hinting_enabled + .then(|| { + // It doesn't really matter what we put here for options. Since the size is `unscaled()`, we will + // always reconfigure this hinting instance with the real options when rendering for the first time. + skrifa::outline::HintingInstance::new( + &glyphs, + skrifa::instance::Size::unscaled(), + skrifa::instance::LocationRef::default(), + skrifa::outline::Target::default(), + ) + .ok() + }) + .flatten(); + + Ok::, Box>(DependentFontData { + skrifa: skrifa_font, + charmap, + outline_glyphs: glyphs, + metrics, + glyph_metrics, + hinting_instance, + }) + })?; + Ok(Self { name, - ab_glyph_font, + font, tweak, glyph_info_cache: Default::default(), glyph_alloc_cache: Default::default(), - } + }) } /// Code points that will always be replaced by the replacement character. @@ -223,10 +418,11 @@ impl FontImpl { /// An un-ordered iterator over all supported characters. fn characters(&self) -> impl Iterator + '_ { - self.ab_glyph_font - .codepoint_ids() - .map(|(_, chr)| chr) - .filter(|&chr| !self.ignore_character(chr)) + self.font + .borrow_dependent() + .charmap + .mappings() + .filter_map(|(chr, _)| char::from_u32(chr).filter(|c| !self.ignore_character(*c))) } /// `\n` will result in `None` @@ -258,7 +454,7 @@ impl FontImpl { // https://en.wikipedia.org/wiki/Thin_space if let Some(space) = self.glyph_info(' ') { - let em = self.ab_glyph_font.units_per_em().unwrap_or(1.0); + let em = self.font.borrow_dependent().metrics.units_per_em as f32; let advance_width = f32::min(em / 6.0, space.advance_width_unscaled.0 * 0.5); // TODO(emilk): make configurable let glyph_info = GlyphInfo { advance_width_unscaled: advance_width.into(), @@ -275,52 +471,68 @@ impl FontImpl { return Some(glyph_info); } - // Add new character: - let glyph_id = self.ab_glyph_font.glyph_id(c); + let font_data = self.font.borrow_dependent(); - if glyph_id.0 == 0 { - None // unsupported character - } else { - let glyph_info = GlyphInfo { - id: Some(glyph_id), - advance_width_unscaled: self.ab_glyph_font.h_advance_unscaled(glyph_id).into(), - }; - self.glyph_info_cache.insert(c, glyph_info); - Some(glyph_info) - } + // Add new character: + let glyph_id = font_data + .charmap + .map(c) + .filter(|id| *id != skrifa::GlyphId::NOTDEF)?; + + let glyph_info = GlyphInfo { + id: Some(glyph_id), + advance_width_unscaled: font_data + .glyph_metrics + .advance_width(glyph_id) + .unwrap_or_default() + .into(), + }; + self.glyph_info_cache.insert(c, glyph_info); + Some(glyph_info) } #[inline] pub(super) fn pair_kerning_pixels( &self, metrics: &ScaledMetrics, - last_glyph_id: ab_glyph::GlyphId, - glyph_id: ab_glyph::GlyphId, + last_glyph_id: skrifa::GlyphId, + glyph_id: skrifa::GlyphId, ) -> f32 { - self.ab_glyph_font.kern_unscaled(last_glyph_id, glyph_id) * metrics.px_scale_factor + let skrifa_font = &self.font.borrow_dependent().skrifa; + let Ok(kern) = skrifa_font.kern() else { + return 0.0; + }; + kern.subtables() + .find_map(|st| match st.ok()?.kind().ok()? { + SubtableKind::Format0(table_ref) => table_ref.kerning(last_glyph_id, glyph_id), + SubtableKind::Format1(_) => None, + SubtableKind::Format2(subtable2) => subtable2.kerning(last_glyph_id, glyph_id), + SubtableKind::Format3(table_ref) => table_ref.kerning(last_glyph_id, glyph_id), + }) + .unwrap_or_default() as f32 + * metrics.px_scale_factor } #[inline] pub fn pair_kerning( &self, metrics: &ScaledMetrics, - last_glyph_id: ab_glyph::GlyphId, - glyph_id: ab_glyph::GlyphId, + last_glyph_id: skrifa::GlyphId, + glyph_id: skrifa::GlyphId, ) -> f32 { self.pair_kerning_pixels(metrics, last_glyph_id, glyph_id) / metrics.pixels_per_point } #[inline(always)] pub fn scaled_metrics(&self, pixels_per_point: f32, font_size: f32) -> ScaledMetrics { - let pt_scale_factor = self - .ab_glyph_font - .px_scale_factor(font_size * self.tweak.scale); - let ascent = (self.ab_glyph_font.ascent_unscaled() * pt_scale_factor).round_ui(); - let descent = (self.ab_glyph_font.descent_unscaled() * pt_scale_factor).round_ui(); - let line_gap = (self.ab_glyph_font.line_gap_unscaled() * pt_scale_factor).round_ui(); + let pt_scale_factor = self.font.px_scale_factor(font_size * self.tweak.scale); + let font_data = self.font.borrow_dependent(); + let ascent = (font_data.metrics.ascent * pt_scale_factor).round_ui(); + let descent = (font_data.metrics.descent * pt_scale_factor).round_ui(); + let line_gap = (font_data.metrics.leading * pt_scale_factor).round_ui(); let scale = font_size * self.tweak.scale * pixels_per_point; - let px_scale_factor = self.ab_glyph_font.px_scale_factor(scale); + let px_scale_factor = self.font.px_scale_factor(scale); let y_offset_in_points = ((font_size * self.tweak.scale * self.tweak.y_offset_factor) + self.tweak.y_offset) @@ -329,6 +541,7 @@ impl FontImpl { ScaledMetrics { pixels_per_point, px_scale_factor, + scale, y_offset_in_points, ascent, row_height: ascent - descent + line_gap, @@ -370,77 +583,20 @@ impl FontImpl { std::collections::hash_map::Entry::Vacant(entry) => entry, }; - debug_assert!(glyph_id.0 != 0, "Can't allocate glyph for id 0"); + let allocation = self + .font + .allocate_glyph_uncached(atlas, metrics, &glyph_info, bin) + .unwrap_or_default(); - let uv_rect = self.ab_glyph_font.outline(glyph_id).map(|outline| { - let glyph = ab_glyph::Glyph { - id: glyph_id, - // We bypass ab-glyph's scaling method because it uses the wrong scale - // (https://github.com/alexheretic/ab-glyph/issues/15), and this field is never accessed when - // rasterizing. We can just put anything here. - scale: PxScale::from(0.0), - position: ab_glyph::Point { - x: bin.as_float(), - y: 0.0, - }, - }; - let outlined = OutlinedGlyph::new( - glyph, - outline, - ab_glyph::PxScaleFactor { - horizontal: metrics.px_scale_factor, - vertical: metrics.px_scale_factor, - }, - ); - let bb = outlined.px_bounds(); - let glyph_width = bb.width() as usize; - let glyph_height = bb.height() as usize; - if glyph_width == 0 || glyph_height == 0 { - UvRect::default() - } else { - let glyph_pos = { - let text_alpha_from_coverage = atlas.text_alpha_from_coverage; - let (glyph_pos, image) = atlas.allocate((glyph_width, glyph_height)); - outlined.draw(|x, y, v| { - if 0.0 < v { - let px = glyph_pos.0 + x as usize; - let py = glyph_pos.1 + y as usize; - image[(px, py)] = text_alpha_from_coverage.color_from_coverage(v); - } - }); - glyph_pos - }; - - let offset_in_pixels = vec2(bb.min.x, bb.min.y); - let offset = offset_in_pixels / metrics.pixels_per_point - + metrics.y_offset_in_points * Vec2::Y; - UvRect { - offset, - size: vec2(glyph_width as f32, glyph_height as f32) / metrics.pixels_per_point, - min: [glyph_pos.0 as u16, glyph_pos.1 as u16], - max: [ - (glyph_pos.0 + glyph_width) as u16, - (glyph_pos.1 + glyph_height) as u16, - ], - } - } - }); - let uv_rect = uv_rect.unwrap_or_default(); - - let allocation = GlyphAllocation { - id: glyph_id, - advance_width_px, - uv_rect, - }; entry.insert(allocation); (allocation, h_pos_round) } } // TODO(emilk): rename? -/// Wrapper over multiple [`FontImpl`] (e.g. a primary + fallbacks for emojis) +/// Wrapper over multiple [`FontFace`] (e.g. a primary + fallbacks for emojis) pub struct Font<'a> { - pub(super) fonts_by_id: &'a mut nohash_hasher::IntMap, + pub(super) fonts_by_id: &'a mut nohash_hasher::IntMap, pub(super) cached_family: &'a mut CachedFamily, pub(super) atlas: &'a mut TextureAtlas, } @@ -471,7 +627,7 @@ impl Font<'_> { .fonts .first() .and_then(|key| self.fonts_by_id.get(key)) - .map(|font_impl| font_impl.scaled_metrics(pixels_per_point, font_size)) + .map(|font_face| font_face.scaled_metrics(pixels_per_point, font_size)) .unwrap_or_default() } @@ -479,7 +635,7 @@ impl Font<'_> { pub fn glyph_width(&mut self, c: char, font_size: f32) -> f32 { let (key, glyph_info) = self.glyph_info(c); if let Some(font) = &self.fonts_by_id.get(&key) { - glyph_info.advance_width_unscaled.0 * font.ab_glyph_font.px_scale_factor(font_size) + glyph_info.advance_width_unscaled.0 * font.font.px_scale_factor(font_size) } else { 0.0 } @@ -524,7 +680,10 @@ pub struct ScaledMetrics { /// Translates "unscaled" units to physical (screen) pixels. pub px_scale_factor: f32, - /// Vertical offset, in UI points. + /// Absolute scale in screen pixels, for skrifa. + pub scale: f32, + + /// Vertical offset, in UI points (not screen-space). pub y_offset_in_points: f32, /// This is the distance from the top to the baseline. @@ -540,7 +699,7 @@ pub struct ScaledMetrics { /// Code points that will always be invisible (zero width). /// -/// See also [`FontImpl::ignore_character`]. +/// See also [`FontFace::ignore_character`]. #[inline] fn invisible_char(c: char) -> bool { if c == '\r' { diff --git a/crates/epaint/src/text/fonts.rs b/crates/epaint/src/text/fonts.rs index 6bc7ccf8f..a2c836d74 100644 --- a/crates/epaint/src/text/fonts.rs +++ b/crates/epaint/src/text/fonts.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Cow, collections::BTreeMap, sync::{ Arc, @@ -7,10 +8,10 @@ use std::{ }; use crate::{ - AlphaFromCoverage, TextureAtlas, + TextureAtlas, text::{ - Galley, LayoutJob, LayoutSection, - font::{Font, FontImpl, GlyphInfo}, + Galley, LayoutJob, LayoutSection, TextOptions, + font::{Font, FontFace, GlyphInfo}, }, }; use emath::{NumExt as _, OrderedFloat}; @@ -116,7 +117,7 @@ impl std::fmt::Display for FontFamily { #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct FontData { /// The content of a `.ttf` or `.otf` file. - pub font: std::borrow::Cow<'static, [u8]>, + pub font: Cow<'static, [u8]>, /// Which font face in the file to use. /// When in doubt, use `0`. @@ -129,7 +130,7 @@ pub struct FontData { impl FontData { pub fn from_static(font: &'static [u8]) -> Self { Self { - font: std::borrow::Cow::Borrowed(font), + font: Cow::Borrowed(font), index: 0, tweak: Default::default(), } @@ -137,7 +138,7 @@ impl FontData { pub fn from_owned(font: Vec) -> Self { Self { - font: std::borrow::Cow::Owned(font), + font: Cow::Owned(font), index: 0, tweak: Default::default(), } @@ -184,6 +185,11 @@ pub struct FontTweak { /// /// Example value: `2.0`. pub y_offset: f32, + + /// Override the global font hinting setting for this specific font. + /// + /// `None` means use the global setting. + pub hinting_override: Option, } impl Default for FontTweak { @@ -192,24 +198,20 @@ impl Default for FontTweak { scale: 1.0, y_offset_factor: 0.0, y_offset: 0.0, + hinting_override: None, } } } // ---------------------------------------------------------------------------- -fn ab_glyph_font_from_font_data(name: &str, data: &FontData) -> ab_glyph::FontArc { - match &data.font { - std::borrow::Cow::Borrowed(bytes) => { - ab_glyph::FontRef::try_from_slice_and_index(bytes, data.index) - .map(ab_glyph::FontArc::from) - } - std::borrow::Cow::Owned(bytes) => { - ab_glyph::FontVec::try_from_vec_and_index(bytes.clone(), data.index) - .map(ab_glyph::FontArc::from) - } +pub type Blob = Arc + Send + Sync>; + +fn blob_from_font_data(data: &FontData) -> Blob { + match data.clone().font { + Cow::Borrowed(bytes) => Arc::new(bytes) as Blob, + Cow::Owned(bytes) => Arc::new(bytes) as Blob, } - .unwrap_or_else(|err| panic!("Error parsing {name:?} TTF/OTF font file: {err}")) } /// Describes the font data and the sizes to use. @@ -438,7 +440,7 @@ pub(super) struct CachedFamily { impl CachedFamily { fn new( fonts: Vec, - fonts_by_id: &mut nohash_hasher::IntMap, + fonts_by_id: &mut nohash_hasher::IntMap, ) -> Self { if fonts.is_empty() { return Self { @@ -476,11 +478,11 @@ impl CachedFamily { pub(crate) fn glyph_info_no_cache_or_fallback( &mut self, c: char, - fonts_by_id: &mut nohash_hasher::IntMap, + fonts_by_id: &mut nohash_hasher::IntMap, ) -> Option<(FontFaceKey, GlyphInfo)> { for font_key in &self.fonts { - let font_impl = fonts_by_id.get_mut(font_key).expect("Nonexistent font ID"); - if let Some(glyph_info) = font_impl.glyph_info(c) { + let font_face = fonts_by_id.get_mut(font_key).expect("Nonexistent font ID"); + if let Some(glyph_info) = font_face.glyph_info(c) { self.glyph_info_cache.insert(c, (*font_key, glyph_info)); return Some((*font_key, glyph_info)); } @@ -508,43 +510,29 @@ pub struct Fonts { impl Fonts { /// Create a new [`Fonts`] for text layout. /// This call is expensive, so only create one [`Fonts`] and then reuse it. - /// - /// * `max_texture_side`: largest supported texture size (one side). - pub fn new( - max_texture_side: usize, - text_alpha_from_coverage: AlphaFromCoverage, - definitions: FontDefinitions, - ) -> Self { + pub fn new(options: TextOptions, definitions: FontDefinitions) -> Self { Self { - fonts: FontsImpl::new(max_texture_side, text_alpha_from_coverage, definitions), + fonts: FontsImpl::new(options, definitions), galley_cache: Default::default(), } } - /// Call at the start of each frame with the latest known - /// `pixels_per_point`, `max_texture_side`, and `text_alpha_from_coverage`. + /// Call at the start of each frame with the latest known [`TextOptions`]. /// /// Call after painting the previous frame, but before using [`Fonts`] for the new frame. /// - /// This function will react to changes in `pixels_per_point`, `max_texture_side`, and `text_alpha_from_coverage`, + /// This function will react to changes in [`TextOptions`], /// as well as notice when the font atlas is getting full, and handle that. - pub fn begin_pass( - &mut self, - max_texture_side: usize, - text_alpha_from_coverage: AlphaFromCoverage, - ) { - let max_texture_side_changed = self.fonts.max_texture_side != max_texture_side; - let text_alpha_from_coverage_changed = - self.fonts.atlas.text_alpha_from_coverage != text_alpha_from_coverage; + pub fn begin_pass(&mut self, options: TextOptions) { + let text_options_changed = self.fonts.options() != &options; let font_atlas_almost_full = self.fonts.atlas.fill_ratio() > 0.8; - let needs_recreate = - max_texture_side_changed || text_alpha_from_coverage_changed || font_atlas_almost_full; + let needs_recreate = text_options_changed || font_atlas_almost_full; if needs_recreate { let definitions = self.fonts.definitions.clone(); *self = Self { - fonts: FontsImpl::new(max_texture_side, text_alpha_from_coverage, definitions), + fonts: FontsImpl::new(options, definitions), galley_cache: Default::default(), }; } @@ -558,8 +546,8 @@ impl Fonts { } #[inline] - pub fn max_texture_side(&self) -> usize { - self.fonts.max_texture_side + pub fn options(&self) -> &TextOptions { + self.texture_atlas().options() } #[inline] @@ -628,8 +616,8 @@ pub struct FontsView<'a> { impl FontsView<'_> { #[inline] - pub fn max_texture_side(&self) -> usize { - self.fonts.max_texture_side + pub fn options(&self) -> &TextOptions { + self.fonts.options() } #[inline] @@ -671,6 +659,7 @@ impl FontsView<'_> { /// Height of one row of text in points. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. + #[inline] pub fn row_height(&mut self, font_id: &FontId) -> f32 { self.fonts .font(&font_id.family) @@ -716,6 +705,7 @@ impl FontsView<'_> { /// Will wrap text at the given width and line break at `\n`. /// /// The implementation uses memoization so repeated calls are cheap. + #[inline] pub fn layout( &mut self, text: String, @@ -730,6 +720,7 @@ impl FontsView<'_> { /// Will line break at `\n`. /// /// The implementation uses memoization so repeated calls are cheap. + #[inline] pub fn layout_no_wrap( &mut self, text: String, @@ -743,6 +734,7 @@ impl FontsView<'_> { /// Like [`Self::layout`], made for when you want to pick a color for the text later. /// /// The implementation uses memoization so repeated calls are cheap. + #[inline] pub fn layout_delayed_color( &mut self, text: String, @@ -759,10 +751,9 @@ impl FontsView<'_> { /// /// Required in order to paint text. pub struct FontsImpl { - max_texture_side: usize, definitions: FontDefinitions, atlas: TextureAtlas, - fonts_by_id: nohash_hasher::IntMap, + fonts_by_id: nohash_hasher::IntMap, fonts_by_name: ahash::HashMap, family_cache: ahash::HashMap, } @@ -770,36 +761,36 @@ pub struct FontsImpl { impl FontsImpl { /// Create a new [`FontsImpl`] for text layout. /// This call is expensive, so only create one [`FontsImpl`] and then reuse it. - pub fn new( - max_texture_side: usize, - text_alpha_from_coverage: AlphaFromCoverage, - definitions: FontDefinitions, - ) -> Self { - let texture_width = max_texture_side.at_most(16 * 1024); + pub fn new(options: TextOptions, definitions: FontDefinitions) -> Self { + let texture_width = options.max_texture_side.at_most(16 * 1024); let initial_height = 32; // Keep initial font atlas small, so it is fast to upload to GPU. This will expand as needed anyways. - let atlas = TextureAtlas::new([texture_width, initial_height], text_alpha_from_coverage); + let atlas = TextureAtlas::new([texture_width, initial_height], options); - let mut fonts_by_id: nohash_hasher::IntMap = Default::default(); - let mut font_impls: ahash::HashMap = Default::default(); + let mut fonts_by_id: nohash_hasher::IntMap = Default::default(); + let mut fonts_by_name: ahash::HashMap = Default::default(); for (name, font_data) in &definitions.font_data { let tweak = font_data.tweak; - let ab_glyph = ab_glyph_font_from_font_data(name, font_data); - let font_impl = FontImpl::new(name.clone(), ab_glyph, tweak); + let blob = blob_from_font_data(font_data); + let font_face = FontFace::new(options, name.clone(), blob, font_data.index, tweak) + .unwrap_or_else(|err| panic!("Error parsing {name:?} TTF/OTF font file: {err}")); let key = FontFaceKey::new(); - fonts_by_id.insert(key, font_impl); - font_impls.insert(name.clone(), key); + fonts_by_id.insert(key, font_face); + fonts_by_name.insert(name.clone(), key); } Self { - max_texture_side, definitions, atlas, fonts_by_id, - fonts_by_name: font_impls, + fonts_by_name, family_cache: Default::default(), } } + pub fn options(&self) -> &TextOptions { + self.atlas.options() + } + /// Get the right font implementation from [`FontFamily`]. pub fn font(&mut self, family: &FontFamily) -> Font<'_> { let cached_family = self.family_cache.entry(family.clone()).or_insert_with(|| { @@ -1192,12 +1183,7 @@ mod tests { #[test] fn test_split_paragraphs() { for pixels_per_point in [1.0, 2.0_f32.sqrt(), 2.0] { - let max_texture_side = 4096; - let mut fonts = FontsImpl::new( - max_texture_side, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); for halign in [Align::Min, Align::Center, Align::Max] { for justify in [false, true] { @@ -1255,11 +1241,7 @@ mod tests { let rounded_output_to_gui = [false, true]; for pixels_per_point in pixels_per_point { - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); for &max_width in &max_widths { for round_output_to_gui in rounded_output_to_gui { @@ -1306,7 +1288,7 @@ mod tests { #[test] fn test_fallback_glyph_width() { - let mut fonts = Fonts::new(1024, AlphaFromCoverage::default(), FontDefinitions::empty()); + let mut fonts = Fonts::new(TextOptions::default(), FontDefinitions::empty()); let mut view = fonts.with_pixels_per_point(1.0); let width = view.glyph_width(&FontId::new(12.0, FontFamily::Proportional), ' '); diff --git a/crates/epaint/src/text/mod.rs b/crates/epaint/src/text/mod.rs index e0f4a3a98..b40ba45b8 100644 --- a/crates/epaint/src/text/mod.rs +++ b/crates/epaint/src/text/mod.rs @@ -20,3 +20,31 @@ pub use { /// Suggested character to use to replace those in password text fields. pub const PASSWORD_REPLACEMENT_CHAR: char = '•'; + +/// Controls how we render text +#[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct TextOptions { + /// Maximum size of the font texture. + pub max_texture_side: usize, + + /// Controls how to convert glyph coverage to alpha. + pub alpha_from_coverage: crate::AlphaFromCoverage, + + /// Whether to enable font hinting + /// + /// (round some font coordinates to pixels for sharper text). + /// + /// Default is `true`. + pub font_hinting: bool, +} + +impl Default for TextOptions { + fn default() -> Self { + Self { + max_texture_side: 2048, // Small but portable + alpha_from_coverage: crate::AlphaFromCoverage::default(), + font_hinting: true, + } + } +} diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs index 1db56731d..2b1ab92b9 100644 --- a/crates/epaint/src/text/text_layout.rs +++ b/crates/epaint/src/text/text_layout.rs @@ -176,7 +176,7 @@ fn layout_section( // Optimization: only recompute `ScaledMetrics` when the concrete `FontImpl` changes. let mut current_font = FontFaceKey::INVALID; - let mut current_font_impl_metrics = ScaledMetrics::default(); + let mut current_font_face_metrics = ScaledMetrics::default(); for chr in job.text[byte_range.clone()].chars() { if job.break_on_newline && chr == '\n' { @@ -185,20 +185,20 @@ fn layout_section( paragraph.empty_paragraph_height = line_height; // TODO(emilk): replace this hack with actually including `\n` in the glyphs? } else { let (font_id, glyph_info) = font.glyph_info(chr); - let mut font_impl = font.fonts_by_id.get_mut(&font_id); + let mut font_face = font.fonts_by_id.get_mut(&font_id); if current_font != font_id { current_font = font_id; - current_font_impl_metrics = font_impl + current_font_face_metrics = font_face .as_ref() - .map(|font_impl| font_impl.scaled_metrics(pixels_per_point, font_size)) + .map(|font_face| font_face.scaled_metrics(pixels_per_point, font_size)) .unwrap_or_default(); } - if let (Some(font_impl), Some(last_glyph_id), Some(glyph_id)) = - (&font_impl, last_glyph_id, glyph_info.id) + if let (Some(font_face), Some(last_glyph_id), Some(glyph_id)) = + (&font_face, last_glyph_id, glyph_info.id) { - paragraph.cursor_x_px += font_impl.pair_kerning_pixels( - ¤t_font_impl_metrics, + paragraph.cursor_x_px += font_face.pair_kerning_pixels( + ¤t_font_face_metrics, last_glyph_id, glyph_id, ); @@ -207,10 +207,10 @@ fn layout_section( paragraph.cursor_x_px += extra_letter_spacing * pixels_per_point; } - let (glyph_alloc, physical_x) = if let Some(font_impl) = font_impl.as_mut() { - font_impl.allocate_glyph( + let (glyph_alloc, physical_x) = if let Some(font_face) = font_face.as_mut() { + font_face.allocate_glyph( font.atlas, - ¤t_font_impl_metrics, + ¤t_font_face_metrics, glyph_info, chr, paragraph.cursor_x_px, @@ -224,8 +224,8 @@ fn layout_section( pos: pos2(physical_x as f32 / pixels_per_point, f32::NAN), advance_width: glyph_alloc.advance_width_px / pixels_per_point, line_height, - font_impl_height: current_font_impl_metrics.row_height, - font_impl_ascent: current_font_impl_metrics.ascent, + font_face_height: current_font_face_metrics.row_height, + font_face_ascent: current_font_face_metrics.ascent, font_height: font_metrics.row_height, font_ascent: font_metrics.ascent, uv_rect: glyph_alloc.uv_rect, @@ -463,22 +463,22 @@ fn replace_last_glyph_with_overflow_character( let font_size = section.format.font_id.size; let (font_id, glyph_info) = font.glyph_info(overflow_character); - let mut font_impl = font.fonts_by_id.get_mut(&font_id); - let font_impl_metrics = font_impl + let mut font_face = font.fonts_by_id.get_mut(&font_id); + let font_face_metrics = font_face .as_mut() .map(|f| f.scaled_metrics(pixels_per_point, font_size)) .unwrap_or_default(); let overflow_glyph_x = if let Some(prev_glyph) = row.glyphs.last() { // Kern the overflow character properly - let pair_kerning = font_impl + let pair_kerning = font_face .as_mut() - .map(|font_impl| { + .map(|font_face| { if let (Some(prev_glyph_id), Some(overflow_glyph_id)) = ( - font_impl.glyph_info(prev_glyph.chr).and_then(|g| g.id), - font_impl.glyph_info(overflow_character).and_then(|g| g.id), + font_face.glyph_info(prev_glyph.chr).and_then(|g| g.id), + font_face.glyph_info(overflow_character).and_then(|g| g.id), ) { - font_impl.pair_kerning(&font_impl_metrics, prev_glyph_id, overflow_glyph_id) + font_face.pair_kerning(&font_face_metrics, prev_glyph_id, overflow_glyph_id) } else { 0.0 } @@ -490,10 +490,10 @@ fn replace_last_glyph_with_overflow_character( 0.0 // TODO(emilk): heed paragraph leading_space 😬 }; - let replacement_glyph_width = font_impl + let replacement_glyph_width = font_face .as_mut() .and_then(|f| f.glyph_info(overflow_character)) - .map(|i| i.advance_width_unscaled.0 * font_impl_metrics.px_scale_factor) + .map(|i| i.advance_width_unscaled.0 * font_face_metrics.px_scale_factor) .unwrap_or_default(); // Check if we're within width budget: @@ -502,12 +502,12 @@ fn replace_last_glyph_with_overflow_character( { // we are done - let (replacement_glyph_alloc, physical_x) = font_impl + let (replacement_glyph_alloc, physical_x) = font_face .as_mut() .map(|f| { f.allocate_glyph( font.atlas, - &font_impl_metrics, + &font_face_metrics, glyph_info, overflow_character, overflow_glyph_x * pixels_per_point, @@ -526,8 +526,8 @@ fn replace_last_glyph_with_overflow_character( pos: pos2(physical_x as f32 / pixels_per_point, f32::NAN), advance_width: replacement_glyph_alloc.advance_width_px / pixels_per_point, line_height, - font_impl_height: font_impl_metrics.row_height, - font_impl_ascent: font_impl_metrics.ascent, + font_face_height: font_face_metrics.row_height, + font_face_ascent: font_face_metrics.ascent, font_height: font_metrics.row_height, font_ascent: font_metrics.ascent, uv_rect: replacement_glyph_alloc.uv_rect, @@ -668,14 +668,14 @@ fn galley_from_rows( for glyph in &mut row.glyphs { let format = &job.sections[glyph.section_index as usize].format; - glyph.pos.y = glyph.font_impl_ascent + glyph.pos.y = glyph.font_face_ascent // Apply valign to the different in height of the entire row, and the height of this `Font`: + format.valign.to_factor() * (max_row_height - glyph.line_height) // When mixing different `FontImpl` (e.g. latin and emojis), // we always center the difference: - + 0.5 * (glyph.font_height - glyph.font_impl_height); + + 0.5 * (glyph.font_height - glyph.font_face_height); glyph.pos.y = point_scale.round_to_pixel(glyph.pos.y); } @@ -1050,18 +1050,13 @@ impl RowBreakCandidates { #[cfg(test)] mod tests { - use crate::AlphaFromCoverage; use super::{super::*, *}; #[test] fn test_zero_max_width() { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let mut layout_job = LayoutJob::single_section("W".into(), TextFormat::default()); layout_job.wrap.max_width = 0.0; let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); @@ -1074,11 +1069,7 @@ mod tests { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let text_format = TextFormat { font_id: FontId::monospace(12.0), ..Default::default() @@ -1124,11 +1115,7 @@ mod tests { #[test] fn test_cjk() { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let mut layout_job = LayoutJob::single_section( "日本語とEnglishの混在した文章".into(), TextFormat::default(), @@ -1144,11 +1131,7 @@ mod tests { #[test] fn test_pre_cjk() { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let mut layout_job = LayoutJob::single_section( "日本語とEnglishの混在した文章".into(), TextFormat::default(), @@ -1164,11 +1147,7 @@ mod tests { #[test] fn test_truncate_width() { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let mut layout_job = LayoutJob::single_section("# DNA\nMore text".into(), TextFormat::default()); layout_job.wrap.max_width = f32::INFINITY; @@ -1188,11 +1167,7 @@ mod tests { #[test] fn test_empty_row() { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let font_id = FontId::default(); let font_height = fonts @@ -1225,11 +1200,7 @@ mod tests { #[test] fn test_end_with_newline() { let pixels_per_point = 1.0; - let mut fonts = FontsImpl::new( - 1024, - AlphaFromCoverage::default(), - FontDefinitions::default(), - ); + let mut fonts = FontsImpl::new(TextOptions::default(), FontDefinitions::default()); let font_id = FontId::default(); let font_height = fonts diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index f3963394a..83a98ab05 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -686,11 +686,11 @@ pub struct Glyph { /// The row/line height of this font. pub font_height: f32, - /// The ascent of the sub-font within the font (`FontImpl`). - pub font_impl_ascent: f32, + /// The ascent of the sub-font within the font (`FontFace`). + pub font_face_ascent: f32, - /// The row/line height of the sub-font within the font (`FontImpl`). - pub font_impl_height: f32, + /// The row/line height of the sub-font within the font (`FontFace`). + pub font_face_height: f32, /// Position and size of the glyph in the font texture, in texels. pub uv_rect: UvRect, diff --git a/crates/epaint/src/texture_atlas.rs b/crates/epaint/src/texture_atlas.rs index 6488d9079..9a77c142a 100644 --- a/crates/epaint/src/texture_atlas.rs +++ b/crates/epaint/src/texture_atlas.rs @@ -1,7 +1,7 @@ use ecolor::Color32; use emath::{Rect, remap_clamp}; -use crate::{AlphaFromCoverage, ColorImage, ImageDelta}; +use crate::{ColorImage, ImageDelta, TextOptions}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] struct Rectu { @@ -75,11 +75,11 @@ pub struct TextureAtlas { discs: Vec, /// Controls how to convert glyph coverage to alpha. - pub(crate) text_alpha_from_coverage: AlphaFromCoverage, + options: TextOptions, } impl TextureAtlas { - pub fn new(size: [usize; 2], text_alpha_from_coverage: AlphaFromCoverage) -> Self { + pub fn new(size: [usize; 2], options: TextOptions) -> Self { assert!(size[0] >= 1024, "Tiny texture atlas"); let mut atlas = Self { image: ColorImage::filled(size, Color32::TRANSPARENT), @@ -88,7 +88,7 @@ impl TextureAtlas { row_height: 0, overflowed: false, discs: vec![], // will be filled in below - text_alpha_from_coverage, + options, }; // Make the top left pixel fully white for `WHITE_UV`, i.e. painting something with solid color: @@ -121,7 +121,7 @@ impl TextureAtlas { let coverage = remap_clamp(distance_to_center, (r - 0.5)..=(r + 0.5), 1.0..=0.0); image[((x as i32 + hw + dx) as usize, (y as i32 + hw + dy) as usize)] = - text_alpha_from_coverage.color_from_coverage(coverage); + options.alpha_from_coverage.color_from_coverage(coverage); } } atlas.discs.push(PrerasterizedDisc { @@ -138,6 +138,10 @@ impl TextureAtlas { atlas } + pub fn options(&self) -> &TextOptions { + &self.options + } + pub fn size(&self) -> [usize; 2] { self.image.size } diff --git a/deny.toml b/deny.toml index c7206ff26..1b3bd8b12 100644 --- a/deny.toml +++ b/deny.toml @@ -51,6 +51,7 @@ skip = [ { name = "core-foundation" }, # version conflict between winit and wgpu ecosystems { name = "core-graphics-types" }, # version conflict between winit and wgpu ecosystems { name = "getrandom" }, # ring / rustls (and thus ehttp) still depend on getrandom 0.2 + { name = "kurbo" }, # Old version because of resvg { name = "quick-xml" }, # old version via wayland-scanner { name = "redox_syscall" }, # old version via winit { name = "rustc-hash" }, # Small enough diff --git a/tests/egui_tests/tests/snapshots/button_shortcut.png b/tests/egui_tests/tests/snapshots/button_shortcut.png index 7f39196b8..de7d64b4d 100644 --- a/tests/egui_tests/tests/snapshots/button_shortcut.png +++ b/tests/egui_tests/tests/snapshots/button_shortcut.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5befd84158b582c79a968f36e43c7017187b364824eb4470b048d133e62f9360 -size 1600 +oid sha256:cbf68b6934dae0868bc9cf0891baf5acf110284d297cfa348e756237fca64a28 +size 1564 diff --git a/tests/egui_tests/tests/snapshots/grow_all.png b/tests/egui_tests/tests/snapshots/grow_all.png index 373889987..3e5208fe0 100644 --- a/tests/egui_tests/tests/snapshots/grow_all.png +++ b/tests/egui_tests/tests/snapshots/grow_all.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:469a1b1faa71da472c07bcc7103933db9964440a4c49dc596220f070e9b483f5 -size 14375 +oid sha256:2b91ae9e626d885b049d80dc9421275e147f4a3501c21ff4740b0f59d9c2998b +size 13930 diff --git a/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png b/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png index 038ce78db..672418f84 100644 --- a/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png +++ b/tests/egui_tests/tests/snapshots/hovering_should_preserve_text_format.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c83e094b1f0dede0195cc77f5caa3b7d13249364612b03c02f0ef5f2af5e28ad -size 12512 +oid sha256:3a5669c2c354c6ea42d8eaeb2eb39b65130a87807cbba8382dcc24d59790e794 +size 12181 diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_image.png b/tests/egui_tests/tests/snapshots/layout/atoms_image.png index bf98d3d2d..200ea6476 100644 --- a/tests/egui_tests/tests/snapshots/layout/atoms_image.png +++ b/tests/egui_tests/tests/snapshots/layout/atoms_image.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:070638cd5c174200161498123a612e4a58d58517b539e91e289d1e3dd38670bb -size 388531 +oid sha256:2e236f71e26e1a96acf9cd135b5db3a9cb0df374b87c3e283023dd14df193411 +size 369870 diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png b/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png index ae17dff6a..3c982b37e 100644 --- a/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png +++ b/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac8885d6e5325b5f1f0ccb11f185df5c4937b66c80159aa8cf53930f5c8045e2 -size 395599 +oid sha256:096ec8246969f85cfa0cb8d58731be9aaf82b7dac70dc064ec999b1eed25e1ef +size 368552 diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png b/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png index 97c181c70..664e23a9b 100644 --- a/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png +++ b/tests/egui_tests/tests/snapshots/layout/atoms_multi_grow.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05b891dd999050150f4cd4226a1c68673b352f04d08d405751d66c698c7711c5 -size 309736 +oid sha256:0813583ca9658b5f27f3585e59f829b71c86061619d7f61a16cc2ccf0906a322 +size 291213 diff --git a/tests/egui_tests/tests/snapshots/layout/button.png b/tests/egui_tests/tests/snapshots/layout/button.png index e53754f51..21449927d 100644 --- a/tests/egui_tests/tests/snapshots/layout/button.png +++ b/tests/egui_tests/tests/snapshots/layout/button.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6e8a7835e3fd22aafc22b6c536051367e2c27c8607fbe5d8b6b6cf6d0ba3d54f -size 332771 +oid sha256:e822c2324268d6e6168f9510aa1caec94df38dd0c163afcdecad11f2b1740936 +size 314449 diff --git a/tests/egui_tests/tests/snapshots/layout/button_image.png b/tests/egui_tests/tests/snapshots/layout/button_image.png index ece6568e9..4ee6cffa2 100644 --- a/tests/egui_tests/tests/snapshots/layout/button_image.png +++ b/tests/egui_tests/tests/snapshots/layout/button_image.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59cbb416865f8bede12b449d8e65baddb6949df017face2782a3492de7a058e3 -size 355276 +oid sha256:682dd89e15ee289a87a592c93ac2b9ec3172cd4fedcc02072c0516a9ae9ecd64 +size 335687 diff --git a/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png b/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png index 13f860b83..5b74267e1 100644 --- a/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png +++ b/tests/egui_tests/tests/snapshots/layout/button_image_shortcut.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cad07a16b6f0eb8c7647c7d0500ea99c68dddf2eef892b4df48aa20f581e8a85 -size 438837 +oid sha256:e2d22c9e7fd701be1dc1581635cdfa2829e02db9c6f66bf54eac106ebd7344a3 +size 421041 diff --git a/tests/egui_tests/tests/snapshots/layout/checkbox.png b/tests/egui_tests/tests/snapshots/layout/checkbox.png index 18ebbdb7c..c1e993885 100644 --- a/tests/egui_tests/tests/snapshots/layout/checkbox.png +++ b/tests/egui_tests/tests/snapshots/layout/checkbox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4747efdf758e7e8e2d7f3954d9595dfd45d3b4b86923b8ff39c8a96002bb4825 -size 408726 +oid sha256:ee91ad31d625930c55ae4ac41011f2018ef11ba20cefe5686b7338671fd6c32e +size 389522 diff --git a/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png b/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png index 127aa7f30..4b972d966 100644 --- a/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png +++ b/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a3ca4b3a47ff516f9b05799cdf5f92845ae1e058728d635986cc61b7317f110 -size 437102 +oid sha256:bcb5e0ec12a4bb7aba8ca8b53622fb2c204411ec66d7745bdb06e01bd1ffc731 +size 417596 diff --git a/tests/egui_tests/tests/snapshots/layout/drag_value.png b/tests/egui_tests/tests/snapshots/layout/drag_value.png index 471d3b867..44bf0bfcb 100644 --- a/tests/egui_tests/tests/snapshots/layout/drag_value.png +++ b/tests/egui_tests/tests/snapshots/layout/drag_value.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c168f197bec3bc780553db0a47f464f8d76afc606e28e2545ecd91f174abe551 -size 249781 +oid sha256:b2cd4d27748e193d4f46ad7a5be6ff411ad3152b4fd546c0dc98dd3bb5333d93 +size 236090 diff --git a/tests/egui_tests/tests/snapshots/layout/radio.png b/tests/egui_tests/tests/snapshots/layout/radio.png index 07e20176d..d3930768e 100644 --- a/tests/egui_tests/tests/snapshots/layout/radio.png +++ b/tests/egui_tests/tests/snapshots/layout/radio.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39f1985a3a975b1b9a179d3b1bd5832e0b4c30d10232babf2e4736f55b43989f -size 350051 +oid sha256:c15ece11f5c45d4bb89096a4d7146032e109fd9a099f2f37641e2676f7c3e184 +size 327971 diff --git a/tests/egui_tests/tests/snapshots/layout/radio_checked.png b/tests/egui_tests/tests/snapshots/layout/radio_checked.png index 2163011e6..c2d12eb98 100644 --- a/tests/egui_tests/tests/snapshots/layout/radio_checked.png +++ b/tests/egui_tests/tests/snapshots/layout/radio_checked.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:18a38fe66d5ac8f2cf5c109f1cd9c29951e5bf8428b6bf0d4587dfc8f8c5c890 -size 370205 +oid sha256:5942409a24177f84e067bcb488d8f976a0a6ad432f9f8603be2fdd4269d79efa +size 347946 diff --git a/tests/egui_tests/tests/snapshots/layout/selectable_value.png b/tests/egui_tests/tests/snapshots/layout/selectable_value.png index 2ee7f7d0e..e2ea0c1f4 100644 --- a/tests/egui_tests/tests/snapshots/layout/selectable_value.png +++ b/tests/egui_tests/tests/snapshots/layout/selectable_value.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfc900ea84b408564652df487e705311b164d9bd3ff5631c3cebb83b06497a7b -size 410131 +oid sha256:2c082417d4f65be1efc6c040d2acaf02d899ceaa547ba86f530e1d2e94f4e385 +size 389160 diff --git a/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png b/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png index 7e3dd6319..2a2553a30 100644 --- a/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png +++ b/tests/egui_tests/tests/snapshots/layout/selectable_value_selected.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c9d08ce85c9210a7d9046480ab208040e5ba399c40acaecf5cb43f807534bce9 -size 423523 +oid sha256:7edb1db196e1a6c740503d976f5f8e4dd9d3d4dd07e8391ce77f01f411cae315 +size 402030 diff --git a/tests/egui_tests/tests/snapshots/layout/slider.png b/tests/egui_tests/tests/snapshots/layout/slider.png index b8cc394c4..b7d9edcd5 100644 --- a/tests/egui_tests/tests/snapshots/layout/slider.png +++ b/tests/egui_tests/tests/snapshots/layout/slider.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b402195e54bdbd09985e4b30a025083298f29ab747b809fbb864c8dfef0975eb -size 289714 +oid sha256:e8bd1515d5c4045f4cd1b5d0c4f48469bd7e3ce738a95f741e9254e02ea28185 +size 276004 diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit.png b/tests/egui_tests/tests/snapshots/layout/text_edit.png index 8b53899dd..379b33806 100644 --- a/tests/egui_tests/tests/snapshots/layout/text_edit.png +++ b/tests/egui_tests/tests/snapshots/layout/text_edit.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ed6af3a92790e07b71e71637b5d6bb45d55a7d26738d438714aca64d7f4534c -size 245394 +oid sha256:61dde59ee92a1c22aba7fd8decf62d88d1ed81c10cd969ce65c451185f7ca58b +size 221618 diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png b/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png index 0c4327b58..ccc29355f 100644 --- a/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png +++ b/tests/egui_tests/tests/snapshots/layout/text_edit_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f107d95fee9a5fb5fbfd2422452e1820738a84c81774587dbfa8153e91e4c73 -size 414552 +oid sha256:c2a7ad1a4568f0ed7f203453697982603fad8b7e9852b4193216ebff1624671d +size 384210 diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png b/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png index ecc6efa8b..9ac2cefee 100644 --- a/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png +++ b/tests/egui_tests/tests/snapshots/layout/text_edit_no_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c1aebada9349f8cb4046469b0a6f9796a21f88b6724bd85cd832a40b8007409 -size 540527 +oid sha256:54a2f4004a71af18ffc42bba723a69855af4913ddedd8185688a59f9967e5a13 +size 509495 diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png b/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png index 780fec82f..e74e0f928 100644 --- a/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png +++ b/tests/egui_tests/tests/snapshots/layout/text_edit_placeholder_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:685de2e33ff26aafa87426bcda18bb9963c2deb2a811cd0aae4450af0e245a06 -size 390735 +oid sha256:2ab3a86f34c5cce033903cd67c1070dcc509e385e62e05358e1329968bfb1e95 +size 363693 diff --git a/tests/egui_tests/tests/snapshots/max_width.png b/tests/egui_tests/tests/snapshots/max_width.png index a10284911..6534961a8 100644 --- a/tests/egui_tests/tests/snapshots/max_width.png +++ b/tests/egui_tests/tests/snapshots/max_width.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9e2dc33b2d4caddac86dd8649d09ff3d57187a0152240f824a6aa170a35dd719 -size 8570 +oid sha256:ea5546e2e72aa5181edfe260cf5b506a30fea8c3db049c080bafc303223ba95f +size 8367 diff --git a/tests/egui_tests/tests/snapshots/max_width_and_grow.png b/tests/egui_tests/tests/snapshots/max_width_and_grow.png index b0d5c134f..54dddf7e8 100644 --- a/tests/egui_tests/tests/snapshots/max_width_and_grow.png +++ b/tests/egui_tests/tests/snapshots/max_width_and_grow.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36ab2c05eade94dcfe524651a0954c122aea754976af94a73a7efd950055c9eb -size 8574 +oid sha256:7d65a6c7e855a5476369422577d02f5e2a96814b100d7385f172fa9506189849 +size 8369 diff --git a/tests/egui_tests/tests/snapshots/shrink_first_text.png b/tests/egui_tests/tests/snapshots/shrink_first_text.png index 7bae217bb..81680a36a 100644 --- a/tests/egui_tests/tests/snapshots/shrink_first_text.png +++ b/tests/egui_tests/tests/snapshots/shrink_first_text.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2ba53264abcaa2ee79858ddbd475ed35aa28d146b846cbc080c26911d373ea6 -size 11881 +oid sha256:77ff29a1441d11f3b13ddaf5f6dd5f2c5781bc418887e1c2eabe00679958cba6 +size 11448 diff --git a/tests/egui_tests/tests/snapshots/shrink_last_text.png b/tests/egui_tests/tests/snapshots/shrink_last_text.png index 821490e52..6f7b28c16 100644 --- a/tests/egui_tests/tests/snapshots/shrink_last_text.png +++ b/tests/egui_tests/tests/snapshots/shrink_last_text.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:082d80ae144338dce45169c02038b6dc5b75d7b6d93c2a8213ddbb2a8784cc92 -size 12435 +oid sha256:23923d37e4dd848b043c7118e651ddade82c0df180652d8f0dcb829b1b6245d6 +size 12009 diff --git a/tests/egui_tests/tests/snapshots/sides/default_long.png b/tests/egui_tests/tests/snapshots/sides/default_long.png index 452ed723a..ae862c32d 100644 --- a/tests/egui_tests/tests/snapshots/sides/default_long.png +++ b/tests/egui_tests/tests/snapshots/sides/default_long.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e455b08f4674a9326682771f12456a71cc22dfd733ee965fdbbb5582cba0380 -size 8176 +oid sha256:9c970aab8c09558b806c81f57fc1d695992cb9f6e735a3fb2be75997c106a141 +size 8214 diff --git a/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png index ce5996d2f..842f41171 100644 --- a/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/default_long_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36600579bd2b5a9f255c9d843ccb76e74c622bc7d206962f52e3519e21dc2cfc -size 8963 +oid sha256:3afbf9e4d598907f088d3f09b1cf2b70c682062f1f4b98aa98b997121f763040 +size 8802 diff --git a/tests/egui_tests/tests/snapshots/sides/default_short.png b/tests/egui_tests/tests/snapshots/sides/default_short.png index 2d7ccae52..f19a5afbf 100644 --- a/tests/egui_tests/tests/snapshots/sides/default_short.png +++ b/tests/egui_tests/tests/snapshots/sides/default_short.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ad4ffb19388aeafd11891f487953525c335b0d10bceb455274df532582733c8 -size 1700 +oid sha256:da2b06feee78b808eab7ec4286b5050244b18b056f08dc49c417da8ff08bed0c +size 1637 diff --git a/tests/egui_tests/tests/snapshots/sides/default_short_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/default_short_fit_contents.png index 9c5635e19..099d55cb5 100644 --- a/tests/egui_tests/tests/snapshots/sides/default_short_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/default_short_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a2985caf40b9bacf9f18c84240181f84bea04cc413a009d5ca68c8d544ffa35 -size 1305 +oid sha256:a0a38c58ae7a30256e9491bfeb1155f2df6bba2a656ed9611fa945cbe2ebdc43 +size 1242 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png b/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png index cc17a1c48..ebf7424c3 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_left_long.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d36fb3c42b7f74e0b6dd8e73b9f8455e7fac035f5979cb93769e6a3f5453fdbc -size 7239 +oid sha256:46bca727290bb0fc5a9a28137385e7ee4821390d1594704ce5e0ea089f28dacf +size 7079 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png index ce5996d2f..842f41171 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_left_long_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36600579bd2b5a9f255c9d843ccb76e74c622bc7d206962f52e3519e21dc2cfc -size 8963 +oid sha256:3afbf9e4d598907f088d3f09b1cf2b70c682062f1f4b98aa98b997121f763040 +size 8802 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_left_short.png b/tests/egui_tests/tests/snapshots/sides/shrink_left_short.png index 2d7ccae52..f19a5afbf 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_left_short.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_left_short.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ad4ffb19388aeafd11891f487953525c335b0d10bceb455274df532582733c8 -size 1700 +oid sha256:da2b06feee78b808eab7ec4286b5050244b18b056f08dc49c417da8ff08bed0c +size 1637 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_left_short_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/shrink_left_short_fit_contents.png index 9c5635e19..099d55cb5 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_left_short_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_left_short_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a2985caf40b9bacf9f18c84240181f84bea04cc413a009d5ca68c8d544ffa35 -size 1305 +oid sha256:a0a38c58ae7a30256e9491bfeb1155f2df6bba2a656ed9611fa945cbe2ebdc43 +size 1242 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png b/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png index 03ca0a66e..d1cfeb533 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_right_long.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:89d9445d7aaff34ace5322af6efc308f261cf5becfdd11aa7fec016236ecfa84 -size 7064 +oid sha256:841f69878a4b9331f8ab4730d212384a82a9de14b9fba0d6964cd3010900132a +size 6939 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png index ce5996d2f..842f41171 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_right_long_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36600579bd2b5a9f255c9d843ccb76e74c622bc7d206962f52e3519e21dc2cfc -size 8963 +oid sha256:3afbf9e4d598907f088d3f09b1cf2b70c682062f1f4b98aa98b997121f763040 +size 8802 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_right_short.png b/tests/egui_tests/tests/snapshots/sides/shrink_right_short.png index 2d7ccae52..f19a5afbf 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_right_short.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_right_short.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ad4ffb19388aeafd11891f487953525c335b0d10bceb455274df532582733c8 -size 1700 +oid sha256:da2b06feee78b808eab7ec4286b5050244b18b056f08dc49c417da8ff08bed0c +size 1637 diff --git a/tests/egui_tests/tests/snapshots/sides/shrink_right_short_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/shrink_right_short_fit_contents.png index 9c5635e19..099d55cb5 100644 --- a/tests/egui_tests/tests/snapshots/sides/shrink_right_short_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/shrink_right_short_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a2985caf40b9bacf9f18c84240181f84bea04cc413a009d5ca68c8d544ffa35 -size 1305 +oid sha256:a0a38c58ae7a30256e9491bfeb1155f2df6bba2a656ed9611fa945cbe2ebdc43 +size 1242 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png b/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png index 48332d65b..be67eaf7a 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_left_long.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7487a1b77fd2db2493bca7d42128aad7a0049962599c8b5add2b7b25376a37d -size 9381 +oid sha256:602bc370e3929995c9b17415b513b412e0e12433f2c2b9120c58ea63c747ed79 +size 9184 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png index ce5996d2f..842f41171 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_left_long_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36600579bd2b5a9f255c9d843ccb76e74c622bc7d206962f52e3519e21dc2cfc -size 8963 +oid sha256:3afbf9e4d598907f088d3f09b1cf2b70c682062f1f4b98aa98b997121f763040 +size 8802 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_left_short.png b/tests/egui_tests/tests/snapshots/sides/wrap_left_short.png index 2d7ccae52..f19a5afbf 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_left_short.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_left_short.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ad4ffb19388aeafd11891f487953525c335b0d10bceb455274df532582733c8 -size 1700 +oid sha256:da2b06feee78b808eab7ec4286b5050244b18b056f08dc49c417da8ff08bed0c +size 1637 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_left_short_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/wrap_left_short_fit_contents.png index 9c5635e19..099d55cb5 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_left_short_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_left_short_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a2985caf40b9bacf9f18c84240181f84bea04cc413a009d5ca68c8d544ffa35 -size 1305 +oid sha256:a0a38c58ae7a30256e9491bfeb1155f2df6bba2a656ed9611fa945cbe2ebdc43 +size 1242 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png b/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png index fa65ff9db..cb31d61e1 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_right_long.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f614fb9b2aba8cc5a6997a519ca92083fb4378a36f335570d9e870159267f40 -size 9495 +oid sha256:b9165daef8acd038a1527192ded0b7cd5d03f235be737308ade467df33b6c8a0 +size 9192 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png index ce5996d2f..842f41171 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_right_long_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36600579bd2b5a9f255c9d843ccb76e74c622bc7d206962f52e3519e21dc2cfc -size 8963 +oid sha256:3afbf9e4d598907f088d3f09b1cf2b70c682062f1f4b98aa98b997121f763040 +size 8802 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_right_short.png b/tests/egui_tests/tests/snapshots/sides/wrap_right_short.png index 2d7ccae52..f19a5afbf 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_right_short.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_right_short.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ad4ffb19388aeafd11891f487953525c335b0d10bceb455274df532582733c8 -size 1700 +oid sha256:da2b06feee78b808eab7ec4286b5050244b18b056f08dc49c417da8ff08bed0c +size 1637 diff --git a/tests/egui_tests/tests/snapshots/sides/wrap_right_short_fit_contents.png b/tests/egui_tests/tests/snapshots/sides/wrap_right_short_fit_contents.png index 9c5635e19..099d55cb5 100644 --- a/tests/egui_tests/tests/snapshots/sides/wrap_right_short_fit_contents.png +++ b/tests/egui_tests/tests/snapshots/sides/wrap_right_short_fit_contents.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a2985caf40b9bacf9f18c84240181f84bea04cc413a009d5ca68c8d544ffa35 -size 1305 +oid sha256:a0a38c58ae7a30256e9491bfeb1155f2df6bba2a656ed9611fa945cbe2ebdc43 +size 1242 diff --git a/tests/egui_tests/tests/snapshots/size_max_size.png b/tests/egui_tests/tests/snapshots/size_max_size.png index 9c5ac8be3..12b526287 100644 --- a/tests/egui_tests/tests/snapshots/size_max_size.png +++ b/tests/egui_tests/tests/snapshots/size_max_size.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5230bd00a43990b30e523528b609e04916dab3cf87a59d56e39dcd5926f47aa5 -size 8838 +oid sha256:f2d9b0884adb89f598dd0c7eb421c0c8e8bcdaa1cbca02f4646c777711a005c2 +size 8655 diff --git a/tests/egui_tests/tests/snapshots/text_edit_rtl_0.png b/tests/egui_tests/tests/snapshots/text_edit_rtl_0.png index d93540222..af1b2dfb8 100644 --- a/tests/egui_tests/tests/snapshots/text_edit_rtl_0.png +++ b/tests/egui_tests/tests/snapshots/text_edit_rtl_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:336581facb1ec989a43291ed76bd8ddb552c46137a75601f466e6dc4dae77278 -size 2395 +oid sha256:1d1102bc84e5ea0b021c6674ca243e51f011cd9212991a245addf0459e045293 +size 2347 diff --git a/tests/egui_tests/tests/snapshots/text_edit_rtl_1.png b/tests/egui_tests/tests/snapshots/text_edit_rtl_1.png index 2ae957da9..ad94f8834 100644 --- a/tests/egui_tests/tests/snapshots/text_edit_rtl_1.png +++ b/tests/egui_tests/tests/snapshots/text_edit_rtl_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3b0684c53a20eaa90a9dccef8ac3eaa2a6eede7c770e7bbbba6d995f43584d99 -size 2353 +oid sha256:28b76c813a9eb7d4b49ffdc25fa63e208396489bd5547602b9df1eeb125b3b4a +size 2305 diff --git a/tests/egui_tests/tests/snapshots/text_edit_rtl_2.png b/tests/egui_tests/tests/snapshots/text_edit_rtl_2.png index b9235740d..a11a1d1b6 100644 --- a/tests/egui_tests/tests/snapshots/text_edit_rtl_2.png +++ b/tests/egui_tests/tests/snapshots/text_edit_rtl_2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38f325f2e741f18f897502c176f9a7efe276e9adab41a144511121dd8b8a3073 -size 3079 +oid sha256:4fdb8db17e3ec526c698812b9912555d1fa3837ba601fd9b39b6c7e9d451a070 +size 3007 diff --git a/tests/egui_tests/tests/snapshots/visuals/button.png b/tests/egui_tests/tests/snapshots/visuals/button.png index 4204dd1d3..0e2ff4cb0 100644 --- a/tests/egui_tests/tests/snapshots/visuals/button.png +++ b/tests/egui_tests/tests/snapshots/visuals/button.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6d0c3773bc3698fbd1bd1eb1aa1ed45938d5cb94696bfcec56e4e7e865871baf -size 11143 +oid sha256:863c60a3246d123b958f0ef8245999da23a9e4fadc942282a4231212b26246dd +size 10879 diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image.png b/tests/egui_tests/tests/snapshots/visuals/button_image.png index 5d1e74292..ee24faad9 100644 --- a/tests/egui_tests/tests/snapshots/visuals/button_image.png +++ b/tests/egui_tests/tests/snapshots/visuals/button_image.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9764ab5549e0775380b1db3c9a9a1d47c6520bcd5b8781f922e97e3524c362aa -size 12133 +oid sha256:a67a3272a3816120f0dc8857086f7c96352366823f6cebc85059abeced8c0cc2 +size 11972 diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png index b2f5646d3..e125622bc 100644 --- a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png +++ b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4d0c7d4b161f7a1f9cadb3e285edcd08588b9e47e10c5579183c824ae4e7be1b -size 15170 +oid sha256:1aa2bfe30e56a7f86145007989fafbc13271cc8268c876c51826d92683125b1a +size 14763 diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png index 3f20c4379..b577739cd 100644 --- a/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png +++ b/tests/egui_tests/tests/snapshots/visuals/button_image_shortcut_selected.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:65359fcb0f01627876e697684b185c60812dd1591b0f42174673712939e2f193 -size 14852 +oid sha256:f3379de9b9c49f6d930203b1bfb1b64951ec78bd712d12dd31ca8a01f5e6b69b +size 14370 diff --git a/tests/egui_tests/tests/snapshots/visuals/checkbox.png b/tests/egui_tests/tests/snapshots/visuals/checkbox.png index 2145ceee7..5c170014f 100644 --- a/tests/egui_tests/tests/snapshots/visuals/checkbox.png +++ b/tests/egui_tests/tests/snapshots/visuals/checkbox.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68347d7eb452a6f30fa93778f9ebd17f20c1425426472d3ebe4c8b55fc0ba8ea -size 13774 +oid sha256:9f1a6442ac27ddb872d9236f6e9041e1552d73926d20ef43a6ad9f2be911cf19 +size 13500 diff --git a/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png b/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png index ec012113b..d60d26c74 100644 --- a/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png +++ b/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c323b3b530be2c4ff195e369e86df49ef28de0696fb33a74361d9dbd95e37ae -size 14889 +oid sha256:6a475763dd3c18e2d027016906e02e5127515bcf89085eb0621022b980278424 +size 14599 diff --git a/tests/egui_tests/tests/snapshots/visuals/drag_value.png b/tests/egui_tests/tests/snapshots/visuals/drag_value.png index 05f63136b..de70c841c 100644 --- a/tests/egui_tests/tests/snapshots/visuals/drag_value.png +++ b/tests/egui_tests/tests/snapshots/visuals/drag_value.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8a48d2014ed6295d61f3200389315662b89e7efba27a93fded255cce7bd21e05 -size 8675 +oid sha256:5ca946ae1875730db15a7e525d2edfab4b55d9a07ad72998c565ce0c7c9bea90 +size 8400 diff --git a/tests/egui_tests/tests/snapshots/visuals/radio.png b/tests/egui_tests/tests/snapshots/visuals/radio.png index 298841d6a..d36c5759f 100644 --- a/tests/egui_tests/tests/snapshots/visuals/radio.png +++ b/tests/egui_tests/tests/snapshots/visuals/radio.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cdaeee74db8c9527e6656b4a3026ed18cb58c4761f1155768a456d6d58dc79e2 -size 12549 +oid sha256:8556c997810eeafc522710365914bca9aefec1362860086e69b2182820444b20 +size 12192 diff --git a/tests/egui_tests/tests/snapshots/visuals/radio_checked.png b/tests/egui_tests/tests/snapshots/visuals/radio_checked.png index 02590ce3d..ba382e20f 100644 --- a/tests/egui_tests/tests/snapshots/visuals/radio_checked.png +++ b/tests/egui_tests/tests/snapshots/visuals/radio_checked.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dfbfd35264e4d35a594c72ef0fb9575b090301e112a98228d3070fa85aa4e42 -size 13240 +oid sha256:5a44028c96d97b68cb2ab44d9d52ec7a8c353d8d11022967c345b2536dc4e5c7 +size 12890 diff --git a/tests/egui_tests/tests/snapshots/visuals/selectable_value.png b/tests/egui_tests/tests/snapshots/visuals/selectable_value.png index 85cb2a451..2a27d8941 100644 --- a/tests/egui_tests/tests/snapshots/visuals/selectable_value.png +++ b/tests/egui_tests/tests/snapshots/visuals/selectable_value.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cbaa88e2769bd9dbffa9b3ced36585c00b4ad6ca91ae61a6becc63a495a812fc -size 14116 +oid sha256:7d4aa6f3a30fa438667b7d63d3b25bb0d478bc1284f87f002f6727d8dfd5a33e +size 13923 diff --git a/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png b/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png index 8f0cfb4a9..31d5bc95f 100644 --- a/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png +++ b/tests/egui_tests/tests/snapshots/visuals/selectable_value_selected.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1bac7bec0c22e9530ef2428c4233be7a1c3554c653b6344a2d7b981c5455920 -size 14142 +oid sha256:0e5a20f72effd38e26dfe8ffd9e1d484bf1000340191eb7ef6188a082f4ee6f1 +size 13929 diff --git a/tests/egui_tests/tests/snapshots/visuals/slider.png b/tests/egui_tests/tests/snapshots/visuals/slider.png index fd9b15b73..61418cede 100644 --- a/tests/egui_tests/tests/snapshots/visuals/slider.png +++ b/tests/egui_tests/tests/snapshots/visuals/slider.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3667467ff1cf2ce210ec1e1555b40bba827008c5ee40d25ccaf082d2718c6d77 -size 10144 +oid sha256:cc69a14376d18201885502575595bfe61c06a6917074892d72aa9189e57d327c +size 9965 diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit.png b/tests/egui_tests/tests/snapshots/visuals/text_edit.png index 649a05fc4..177043578 100644 --- a/tests/egui_tests/tests/snapshots/visuals/text_edit.png +++ b/tests/egui_tests/tests/snapshots/visuals/text_edit.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d06b03948190e2d6408c339b97ec3f3e2104ffc7da61f5935b7df8bb89c9d7aa -size 8813 +oid sha256:3b322265006cd8e5ef6dfddafb38c8a47714d084402bd2fbc9bc80b4ff10e8e7 +size 8214 diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png index 70c4bfe8f..049341e46 100644 --- a/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png +++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2be8ebcc7d8cc7b3824ae27c57969c0d1bc2d5affb8f3f9df687fb3d1860280 -size 11567 +oid sha256:65cf9db0c073eae5a484058bd26f41d89da949bdca3144ec73aa21878e248923 +size 11011 diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png index a5bda4b8f..8864dca70 100644 --- a/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png +++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_no_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:934263e4413e48ea3abf8b53e213f3a61459b697b30cf05436e2d2e6a3d48e3c -size 22356 +oid sha256:188be46ed22526b36620539c802bf7b4a116b574eb790d1c3ff18058fe37b807 +size 21534 diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png b/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png index e49bb4414..7190703ba 100644 --- a/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png +++ b/tests/egui_tests/tests/snapshots/visuals/text_edit_placeholder_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb3230e609246415501d89984bb59ee1dad1241b8054009e7a5108efe3965904 -size 10880 +oid sha256:afeb3a0de414de4e5ab00ecb9eb7e3e69ed0dc85b5e419a796c3e7159d6da3de +size 10360 From 6277a310b93f2f07834e920baabe43409334c973 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sun, 7 Dec 2025 08:33:51 +0000 Subject: [PATCH 11/26] Disable the Skrifa traversal feature (#7758) - Followup to https://github.com/emilk/egui/pull/7694 - Disables the `traversal` feature of `skrifa` which is not needed except internally by the fontations project - Should save a little compile time, and possibly some binary size. Signed-off-by: Nico Burns --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b1822d58a..5650152cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,7 +124,7 @@ ron = "0.11.0" self_cell = "1.2.1" serde = { version = "1.0.228", features = ["derive"] } similar-asserts = "1.7.0" -skrifa = "0.37.0" +skrifa = { version = "0.37.0", default-features = false, features = ["std", "autohint_shaping"] } smallvec = "1.15.1" smithay-clipboard = "0.7.2" static_assertions = "1.1.0" From 2115ca941be9ca52e70468ec7638d62fd1da6adf Mon Sep 17 00:00:00 2001 From: switch Date: Sun, 7 Dec 2025 23:34:26 +0100 Subject: [PATCH 12/26] egui-wgpu: attach stencil buffer (#7702) --- crates/eframe/src/web/web_painter_wgpu.rs | 27 +++++++++++++++------ crates/egui-wgpu/src/winit.rs | 29 +++++++++++++++++------ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/crates/eframe/src/web/web_painter_wgpu.rs b/crates/eframe/src/web/web_painter_wgpu.rs index efecd12ee..387366e5a 100644 --- a/crates/eframe/src/web/web_painter_wgpu.rs +++ b/crates/eframe/src/web/web_painter_wgpu.rs @@ -243,13 +243,26 @@ impl WebPainter for WebPainterWgpu { depth_stencil_attachment: self.depth_texture_view.as_ref().map(|view| { wgpu::RenderPassDepthStencilAttachment { view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - // It is very unlikely that the depth buffer is needed after egui finished rendering - // so no need to store it. (this can improve performance on tiling GPUs like mobile chips or Apple Silicon) - store: wgpu::StoreOp::Discard, - }), - stencil_ops: None, + depth_ops: self + .depth_stencil_format + .is_some_and(|depth_stencil_format| { + depth_stencil_format.has_depth_aspect() + }) + .then_some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + // It is very unlikely that the depth buffer is needed after egui finished rendering + // so no need to store it. (this can improve performance on tiling GPUs like mobile chips or Apple Silicon) + store: wgpu::StoreOp::Discard, + }), + stencil_ops: self + .depth_stencil_format + .is_some_and(|depth_stencil_format| { + depth_stencil_format.has_stencil_aspect() + }) + .then_some(wgpu::Operations { + load: wgpu::LoadOp::Clear(0), + store: wgpu::StoreOp::Discard, + }), } }), label: Some("egui_render"), diff --git a/crates/egui-wgpu/src/winit.rs b/crates/egui-wgpu/src/winit.rs index 3a286cc9e..a35466493 100644 --- a/crates/egui-wgpu/src/winit.rs +++ b/crates/egui-wgpu/src/winit.rs @@ -526,13 +526,28 @@ impl Painter { depth_stencil_attachment: self.depth_texture_view.get(&viewport_id).map(|view| { wgpu::RenderPassDepthStencilAttachment { view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - // It is very unlikely that the depth buffer is needed after egui finished rendering - // so no need to store it. (this can improve performance on tiling GPUs like mobile chips or Apple Silicon) - store: wgpu::StoreOp::Discard, - }), - stencil_ops: None, + depth_ops: self + .options + .depth_stencil_format + .is_some_and(|depth_stencil_format| { + depth_stencil_format.has_depth_aspect() + }) + .then_some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + // It is very unlikely that the depth buffer is needed after egui finished rendering + // so no need to store it. (this can improve performance on tiling GPUs like mobile chips or Apple Silicon) + store: wgpu::StoreOp::Discard, + }), + stencil_ops: self + .options + .depth_stencil_format + .is_some_and(|depth_stencil_format| { + depth_stencil_format.has_stencil_aspect() + }) + .then_some(wgpu::Operations { + load: wgpu::LoadOp::Clear(0), + store: wgpu::StoreOp::Discard, + }), } }), timestamp_writes: None, From a0bb4cfef82dd9b50f990f607b7c7c4f28eb8589 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Thu, 11 Dec 2025 15:34:47 +0100 Subject: [PATCH 13/26] Release 0.33.3: update cargo version and changelog --- CHANGELOG.md | 5 ++++ Cargo.lock | 32 ++++++++++++------------ Cargo.toml | 26 +++++++++---------- crates/ecolor/CHANGELOG.md | 4 +++ crates/eframe/CHANGELOG.md | 4 +++ crates/egui-wgpu/CHANGELOG.md | 4 +++ crates/egui-winit/CHANGELOG.md | 4 +++ crates/egui_extras/CHANGELOG.md | 4 +++ crates/egui_glow/CHANGELOG.md | 4 +++ crates/egui_kittest/CHANGELOG.md | 5 ++++ crates/emath/CHANGELOG.md | 4 +++ crates/epaint/CHANGELOG.md | 4 +++ crates/epaint_default_fonts/CHANGELOG.md | 4 +++ 13 files changed, 75 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 856fe09da..12010e287 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +* Treat `.` as a word-splitter in text navigation [#7741](https://github.com/emilk/egui/pull/7741) by [@emilk](https://github.com/emilk) +* Change text color of selected text [#7691](https://github.com/emilk/egui/pull/7691) by [@emilk](https://github.com/emilk) + + ## 0.33.2 - 2025-11-13 ### ⭐ Added * Add `Plugin::on_widget_under_pointer` to support widget inspector [#7652](https://github.com/emilk/egui/pull/7652) by [@juancampa](https://github.com/juancampa) diff --git a/Cargo.lock b/Cargo.lock index f75e31381..a99c0d281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1257,7 +1257,7 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] name = "ecolor" -version = "0.33.2" +version = "0.33.3" dependencies = [ "bytemuck", "cint", @@ -1269,7 +1269,7 @@ dependencies = [ [[package]] name = "eframe" -version = "0.33.2" +version = "0.33.3" dependencies = [ "ahash", "bytemuck", @@ -1308,7 +1308,7 @@ dependencies = [ [[package]] name = "egui" -version = "0.33.2" +version = "0.33.3" dependencies = [ "accesskit", "ahash", @@ -1328,7 +1328,7 @@ dependencies = [ [[package]] name = "egui-wgpu" -version = "0.33.2" +version = "0.33.3" dependencies = [ "ahash", "bytemuck", @@ -1346,7 +1346,7 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.33.2" +version = "0.33.3" dependencies = [ "accesskit_winit", "arboard", @@ -1369,7 +1369,7 @@ dependencies = [ [[package]] name = "egui_demo_app" -version = "0.33.2" +version = "0.33.3" dependencies = [ "accesskit", "accesskit_consumer", @@ -1399,7 +1399,7 @@ dependencies = [ [[package]] name = "egui_demo_lib" -version = "0.33.2" +version = "0.33.3" dependencies = [ "chrono", "criterion", @@ -1416,7 +1416,7 @@ dependencies = [ [[package]] name = "egui_extras" -version = "0.33.2" +version = "0.33.3" dependencies = [ "ahash", "chrono", @@ -1435,7 +1435,7 @@ dependencies = [ [[package]] name = "egui_glow" -version = "0.33.2" +version = "0.33.3" dependencies = [ "bytemuck", "document-features", @@ -1454,7 +1454,7 @@ dependencies = [ [[package]] name = "egui_kittest" -version = "0.33.2" +version = "0.33.3" dependencies = [ "dify", "document-features", @@ -1474,7 +1474,7 @@ dependencies = [ [[package]] name = "egui_tests" -version = "0.33.2" +version = "0.33.3" dependencies = [ "egui", "egui_extras", @@ -1504,7 +1504,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "emath" -version = "0.33.2" +version = "0.33.3" dependencies = [ "bytemuck", "document-features", @@ -1602,7 +1602,7 @@ dependencies = [ [[package]] name = "epaint" -version = "0.33.2" +version = "0.33.3" dependencies = [ "ahash", "bytemuck", @@ -1626,7 +1626,7 @@ dependencies = [ [[package]] name = "epaint_default_fonts" -version = "0.33.2" +version = "0.33.3" [[package]] name = "equivalent" @@ -3495,7 +3495,7 @@ checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" [[package]] name = "popups" -version = "0.33.2" +version = "0.33.3" dependencies = [ "eframe", "env_logger", @@ -5894,7 +5894,7 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" [[package]] name = "xtask" -version = "0.33.2" +version = "0.33.3" [[package]] name = "yaml-rust" diff --git a/Cargo.toml b/Cargo.toml index 5650152cc..b291cb36c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ members = [ edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.88" -version = "0.33.2" +version = "0.33.3" [profile.release] @@ -55,18 +55,18 @@ opt-level = 2 [workspace.dependencies] -emath = { version = "0.33.2", path = "crates/emath", default-features = false } -ecolor = { version = "0.33.2", path = "crates/ecolor", default-features = false } -epaint = { version = "0.33.2", path = "crates/epaint", default-features = false } -epaint_default_fonts = { version = "0.33.2", path = "crates/epaint_default_fonts" } -egui = { version = "0.33.2", path = "crates/egui", default-features = false } -egui-winit = { version = "0.33.2", path = "crates/egui-winit", default-features = false } -egui_extras = { version = "0.33.2", path = "crates/egui_extras", default-features = false } -egui-wgpu = { version = "0.33.2", path = "crates/egui-wgpu", default-features = false } -egui_demo_lib = { version = "0.33.2", path = "crates/egui_demo_lib", default-features = false } -egui_glow = { version = "0.33.2", path = "crates/egui_glow", default-features = false } -egui_kittest = { version = "0.33.2", path = "crates/egui_kittest", default-features = false } -eframe = { version = "0.33.2", path = "crates/eframe", default-features = false } +emath = { version = "0.33.3", path = "crates/emath", default-features = false } +ecolor = { version = "0.33.3", path = "crates/ecolor", default-features = false } +epaint = { version = "0.33.3", path = "crates/epaint", default-features = false } +epaint_default_fonts = { version = "0.33.3", path = "crates/epaint_default_fonts" } +egui = { version = "0.33.3", path = "crates/egui", default-features = false } +egui-winit = { version = "0.33.3", path = "crates/egui-winit", default-features = false } +egui_extras = { version = "0.33.3", path = "crates/egui_extras", default-features = false } +egui-wgpu = { version = "0.33.3", path = "crates/egui-wgpu", default-features = false } +egui_demo_lib = { version = "0.33.3", path = "crates/egui_demo_lib", default-features = false } +egui_glow = { version = "0.33.3", path = "crates/egui_glow", default-features = false } +egui_kittest = { version = "0.33.3", path = "crates/egui_kittest", default-features = false } +eframe = { version = "0.33.3", path = "crates/eframe", default-features = false } accesskit = "0.21.1" accesskit_consumer = "0.30.1" diff --git a/crates/ecolor/CHANGELOG.md b/crates/ecolor/CHANGELOG.md index 4dee81296..a4fe1f3de 100644 --- a/crates/ecolor/CHANGELOG.md +++ b/crates/ecolor/CHANGELOG.md @@ -6,6 +6,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 Nothing new diff --git a/crates/eframe/CHANGELOG.md b/crates/eframe/CHANGELOG.md index 11f1c8fc9..74a705251 100644 --- a/crates/eframe/CHANGELOG.md +++ b/crates/eframe/CHANGELOG.md @@ -7,6 +7,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 * Fix jittering during window resize on MacOS for WGPU/Metal [#7641](https://github.com/emilk/egui/pull/7641) by [@aspcartman](https://github.com/aspcartman) * Make sure `native_pixels_per_point` is set during app creation [#7683](https://github.com/emilk/egui/pull/7683) by [@emilk](https://github.com/emilk) diff --git a/crates/egui-wgpu/CHANGELOG.md b/crates/egui-wgpu/CHANGELOG.md index be00dd049..cef640184 100644 --- a/crates/egui-wgpu/CHANGELOG.md +++ b/crates/egui-wgpu/CHANGELOG.md @@ -6,6 +6,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 * Fix jittering during window resize on MacOS for WGPU/Metal [#7641](https://github.com/emilk/egui/pull/7641) by [@aspcartman](https://github.com/aspcartman) diff --git a/crates/egui-winit/CHANGELOG.md b/crates/egui-winit/CHANGELOG.md index 8e555a7bc..f88a8c84a 100644 --- a/crates/egui-winit/CHANGELOG.md +++ b/crates/egui-winit/CHANGELOG.md @@ -5,6 +5,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 * Don't enable `arboard` on iOS [#7663](https://github.com/emilk/egui/pull/7663) by [@irh](https://github.com/irh) diff --git a/crates/egui_extras/CHANGELOG.md b/crates/egui_extras/CHANGELOG.md index 9dbeb5879..15eaf8704 100644 --- a/crates/egui_extras/CHANGELOG.md +++ b/crates/egui_extras/CHANGELOG.md @@ -5,6 +5,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +* Bump `ehttp` to 0.6.0 [#7757](https://github.com/emilk/egui/pull/7757) by [@jprochazk](https://github.com/jprochazk) + + ## 0.33.2 - 2025-11-13 Nothing new diff --git a/crates/egui_glow/CHANGELOG.md b/crates/egui_glow/CHANGELOG.md index 4dd90a359..2fccf1166 100644 --- a/crates/egui_glow/CHANGELOG.md +++ b/crates/egui_glow/CHANGELOG.md @@ -6,6 +6,10 @@ Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +* Enforce consistent snapshot updates [#7744](https://github.com/emilk/egui/pull/7744) by [@lucasmerlin](https://github.com/lucasmerlin) +* `kittest`: add drag-and-drop helpers [#7690](https://github.com/emilk/egui/pull/7690) by [@emilk](https://github.com/emilk) + + ## 0.33.2 - 2025-11-13 Nothing new diff --git a/crates/emath/CHANGELOG.md b/crates/emath/CHANGELOG.md index 334af345f..f559265c4 100644 --- a/crates/emath/CHANGELOG.md +++ b/crates/emath/CHANGELOG.md @@ -6,6 +6,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 * Fix edge cases in "smart aiming" in sliders [#7680](https://github.com/emilk/egui/pull/7680) by [@emilk](https://github.com/emilk) diff --git a/crates/epaint/CHANGELOG.md b/crates/epaint/CHANGELOG.md index b23c454b4..dd6b4e2a5 100644 --- a/crates/epaint/CHANGELOG.md +++ b/crates/epaint/CHANGELOG.md @@ -5,6 +5,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 Nothing new diff --git a/crates/epaint_default_fonts/CHANGELOG.md b/crates/epaint_default_fonts/CHANGELOG.md index 3f131cb55..58fd310f4 100644 --- a/crates/epaint_default_fonts/CHANGELOG.md +++ b/crates/epaint_default_fonts/CHANGELOG.md @@ -5,6 +5,10 @@ This file is updated upon each release. Changes since the last release can be found at or by running the `scripts/generate_changelog.py` script. +## 0.33.3 - 2025-12-11 +Nothing new + + ## 0.33.2 - 2025-11-13 Nothing new From 06e632535b4fe6a6d710239f268d6384cf310696 Mon Sep 17 00:00:00 2001 From: Johnchoi913 Date: Sun, 14 Dec 2025 09:23:41 -0500 Subject: [PATCH 14/26] Enable feature for example custom_3d_glow (#7730) * Small fix, no issue opened * [x] I have followed the instructions in the PR template --- examples/custom_3d_glow/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/custom_3d_glow/Cargo.toml b/examples/custom_3d_glow/Cargo.toml index 8636b0f43..1aaca8a43 100644 --- a/examples/custom_3d_glow/Cargo.toml +++ b/examples/custom_3d_glow/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] eframe = { workspace = true, features = [ "default", + "glow", "__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO ] } env_logger = { workspace = true, features = ["auto-color", "humantime"] } From 8ef7f10367ecdca0e0938394ff217d3bf9f2ef0e Mon Sep 17 00:00:00 2001 From: Justin Symonds Date: Sun, 14 Dec 2025 06:24:08 -0800 Subject: [PATCH 15/26] Fixes for doc comments (#7668) * [x] I have followed the instructions in the PR template - Some typos/grammos - Attempt to finish incomplete comment - Broken link - I understand the colon is a convention for pluralizing symbol names, but it seems redundant in the presence of other punctuation --------- Co-authored-by: Lucas Meurer --- crates/egui/src/context.rs | 8 ++++---- crates/egui/src/lib.rs | 2 +- crates/egui/src/memory/mod.rs | 2 +- crates/egui/src/ui.rs | 20 ++++++++++---------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 988226e2c..ad329e7fb 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2880,7 +2880,7 @@ impl Context { self.input(|i| i.pointer.hover_pos()) } - /// If you detect a click or drag and wants to know where it happened, use this. + /// If you detect a click or drag and want to know where it happened, use this. /// /// Latest position of the mouse, but ignoring any [`crate::Event::PointerGone`] /// if there were interactions this pass. @@ -2953,7 +2953,7 @@ impl Context { /// Moves the given area to the top in its [`Order`]. /// - /// [`crate::Area`]:s and [`crate::Window`]:s also do this automatically when being clicked on or interacted with. + /// [`crate::Area`]s and [`crate::Window`]s also do this automatically when being clicked on or interacted with. pub fn move_to_top(&self, layer_id: LayerId) { self.memory_mut(|mem| mem.areas_mut().move_to_top(layer_id)); } @@ -3072,7 +3072,7 @@ impl Context { /// for a responsive start and a slow end. /// /// The easing function flips when `target_value` is `false`, - /// so that when going back towards 0.0, we get + /// so that when going back towards 0.0, we get the reverse behavior. #[track_caller] // To track repaint cause pub fn animate_bool_with_time_and_easing( &self, @@ -3953,7 +3953,7 @@ impl Context { /// Show an immediate viewport, creating a new native window, if possible. /// /// This is the easier type of viewport to use, but it is less performant - /// at it requires both parent and child to repaint if any one of them needs repainting, + /// as it requires both parent and child to repaint if any one of them needs repainting, /// which effectively produce double work for two viewports, and triple work for three viewports, etc. /// To avoid this, use [`Self::show_viewport_deferred`] instead. /// diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index d756caf75..c39f254a2 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -195,7 +195,7 @@ //! * lays out the letters `click me` in order to figure out the size of the button //! * decides where on screen to place the button //! * check if the mouse is hovering or clicking that location -//! * chose button colors based on if it is being hovered or clicked +//! * choose button colors based on if it is being hovered or clicked //! * add a [`Shape::Rect`] and [`Shape::Text`] to the list of shapes to be painted later this frame //! * return a [`Response`] with the [`clicked`](`Response::clicked`) member so the user can check for interactions //! diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index d215a3bec..77a18dc04 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -21,7 +21,7 @@ pub use theme::{Theme, ThemePreference}; /// how far the user has scrolled in a [`ScrollArea`](crate::ScrollArea) etc. /// /// If you want this to persist when closing your app, you should serialize [`Memory`] and store it. -/// For this you need to enable the `persistence`. +/// For this you need to enable the `persistence` feature. /// /// If you want to store data for your widgets, you should look at [`Memory::data`] #[derive(Clone, Debug)] diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index d230ed736..228f2beaf 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -74,14 +74,14 @@ pub struct Ui { /// This value is based on where in the hierarchy of widgets this Ui is in, /// and the value is increment with each added child widget. /// This works as an Id source only as long as new widgets aren't added or removed. - /// They are therefore only good for Id:s that has no state. + /// They are therefore only good for Id:s that have no state. next_auto_id_salt: u64, /// Specifies paint layer, clip rectangle and a reference to [`Context`]. painter: Painter, /// The [`Style`] (visuals, spacing, etc) of this ui. - /// Commonly many [`Ui`]:s share the same [`Style`]. + /// Commonly many [`Ui`]s share the same [`Style`]. /// The [`Ui`] implements copy-on-write for this. style: Arc