diff --git a/Cargo.lock b/Cargo.lock index 819c18bc..eec56131 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "e074464580a518d16a7126262fffaaa47af89d4099d4cb403f8ed938ba12ee7d" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", diff --git a/crates/egui/src/atomics/atom_ext.rs b/crates/egui/src/atomics/atom_ext.rs index 0c34544d..6d008b84 100644 --- a/crates/egui/src/atomics/atom_ext.rs +++ b/crates/egui/src/atomics/atom_ext.rs @@ -60,7 +60,7 @@ pub trait AtomExt<'a> { { let font_selection = FontSelection::default(); let font_id = font_selection.resolve(ui.style()); - let height = ui.fonts(|f| f.row_height(&font_id)); + let height = ui.fonts_mut(|f| f.row_height(&font_id)); self.atom_max_height(height) } } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 39190d7a..c3c45dfe 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -476,7 +476,7 @@ impl Window<'_> { let (title_bar_height_with_margin, title_content_spacing) = if with_title_bar { let style = ctx.style(); let title_bar_inner_height = ctx - .fonts(|fonts| title.font_height(fonts, &style)) + .fonts_mut(|fonts| title.font_height(fonts, &style)) .at_least(style.spacing.interact_size.y); let title_bar_inner_height = title_bar_inner_height + window_frame.inner_margin.sum().y; let half_height = (title_bar_inner_height / 2.0).round() as _; diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 8dbbc2c1..4360f66c 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2,15 +2,15 @@ use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration}; -use emath::{GuiRounding as _, OrderedFloat}; +use emath::GuiRounding as _; use epaint::{ - ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect, StrokeKind, - TessellationOptions, TextureAtlas, TextureId, Vec2, + ClippedPrimitive, ClippedShape, Color32, ImageData, Pos2, Rect, StrokeKind, + TessellationOptions, TextureId, Vec2, emath::{self, TSTransform}, mutex::RwLock, stats::PaintStats, tessellator, - text::{FontInsert, FontPriority, Fonts}, + text::{FontInsert, FontPriority, Fonts, FontsView}, vec2, }; @@ -406,12 +406,7 @@ impl ViewportRepaintInfo { #[derive(Default)] struct ContextImpl { - /// Since we could have multiple viewports across multiple monitors with - /// different `pixels_per_point`, we need a `Fonts` instance for each unique - /// `pixels_per_point`. - /// This is because the `Fonts` depend on `pixels_per_point` for the font atlas - /// as well as kerning, font sizes, etc. - fonts: std::collections::BTreeMap, Fonts>, + fonts: Option, font_definitions: FontDefinitions, memory: Memory, @@ -575,12 +570,11 @@ impl ContextImpl { fn update_fonts_mut(&mut self) { profiling::function_scope!(); let input = &self.viewport().input; - let pixels_per_point = input.pixels_per_point(); let max_texture_side = input.max_texture_side; if let Some(font_definitions) = self.memory.new_font_definitions.take() { // New font definition loaded, so we need to reload all fonts. - self.fonts.clear(); + self.fonts = None; self.font_definitions = font_definitions; #[cfg(feature = "log")] log::trace!("Loading new font definitions"); @@ -589,7 +583,7 @@ impl ContextImpl { if !self.memory.add_fonts.is_empty() { let fonts = self.memory.add_fonts.drain(..); for font in fonts { - self.fonts.clear(); // recreate all the fonts + self.fonts = None; // recreate all the fonts for family in font.families { let fam = self .font_definitions @@ -614,26 +608,22 @@ impl ContextImpl { let mut is_new = false; - let fonts = self - .fonts - .entry(pixels_per_point.into()) - .or_insert_with(|| { - #[cfg(feature = "log")] - log::trace!("Creating new Fonts for pixels_per_point={pixels_per_point}"); + let fonts = self.fonts.get_or_insert_with(|| { + #[cfg(feature = "log")] + log::trace!("Creating new Fonts"); - is_new = true; - profiling::scope!("Fonts::new"); - Fonts::new( - pixels_per_point, - max_texture_side, - text_alpha_from_coverage, - self.font_definitions.clone(), - ) - }); + is_new = true; + profiling::scope!("Fonts::new"); + Fonts::new( + max_texture_side, + text_alpha_from_coverage, + self.font_definitions.clone(), + ) + }); { profiling::scope!("Fonts::begin_pass"); - fonts.begin_pass(pixels_per_point, max_texture_side, text_alpha_from_coverage); + fonts.begin_pass(max_texture_side, text_alpha_from_coverage); } if is_new && self.memory.options.preload_font_glyphs { @@ -641,7 +631,10 @@ impl ContextImpl { // Preload the most common characters for the most common fonts. // This is not very important to do, but may save a few GPU operations. for font_id in self.memory.options.style().text_styles.values() { - fonts.lock().fonts.font(font_id).preload_common_characters(); + fonts + .fonts + .font(&font_id.family) + .preload_common_characters(); } } } @@ -1049,13 +1042,32 @@ impl Context { /// Not valid until first call to [`Context::run()`]. /// That's because since we don't know the proper `pixels_per_point` until then. #[inline] - pub fn fonts(&self, reader: impl FnOnce(&Fonts) -> R) -> R { + pub fn fonts(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R { self.write(move |ctx| { let pixels_per_point = ctx.pixels_per_point(); reader( - ctx.fonts - .get(&pixels_per_point.into()) - .expect("No fonts available until first call to Context::run()"), + &ctx.fonts + .as_mut() + .expect("No fonts available until first call to Context::run()") + .with_pixels_per_point(pixels_per_point), + ) + }) + } + + /// Read-write access to [`Fonts`]. + /// + /// Not valid until first call to [`Context::run()`]. + /// That's because since we don't know the proper `pixels_per_point` until then. + #[inline] + pub fn fonts_mut(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R { + self.write(move |ctx| { + let pixels_per_point = ctx.pixels_per_point(); + reader( + &mut ctx + .fonts + .as_mut() + .expect("No fonts available until first call to Context::run()") + .with_pixels_per_point(pixels_per_point), ) }) } @@ -1568,9 +1580,8 @@ impl Context { } = ModifierNames::SYMBOLS; let font_id = TextStyle::Body.resolve(&self.style()); - self.fonts(|f| { - let mut lock = f.lock(); - let font = lock.fonts.font(&font_id); + self.fonts_mut(|f| { + let mut font = f.fonts.font(&font_id.family); font.has_glyphs(alt) && font.has_glyphs(ctrl) && font.has_glyphs(shift) @@ -1920,14 +1931,12 @@ impl Context { pub fn set_fonts(&self, font_definitions: FontDefinitions) { profiling::function_scope!(); - let pixels_per_point = self.pixels_per_point(); - let mut update_fonts = true; self.read(|ctx| { - if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) { + if let Some(current_fonts) = ctx.fonts.as_ref() { // NOTE: this comparison is expensive since it checks TTF data for equality - if current_fonts.lock().fonts.definitions() == &font_definitions { + if current_fonts.definitions() == &font_definitions { update_fonts = false; // no need to update } } @@ -1948,15 +1957,11 @@ impl Context { pub fn add_font(&self, new_font: FontInsert) { profiling::function_scope!(); - let pixels_per_point = self.pixels_per_point(); - let mut update_fonts = true; self.read(|ctx| { - if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) { + if let Some(current_fonts) = ctx.fonts.as_ref() { if current_fonts - .lock() - .fonts .definitions() .font_data .contains_key(&new_font.name) @@ -2449,30 +2454,12 @@ impl ContextImpl { self.memory.end_pass(&viewport.this_pass.used_ids); - if let Some(fonts) = self.fonts.get(&pixels_per_point.into()) { + if let Some(fonts) = self.fonts.as_mut() { let tex_mngr = &mut self.tex_manager.0.write(); if let Some(font_image_delta) = fonts.font_image_delta() { // A partial font atlas update, e.g. a new glyph has been entered. tex_mngr.set(TextureId::default(), font_image_delta); } - - if 1 < self.fonts.len() { - // We have multiple different `pixels_per_point`, - // e.g. because we have many viewports spread across - // monitors with different DPI scaling. - // All viewports share the same texture namespace and renderer, - // so the all use `TextureId::default()` for the font texture. - // This is a problem. - // We solve this with a hack: we always upload the full font atlas - // every frame, for all viewports. - // This ensures it is up-to-date, solving - // https://github.com/emilk/egui/issues/3664 - // at the cost of a lot of performance. - // (This will override any smaller delta that was uploaded above.) - profiling::scope!("full_font_atlas_update"); - let full_delta = ImageDelta::full(fonts.image(), TextureAtlas::texture_options()); - tex_mngr.set(TextureId::default(), full_delta); - } } // Inform the backend of all textures that have been updated (including font atlas). @@ -2615,24 +2602,6 @@ impl ContextImpl { self.memory.set_viewport_id(viewport_id); } - let active_pixels_per_point: std::collections::BTreeSet> = self - .viewports - .values() - .map(|v| v.input.pixels_per_point.into()) - .collect(); - self.fonts.retain(|pixels_per_point, _| { - if active_pixels_per_point.contains(pixels_per_point) { - true - } else { - #[cfg(feature = "log")] - log::trace!( - "Freeing Fonts with pixels_per_point={} because it is no longer needed", - pixels_per_point.into_inner() - ); - false - } - }); - platform_output.num_completed_passes += 1; FullOutput { @@ -2664,7 +2633,7 @@ impl Context { self.write(|ctx| { let tessellation_options = ctx.memory.options.tessellation_options; - let texture_atlas = if let Some(fonts) = ctx.fonts.get(&pixels_per_point.into()) { + let texture_atlas = if let Some(fonts) = ctx.fonts.as_ref() { fonts.texture_atlas() } else { #[cfg(feature = "log")] @@ -2673,13 +2642,8 @@ impl Context { .iter() .next() .expect("No fonts loaded") - .1 .texture_atlas() }; - let (font_tex_size, prepared_discs) = { - let atlas = texture_atlas.lock(); - (atlas.size(), atlas.prepared_discs()) - }; let paint_stats = PaintStats::from_shapes(&shapes); let clipped_primitives = { @@ -2687,8 +2651,8 @@ impl Context { tessellator::Tessellator::new( pixels_per_point, tessellation_options, - font_tex_size, - prepared_discs, + texture_atlas.size(), + texture_atlas.prepared_discs(), ) .tessellate_shapes(shapes) }; diff --git a/crates/egui/src/debug_text.rs b/crates/egui/src/debug_text.rs index 2cd1a275..c3f93871 100644 --- a/crates/egui/src/debug_text.rs +++ b/crates/egui/src/debug_text.rs @@ -98,7 +98,7 @@ impl State { { // Paint location to left of `pos`: let location_galley = - ctx.fonts(|f| f.layout(location, font_id.clone(), color, f32::INFINITY)); + ctx.fonts_mut(|f| f.layout(location, font_id.clone(), color, f32::INFINITY)); let location_rect = Align2::RIGHT_TOP.anchor_size(pos - 4.0 * Vec2::X, location_galley.size()); painter.galley(location_rect.min, location_galley, color); diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index fe273970..f121c855 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use emath::GuiRounding as _; use epaint::{ CircleShape, ClippedShape, CornerRadius, PathStroke, RectShape, Shape, Stroke, StrokeKind, - text::{Fonts, Galley, LayoutJob}, + text::{FontsView, Galley, LayoutJob}, }; use crate::{ @@ -141,14 +141,22 @@ impl Painter { self.pixels_per_point } - /// Read-only access to the shared [`Fonts`]. + /// Read-only access to the shared [`FontsView`]. /// /// See [`Context`] documentation for how locks work. #[inline] - pub fn fonts(&self, reader: impl FnOnce(&Fonts) -> R) -> R { + pub fn fonts(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R { self.ctx.fonts(reader) } + /// Read-write access to the shared [`FontsView`]. + /// + /// See [`Context`] documentation for how locks work. + #[inline] + pub fn fonts_mut(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R { + self.ctx.fonts_mut(reader) + } + /// Where we paint #[inline] pub fn layer_id(&self) -> LayerId { @@ -525,7 +533,7 @@ impl Painter { color: crate::Color32, wrap_width: f32, ) -> Arc { - self.fonts(|f| f.layout(text, font_id, color, wrap_width)) + self.fonts_mut(|f| f.layout(text, font_id, color, wrap_width)) } /// Will line break at `\n`. @@ -539,7 +547,7 @@ impl Painter { font_id: FontId, color: crate::Color32, ) -> Arc { - self.fonts(|f| f.layout(text, font_id, color, f32::INFINITY)) + self.fonts_mut(|f| f.layout(text, font_id, color, f32::INFINITY)) } /// Lay out this text layut job in a galley. @@ -548,7 +556,7 @@ impl Painter { #[inline] #[must_use] pub fn layout_job(&self, layout_job: LayoutJob) -> Arc { - self.fonts(|f| f.layout_job(layout_job)) + self.fonts_mut(|f| f.layout_job(layout_job)) } /// Paint text that has already been laid out in a [`Galley`]. diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index ff8043be..f43a549a 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -2790,7 +2790,6 @@ impl Widget for &mut FontTweak { scale, y_offset_factor, y_offset, - baseline_offset_factor, } = self; ui.label("Scale"); @@ -2806,10 +2805,6 @@ impl Widget for &mut FontTweak { ui.add(DragValue::new(y_offset).speed(-0.02)); ui.end_row(); - ui.label("baseline_offset_factor"); - ui.add(DragValue::new(baseline_offset_factor).speed(-0.0025)); - ui.end_row(); - if ui.button("Reset").clicked() { *self = Default::default(); } diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index f595469b..357e1353 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -3,6 +3,7 @@ use emath::GuiRounding as _; use epaint::mutex::RwLock; +use epaint::text::FontsView; use std::{any::Any, hash::Hash, sync::Arc}; use crate::ClosableTag; @@ -16,9 +17,7 @@ use crate::{ WidgetRect, WidgetText, containers::{CollapsingHeader, CollapsingResponse, Frame}, ecolor::Hsva, - emath, epaint, - epaint::text::Fonts, - grid, + emath, epaint, grid, layout::{Direction, Layout}, pass_state, placer::Placer, @@ -735,7 +734,7 @@ impl Ui { /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. pub fn text_style_height(&self, style: &TextStyle) -> f32 { - self.fonts(|f| f.row_height(&style.resolve(self.style()))) + self.fonts_mut(|f| f.row_height(&style.resolve(self.style()))) } /// Screen-space rectangle for clipping what we paint in this ui. @@ -847,11 +846,17 @@ impl Ui { self.ctx().output_mut(writer) } - /// Read-only access to [`Fonts`]. + /// Read-only access to [`FontsView`]. #[inline] - pub fn fonts(&self, reader: impl FnOnce(&Fonts) -> R) -> R { + pub fn fonts(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R { self.ctx().fonts(reader) } + + /// Read-write access to [`FontsView`]. + #[inline] + pub fn fonts_mut(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R { + self.ctx().fonts_mut(reader) + } } // ------------------------------------------------------------------------ diff --git a/crates/egui/src/widget_text.rs b/crates/egui/src/widget_text.rs index eb0111a7..c66e38d7 100644 --- a/crates/egui/src/widget_text.rs +++ b/crates/egui/src/widget_text.rs @@ -307,7 +307,7 @@ impl RichText { /// Read the font height of the selected text style. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - pub fn font_height(&self, fonts: &epaint::Fonts, style: &Style) -> f32 { + pub fn font_height(&self, fonts: &mut epaint::FontsView<'_>, style: &Style) -> f32 { let mut font_id = self.text_style.as_ref().map_or_else( || FontSelection::Default.resolve(style), |text_style| text_style.resolve(style), @@ -676,7 +676,7 @@ impl WidgetText { } /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - pub(crate) fn font_height(&self, fonts: &epaint::Fonts, style: &Style) -> f32 { + pub(crate) fn font_height(&self, fonts: &mut epaint::FontsView<'_>, style: &Style) -> f32 { match self { Self::Text(_) => fonts.row_height(&FontSelection::Default.resolve(style)), Self::RichText(text) => text.font_height(fonts, style), @@ -762,7 +762,7 @@ impl WidgetText { }, ); layout_job.wrap = text_wrapping; - ctx.fonts(|f| f.layout_job(layout_job)) + ctx.fonts_mut(|f| f.layout_job(layout_job)) } Self::RichText(text) => { let mut layout_job = Arc::unwrap_or_clone(text).into_layout_job( @@ -771,12 +771,12 @@ impl WidgetText { default_valign, ); layout_job.wrap = text_wrapping; - ctx.fonts(|f| f.layout_job(layout_job)) + ctx.fonts_mut(|f| f.layout_job(layout_job)) } Self::LayoutJob(job) => { let mut job = Arc::unwrap_or_clone(job); job.wrap = text_wrapping; - ctx.fonts(|f| f.layout_job(job)) + ctx.fonts_mut(|f| f.layout_job(job)) } Self::Galley(galley) => galley, } diff --git a/crates/egui/src/widgets/label.rs b/crates/egui/src/widgets/label.rs index 115e7551..e0f21fd1 100644 --- a/crates/egui/src/widgets/label.rs +++ b/crates/egui/src/widgets/label.rs @@ -211,7 +211,7 @@ impl Label { if let Some(first_section) = layout_job.sections.first_mut() { first_section.leading_space = first_row_indentation; } - let galley = ui.fonts(|fonts| fonts.layout_job(layout_job)); + let galley = ui.fonts_mut(|fonts| fonts.layout_job(layout_job)); let pos = pos2(ui.max_rect().left(), ui.cursor().top()); assert!(!galley.rows.is_empty(), "Galleys are never empty"); @@ -252,7 +252,7 @@ impl Label { layout_job.justify = ui.layout().horizontal_justify(); } - let galley = ui.fonts(|fonts| fonts.layout_job(layout_job)); + let galley = ui.fonts_mut(|fonts| fonts.layout_job(layout_job)); let (rect, mut response) = ui.allocate_exact_size(galley.size(), sense); response.intrinsic_size = Some(galley.intrinsic_size()); let galley_pos = match galley.job.halign { diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 63dec923..20cd079b 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -266,7 +266,7 @@ impl<'t> TextEdit<'t> { /// let mut layouter = |ui: &egui::Ui, buf: &dyn egui::TextBuffer, wrap_width: f32| { /// let mut layout_job: egui::text::LayoutJob = my_memoized_highlighter(buf.as_str()); /// layout_job.wrap.max_width = wrap_width; - /// ui.fonts(|f| f.layout_job(layout_job)) + /// ui.fonts_mut(|f| f.layout_job(layout_job)) /// }; /// ui.add(egui::TextEdit::multiline(&mut my_code).layouter(&mut layouter)); /// # }); @@ -504,7 +504,7 @@ impl TextEdit<'_> { let hint_text_str = hint_text.text().to_owned(); let font_id = font_selection.resolve(ui.style()); - let row_height = ui.fonts(|f| f.row_height(&font_id)); + let row_height = ui.fonts_mut(|f| f.row_height(&font_id)); const MIN_WIDTH: f32 = 24.0; // Never make a [`TextEdit`] more narrow than this. let available_width = (ui.available_width() - margin.sum().x).at_least(MIN_WIDTH); let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width); @@ -522,7 +522,7 @@ impl TextEdit<'_> { } else { LayoutJob::simple_singleline(text, font_id_clone.clone(), text_color) }; - ui.fonts(|f| f.layout_job(layout_job)) + ui.fonts_mut(|f| f.layout_job(layout_job)) }; let layouter = layouter.unwrap_or(&mut default_layouter); diff --git a/crates/egui_demo_app/src/apps/http_app.rs b/crates/egui_demo_app/src/apps/http_app.rs index 2aed2adb..f16aa596 100644 --- a/crates/egui_demo_app/src/apps/http_app.rs +++ b/crates/egui_demo_app/src/apps/http_app.rs @@ -238,7 +238,7 @@ impl ColoredText { pub fn ui(&self, ui: &mut egui::Ui) { let mut job = self.0.clone(); job.wrap.max_width = ui.available_width(); - let galley = ui.fonts(|f| f.layout_job(job)); + let galley = ui.fonts_mut(|f| f.layout_job(job)); ui.add(egui::Label::new(galley).selectable(true)); } } diff --git a/crates/egui_demo_app/src/frame_history.rs b/crates/egui_demo_app/src/frame_history.rs index 0b34f858..52ff8342 100644 --- a/crates/egui_demo_app/src/frame_history.rs +++ b/crates/egui_demo_app/src/frame_history.rs @@ -90,7 +90,7 @@ impl FrameHistory { )); let cpu_usage = to_screen.inverse().transform_pos(pointer_pos).y; let text = format!("{:.1} ms", 1e3 * cpu_usage); - shapes.push(ui.fonts(|f| { + shapes.push(ui.fonts_mut(|f| { Shape::text( f, pos2(rect.left(), y), diff --git a/crates/egui_demo_app/tests/snapshots/clock.png b/crates/egui_demo_app/tests/snapshots/clock.png index 52e165c9..3ccc458f 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:991cd41c5c9c4e42d8408259a1f276c56470665ee924082405217a83f630c536 -size 334990 +oid sha256:c9a4ac7d3f959100ae760e32b1fa35ba5bbaa0dd3b3d25472cd9c311430e766e +size 335270 diff --git a/crates/egui_demo_app/tests/snapshots/custom3d.png b/crates/egui_demo_app/tests/snapshots/custom3d.png index 18552e0f..7d9c5dfd 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:187da3058c8311292b9fa3387cb0f059a4449ac982ab3a93743427bd7ed602f2 -size 92380 +oid sha256:2c4f0263b6ab61b9b589f6cb7b83ed020e0131bea88a7d2db24a8b2dff026f69 +size 93090 diff --git a/crates/egui_demo_app/tests/snapshots/easymarkeditor.png b/crates/egui_demo_app/tests/snapshots/easymarkeditor.png index f06e16cb..c44c6d3a 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:fc3dbdcd483d4da7a9c1a00f0245a7882997fbcd2d26f8d6a6d2d855f3382063 -size 179724 +oid sha256:3ee4ef83971dc7df940326444723bc9ebd57378476686085d68574c35d3d6513 +size 182173 diff --git a/crates/egui_demo_app/tests/snapshots/imageviewer.png b/crates/egui_demo_app/tests/snapshots/imageviewer.png index e6f108e9..629dbb24 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:c8ad2c2d494e2287b878049091688069e4d86b69ae72b89cb7ecbe47d8c35e33 -size 100766 +oid sha256:47792205570445b5fc3a64ffbc6a4804c7b23b074af90ed1baca691f73f96963 +size 102366 diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index 02f098e6..48e7d520 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -165,14 +165,12 @@ pub fn criterion_benchmark(c: &mut Criterion) { let wrap_width = 512.0; let font_id = egui::FontId::default(); let text_color = egui::Color32::WHITE; - let fonts = egui::epaint::text::Fonts::new( - pixels_per_point, + let mut fonts = egui::epaint::text::Fonts::new( max_texture_side, egui::epaint::AlphaFromCoverage::default(), egui::FontDefinitions::default(), ); { - let mut locked_fonts = fonts.lock(); c.bench_function("text_layout_uncached", |b| { b.iter(|| { use egui::epaint::text::{LayoutJob, layout}; @@ -183,13 +181,13 @@ pub fn criterion_benchmark(c: &mut Criterion) { text_color, wrap_width, ); - layout(&mut locked_fonts.fonts, job.into()) + layout(&mut fonts.fonts, pixels_per_point, job.into()) }); }); } c.bench_function("text_layout_cached", |b| { b.iter(|| { - fonts.layout( + fonts.with_pixels_per_point(pixels_per_point).layout( LOREM_IPSUM_LONG.to_owned(), font_id.clone(), text_color, @@ -211,24 +209,30 @@ pub fn criterion_benchmark(c: &mut Criterion) { let mut rng = rand::rng(); b.iter(|| { - fonts.begin_pass( - pixels_per_point, - max_texture_side, - egui::epaint::AlphaFromCoverage::default(), - ); + fonts.begin_pass(max_texture_side, egui::epaint::AlphaFromCoverage::default()); // Delete a random character, simulating a user making an edit in a long file: let mut new_string = string.clone(); let idx = rng.random_range(0..string.len()); new_string.remove(idx); - fonts.layout(new_string, font_id.clone(), text_color, wrap_width); + fonts.with_pixels_per_point(pixels_per_point).layout( + new_string, + font_id.clone(), + text_color, + wrap_width, + ); }); }); - let galley = fonts.layout(LOREM_IPSUM_LONG.to_owned(), font_id, text_color, wrap_width); + let galley = fonts.with_pixels_per_point(pixels_per_point).layout( + LOREM_IPSUM_LONG.to_owned(), + font_id, + text_color, + wrap_width, + ); let font_image_size = fonts.font_image_size(); - let prepared_discs = fonts.texture_atlas().lock().prepared_discs(); + let prepared_discs = fonts.texture_atlas().prepared_discs(); let mut tessellator = egui::epaint::Tessellator::new( 1.0, Default::default(), diff --git a/crates/egui_demo_lib/src/demo/code_editor.rs b/crates/egui_demo_lib/src/demo/code_editor.rs index 2d67f7d4..6a472031 100644 --- a/crates/egui_demo_lib/src/demo/code_editor.rs +++ b/crates/egui_demo_lib/src/demo/code_editor.rs @@ -85,7 +85,7 @@ impl crate::View for CodeEditor { language, ); layout_job.wrap.max_width = wrap_width; - ui.fonts(|f| f.layout_job(layout_job)) + ui.fonts_mut(|f| f.layout_job(layout_job)) }; egui::ScrollArea::vertical().show(ui, |ui| { diff --git a/crates/egui_demo_lib/src/demo/code_example.rs b/crates/egui_demo_lib/src/demo/code_example.rs index 52cafad0..23f56150 100644 --- a/crates/egui_demo_lib/src/demo/code_example.rs +++ b/crates/egui_demo_lib/src/demo/code_example.rs @@ -85,7 +85,7 @@ impl CodeExample { ui.horizontal(|ui| { let font_id = egui::TextStyle::Monospace.resolve(ui.style()); - let indentation = 2.0 * 4.0 * ui.fonts(|f| f.glyph_width(&font_id, ' ')); + let indentation = 2.0 * 4.0 * ui.fonts_mut(|f| f.glyph_width(&font_id, ' ')); ui.add_space(indentation); egui::Grid::new("code_samples") diff --git a/crates/egui_demo_lib/src/demo/font_book.rs b/crates/egui_demo_lib/src/demo/font_book.rs index 1ef9867f..39acf844 100644 --- a/crates/egui_demo_lib/src/demo/font_book.rs +++ b/crates/egui_demo_lib/src/demo/font_book.rs @@ -77,7 +77,7 @@ impl crate::View for FontBook { let available_glyphs = self .available_glyphs .entry(self.font_id.family.clone()) - .or_insert_with(|| available_characters(ui, self.font_id.family.clone())); + .or_insert_with(|| available_characters(ui, &self.font_id.family)); ui.separator(); @@ -140,11 +140,10 @@ fn char_info_ui(ui: &mut egui::Ui, chr: char, glyph_info: &GlyphInfo, font_id: e }); } -fn available_characters(ui: &egui::Ui, family: egui::FontFamily) -> BTreeMap { - ui.fonts(|f| { - f.lock() - .fonts - .font(&egui::FontId::new(10.0, family)) // size is arbitrary for getting the characters +fn available_characters(ui: &egui::Ui, family: &egui::FontFamily) -> BTreeMap { + ui.fonts_mut(|f| { + f.fonts + .font(family) .characters() .iter() .filter(|(chr, _fonts)| !chr.is_whitespace() && !chr.is_ascii_control()) diff --git a/crates/egui_demo_lib/src/demo/misc_demo_window.rs b/crates/egui_demo_lib/src/demo/misc_demo_window.rs index b5a2402b..bb62f182 100644 --- a/crates/egui_demo_lib/src/demo/misc_demo_window.rs +++ b/crates/egui_demo_lib/src/demo/misc_demo_window.rs @@ -213,7 +213,7 @@ fn label_ui(ui: &mut egui::Ui) { ui.horizontal_wrapped(|ui| { // Trick so we don't have to add spaces in the text below: - let width = ui.fonts(|f|f.glyph_width(&TextStyle::Body.resolve(ui.style()), ' ')); + let width = ui.fonts_mut(|f|f.glyph_width(&TextStyle::Body.resolve(ui.style()), ' ')); ui.spacing_mut().item_spacing.x = width; ui.label(RichText::new("Text can have").color(Color32::from_rgb(110, 255, 110))); @@ -792,7 +792,7 @@ impl TextRotation { let start_pos = self.size / 2.0; - let s = ui.ctx().fonts(|f| { + let s = ui.ctx().fonts_mut(|f| { let mut t = egui::Shape::text( f, rect.min + start_pos, diff --git a/crates/egui_demo_lib/src/demo/scrolling.rs b/crates/egui_demo_lib/src/demo/scrolling.rs index ca3f6e90..63fc81db 100644 --- a/crates/egui_demo_lib/src/demo/scrolling.rs +++ b/crates/egui_demo_lib/src/demo/scrolling.rs @@ -191,7 +191,7 @@ fn huge_content_painter(ui: &mut egui::Ui) { ui.add_space(4.0); let font_id = TextStyle::Body.resolve(ui.style()); - let row_height = ui.fonts(|f| f.row_height(&font_id)) + ui.spacing().item_spacing.y; + let row_height = ui.fonts_mut(|f| f.row_height(&font_id)) + ui.spacing().item_spacing.y; let num_rows = 10_000; ScrollArea::vertical() diff --git a/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs b/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs index 47d0beea..976bdd39 100644 --- a/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs +++ b/crates/egui_demo_lib/src/easy_mark/easy_mark_editor.rs @@ -83,7 +83,7 @@ impl EasyMarkEditor { let mut layouter = |ui: &egui::Ui, easymark: &dyn TextBuffer, wrap_width: f32| { let mut layout_job = highlighter.highlight(ui.style(), easymark.as_str()); layout_job.wrap.max_width = wrap_width; - ui.fonts(|f| f.layout_job(layout_job)) + ui.fonts_mut(|f| f.layout_job(layout_job)) }; ui.add( diff --git a/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs b/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs index 41d99fb8..f9d078b2 100644 --- a/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs +++ b/crates/egui_demo_lib/src/easy_mark/easy_mark_viewer.rs @@ -162,7 +162,7 @@ fn bullet_point(ui: &mut Ui, width: f32) -> Response { fn numbered_point(ui: &mut Ui, width: f32, number: &str) -> Response { let font_id = TextStyle::Body.resolve(ui.style()); - let row_height = ui.fonts(|f| f.row_height(&font_id)); + let row_height = ui.fonts_mut(|f| f.row_height(&font_id)); let (rect, response) = ui.allocate_exact_size(vec2(width, row_height), Sense::hover()); let text = format!("{number}."); let text_color = ui.visuals().strong_text_color(); diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png b/crates/egui_demo_lib/tests/snapshots/demos/Bézier Curve.png index 0bf7d928..39223555 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:13262df01a7f2cd5655b8b0bb9379ae02a851c877314375f047a7d749908125c -size 31368 +oid sha256:514f2d25acec42f1a7baf40716549fe233f61a19cca675165d53f99b2433bb76 +size 31669 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 449c8868..54fd6256 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:27d5aa7b7e6bd5f59c1765e98ca4588545284456e4cc255799ea797950e09850 -size 26461 +oid sha256:693d26c8195ef8062d81127290a1e2e252b317f6430aba8cabf1f1c8b25a3213 +size 26895 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 abd66feb..e5e08d8f 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:b768086b0f79d76f08b21ef315ad5333ae81aa5b592dfbf47535b40d10cc19bc -size 26422 +oid sha256:d55b12672145f5a1b3fd7d8f063735dcce06d1e6dc6fa06af93d7d04c0460ab9 +size 26928 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 94601b4d..e225a8dd 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:d36b7a37d8fcb727a015475f98b54552b37339e1087d0a1af3fd0fefe9a8b9cf -size 78742 +oid sha256:1054c1cb66803f36119e8e698f69dfaf1583167a8eba6316915a21c7303dc22c +size 78324 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 00700086..06832b75 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:3c03eadbd3ba486100303ab9b350d82d5ba31b7aa694641538e8b347a1bc18b0 -size 61400 +oid sha256:4d43b44d4ae5c168762c74b3c34f9ae5a57b63ff3470dfc272a69625b57c8710 +size 62921 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 8fa22e08..53a03ba1 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:a63cee05ac47fdf52ae3a1398f7e230a29ffdfd62ac63f3acc74cedba9100069 -size 25840 +oid sha256:d6a7ac851b248bfe69f486ccaf12063ccc7e73fb01b4e7d07902677b5db6118b +size 25946 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 1bb7af6e..2aedac9a 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:1e3e0330de3f68593329d2f36649127d5ac70109232c68f5c7ce310fa919fda5 -size 20348 +oid sha256:8e37b5c785cd011dbbade5975147702fe7d458c22699c83e307033339f614c26 +size 20797 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 9fd711db..6f8feb5e 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:2882a9842f51a7c3e9642a9a3d260407e1194648f47574608822a293bd3b1d56 -size 10465 +oid sha256:24e31eeaf1b7c07fb1ddb3aa92a876595436c20fa54937cf35c44fb7a7a6d890 +size 10774 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 2551a521..1ea554b0 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:1e4ba53720713a8083997acb990fe4fc68ba4b9ffc7a4e58f17faa66de0da091 -size 128261 +oid sha256:a1c130d0a2cacc4fcc55d9c6947ce239a68cada8c207a03a04b08e822adb9cd5 +size 127038 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Frame.png b/crates/egui_demo_lib/tests/snapshots/demos/Frame.png index e802bcec..e5484585 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:08deb70e760326a1274ebcbd51849aae958ace52ec1aab36fff93a9b8dd98f4d -size 24029 +oid sha256:294f03e8961a96705ca219da37555a4c856849ac2e8cea73bca29948e68526c6 +size 24505 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 09ccf9c6..a19dafc5 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:828ee860ed31930d67deb2b6efee8bf2aec3c3266cf05b5510d1565dc7090e2f -size 99106 +oid sha256:d5bb6d587903f3bd06ed8e3410ba8f31aa88fe355adb36023e4949bf89c009b4 +size 101649 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png b/crates/egui_demo_lib/tests/snapshots/demos/Highlighting.png index e8b6bd55..5a623f8a 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:403321533e97eac1aaf994d0ddeb5d53f06070a4b6a5c913c0ba22a3c60ad761 -size 17604 +oid sha256:12aa0ce4cd746cffc9fafc1daa43342df7b251f92a7e330be44b1b73e671c9f7 +size 18142 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 b7f376a3..2274ecb7 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:e3978a1dd2479bab2f234411b49d414fa3cf43ae18025db570f3c7a84f4a16e7 -size 111696 +oid sha256:cc2575366c79922f95a7b40766b6a5a91fdac7bce49c1eb057d992679d11030f +size 115934 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 40ea1255..80f75d67 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:c6e29013cf12bd663cd7243baad03585c8d5b95d592f96aa8d7910abf5dcc2db -size 24541 +oid sha256:a7b1f709a5e8be577dbdd6122935dc1969fbe355155b78b00b862be2bdb268d1 +size 24876 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 46e5daea..dac41f75 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:8071d1a913ed35c4edab01dcce28996ee1c365ca393e11fd3f99cef65c7736ec -size 50357 +oid sha256:b3201768ee61eb87aba5fac21b3382b160296acd3a0d7caab62360efe63cd94d +size 51714 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 d934345b..e354d67c 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:641e5c7d4deccc8eb0374db4707dc356285a5c72186f9021d0d601c22bc5115f -size 21894 +oid sha256:28112d906a73833fb6052402df4717a17fd374ab7c3a5f84348463e025689b58 +size 22255 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 00958a6e..2d194861 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:6cefcd7aa537e98e3a560fc458028f7e6b4f67e92343b94771f3ba21dce0298c -size 46666 +oid sha256:8b485f4dd8b72fa6b8c689b4091a0660afd4f1301287382c44c16c3bb4fc5e0c +size 47315 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 3e4c97ce..11e7bc7d 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:9ff7b37547644d542e7fe3486954479d0e28ee30be37f7c938b820192eddcfb9 -size 24078 +oid sha256:90d78b13159965cdaac9c67aa54a11390c0a18a0fdcee7f818edd06f87fa865f +size 24313 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 1a65dbc7..d2151b1b 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:5211f7be04c3c28555cc3b53c798c165854441e9847d9bf7d67ad6b2fb0e72cc -size 64618 +oid sha256:c672c2ad3c33863a09b35e00fcd761ba91488d194273788c9790ac475d20e33c +size 66212 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Modals.png b/crates/egui_demo_lib/tests/snapshots/demos/Modals.png index e77312e7..c2f99876 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:2f467edf4a84c8a98d96f168d843edb201ad2ee067dcd9d8d9ea214a02a41b1f -size 32182 +oid sha256:0d12e4f2fbfebc8ba3050f317e98f2a485ec7961db9190104143257499d206ac +size 32700 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 a5036a36..7fc83efa 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:99c68d8904a48205bbf02eb134715d289881be5b868949dbd22602f2a35a1d47 -size 35718 +oid sha256:a80efaa91120ab8b830037073b5c177045261da2a8f146c859bc76317a6a3b1a +size 36328 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Painting.png b/crates/egui_demo_lib/tests/snapshots/demos/Painting.png index d39c76ef..6f56df92 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:f8d3c5c2032c8eb36f60b2422eb8dd257b7b6417b1d93b120b3347e37a047c74 -size 17447 +oid sha256:a654b9ebd75fb1fea733378ffcd50876dae406610ef070c3aa487db0a5f48eb1 +size 17625 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Panels.png b/crates/egui_demo_lib/tests/snapshots/demos/Panels.png index 87b675bc..22daed0e 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:376657d119ace8d96b52bbf0e9daf379f8e0d5ee6a1be840b3efc210a02b6364 -size 277816 +oid sha256:c91f592571ba654d0a96791662ae7530a1db4c1630b57c795d1c006ea6e46f19 +size 256975 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Popups.png b/crates/egui_demo_lib/tests/snapshots/demos/Popups.png index 27b088e2..e926f466 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:88cebf1a05400c967f8930271eb3f6a983fe82e9afa266682a2bd3862e2ab62f -size 57055 +oid sha256:87df1de1677b993bdaaf0c0f13db1e0c9a52bdf91cbdc8c4487357e09cbfc453 +size 56985 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 9e14e624..f96fce91 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:22515363a812443b65cbe9060e2352e18eed04dc382fc993c33bd8a4b5ddff91 -size 24817 +oid sha256:a11b0aeb8b8a7ff3acd54b99869af03cd04cc2edf13afc713ce924c52d39262d +size 24826 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Scene.png b/crates/egui_demo_lib/tests/snapshots/demos/Scene.png index 760c84e8..0f8ca667 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:aabc0e3821a2d9b21708e9b8d9be02ad55055ccabe719a93af921dba2384b4b3 -size 34297 +oid sha256:b17c6044a9975a871da3062a5e1f55e500ebd4b0c325ee8c1d9277d8f7ba24e3 +size 35158 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png b/crates/egui_demo_lib/tests/snapshots/demos/Screenshot.png index 7a57f940..32dd79e9 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:15d023fcd551cbf7b643bae2591751e075fdcd8ef9386e5ab28ac2cd99c0efee -size 23230 +oid sha256:165b7029b921d3c4a2ad7164eaf288efc3e5f022341dc89ea214f50890072c49 +size 23385 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png b/crates/egui_demo_lib/tests/snapshots/demos/Scrolling.png index 5d1261a7..16912ea5 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:059238da7f4eebf6f33da593ee5e756a710d1ea1c19ebab4494dd0f9362e822f -size 179995 +oid sha256:45a5e9542b928cf1624d84f6bf8e339dc78e02adb4d90ae83fad914941319631 +size 186697 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png b/crates/egui_demo_lib/tests/snapshots/demos/Sliders.png index 89e3c12f..4c18fae8 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:599ecaca9a324200096e445992de027fb9e9a93d56fc5cb918777aa306d20f58 -size 115446 +oid sha256:d96d6f381aa5e2ac87ee8a7a3fcf1d07a98532642ba5d45e3c24a5c331bafd96 +size 119551 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Strip.png b/crates/egui_demo_lib/tests/snapshots/demos/Strip.png index 40ba0313..cadb7ea8 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:c8a0b214ec1cc325b88918f25da87bfdb469cbcc6bf6646a0ac0a1d5f21a26e6 -size 25614 +oid sha256:b97435e619f0655d6332ed1f779af6b93c65b5264b09e7f05242db0b196c8c27 +size 26019 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Table.png b/crates/egui_demo_lib/tests/snapshots/demos/Table.png index f6e367f3..dd8ef686 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:9b51b334db17a29df66e010c06d6cb3599013b569c068cf55b9603ed40c03eae -size 75313 +oid sha256:a834ebd9c0e66b4e4e60d5dd02274624005e368ae4c9b6f0a34feef51ecd6648 +size 76635 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 462a40ad..75cd7ad6 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:a3f8873c9cfb80ddeb1ccc0fa04c1c84ea936db1685238f5d29ee6e89f55e457 -size 68814 +oid sha256:a77520c0176ff60c506174998fa6e0cc9473103e93efb05858f52c82fe1b3852 +size 69473 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 ef9969e5..a0dd98a5 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:1f74f765e6f187a9cf8f3ff254b1fa5826d0c2719ef904560d56aebae7526fa7 -size 64799 +oid sha256:beeb28e1e1d25281ad69736be3aae98ae6ca20c16873be5596f2e608894536b8 +size 66019 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png b/crates/egui_demo_lib/tests/snapshots/demos/TextEdit.png index 3bdadb62..96b998fe 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:e82ae562cf2c987624667cd9324e21726411802c2a901fe36d9f9e4e61c6b980 -size 20968 +oid sha256:806b43782ee228900ecb9c7b1fb7b57a8894669db1475a13852215f64d18b2c5 +size 21352 diff --git a/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png b/crates/egui_demo_lib/tests/snapshots/demos/Tooltips.png index 0652b37e..c790b599 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:a328a035ebf0dd10b935902e8e17a8fce7455f2dcf21c90f44e44ce9e99c2677 -size 62318 +oid sha256:3b70081c1423731d387df294f5685c56d265b6b66dfd95e606624665d45d3766 +size 64463 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 6da00036..fce774dc 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:0bcca7b25740375f882acd6707b360092a78f96a1b7c807b5c22904a9c8efbd8 -size 12872 +oid sha256:1a837402657274b1a31e757005cb1fb0f5b345f9d3427be700357b982455baec +size 13081 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 6b889a87..b61e004c 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:288d8c2a5aa14fb1b9a7bb6dbc098c7cfbe5bb5391baf6566785d824affb9396 -size 35306 +oid sha256:fda993429a2454cf84ae9cc73ae4242aa50a80a5fd8920dc35601bf8442e9669 +size 36020 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 4f39f775..41115407 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:b8c3dd4dd971ad19d6695f063779f0a25c9b4ad4a15d4e5e080ac5d832605d95 -size 42521 +oid sha256:c8ee6b7e3e4c4d3dd96b1b7f6111a9e032e2ee96c157ff7d669332d15b23129d +size 43557 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_1.png b/crates/egui_demo_lib/tests/snapshots/modals_1.png index f38387d3..e5e0ddc0 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:0b1ef1ed7d902b72fac55a83865cff451c04c8ef230096a4dc420a699936334a -size 47540 +oid sha256:702842a12c11f131bf41ad49542369b0aa520bf2ec89e460c069177c48e630b4 +size 48301 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_2.png b/crates/egui_demo_lib/tests/snapshots/modals_2.png index 99115921..119ff2e5 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:630041fbea61422695bb52fb3d5b00ad877cb0a55cdc264d3d6c665e7d2339a7 -size 47502 +oid sha256:ab58d458abb369d4925e6ca614cdfd5f87171de5def5daa23f0fa002af8c7b18 +size 48229 diff --git a/crates/egui_demo_lib/tests/snapshots/modals_3.png b/crates/egui_demo_lib/tests/snapshots/modals_3.png index ed47d5db..a8301076 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:9c831bbc1f4f52e0b1d2868af3e5632717b2fd8df196b507151dcafc61ddbd45 -size 43772 +oid sha256:a89afce6dbbc27ebac9989be3219d96aac4f51f09dea0c10c9a13e3e6e5b7d54 +size 44194 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 c14d596e..7e0bac99 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:7b5ecf62a1a4edbecb65948796695084d3ac82d6bdf6b80a5f09241e76987f64 -size 43676 +oid sha256:331d86036fea0271cda3969de4c59650df90c1d6442d61f99200fa699d5b9d74 +size 44318 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 200de983..d04c406a 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:39bd11647241521c0ad5c7163a1af4f1aa86792018657091a2d47bb7f2c48b47 -size 598408 +oid sha256:89326fda609fdd4b6ce6aa5cd0881d2a720ee498c7283670085fb4116738117d +size 619548 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 ea9298ad..bda95de7 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:080a59163ab60d60738cfab5afac7cfbddfb585d8a0ee7d03540924b458badea -size 833822 +oid sha256:fde14e4bb03251a7ff4ba508e3c78eb33204781dc67dec440f93a146d74f6691 +size 813974 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 86ec338c..7d389ceb 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:216d3d028f48f4bfbd6aca0a25500655d4eb4d5581a387397ed0b048d57fc0c3 -size 984737 +oid sha256:d5c95515a85e1bb827ff5507843c30d39864fdf0578890ce788889578ae65724 +size 992333 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 3b239324..ea6dc57c 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:399fc3d64e7ff637425effe6c80d684be1cf8bb9b555458352d0ae6c62bddb5a -size 1109505 +oid sha256:53423e41be4856056639d14aca6695966465d8ed0379a97deeb101aa41ff560b +size 1129280 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 8d4a1b36..ef72be63 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:30ce4874a1adb8acf8c8e404f3e19e683eca3133cdef15befbc50d6c09618094 -size 1241773 +oid sha256:56ec1367a030b816a01b5580f454d1a2138cc4dc1fd2534526743b33fd4d1be9 +size 1239055 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 854ee6b2..4c0ac30e 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:135fbe5f4ee485ee671931b64c16410b9073d40bedb23dc2545fc863448e8c63 -size 1398091 +oid sha256:3d9ab25243e4850888e43b268801963d8fafb68aa27e0a7cfc1f4b563c8326e8 +size 1410062 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 852bc6bb..50bf1982 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:1b0fe7aa33506c59142aff764c6b229e8c55b35c8038312b22ea2659987a081a -size 45578 +oid sha256:ec6720a0b4d1db5ddcd08e4ee9834b56b9d0bded7d7e7194865f804d74bb76b2 +size 46251 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 49ba9ad0..5d1ececa 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:3a3512ea7235640db79e86aa84039621784270201c9213c910f15e7451e5600b -size 87336 +oid sha256:234f2b50e096f1f1545531edeb5a7865e0a73e2035967ce3270602512c3a9a18 +size 88006 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 6130a530..26a97fe6 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:dc4918a534f26b72d42ef20221e26c0f91a0252870a1987c1fe4cc4aa3c74872 -size 119406 +oid sha256:d4611a5844cb85a000ec1fb7b51b6a75ba8ada24da108d962b16b0317e55fa7f +size 120119 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 7969d6be..50bae8ac 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:71182570a65693839fd7cd7390025731ab3f3f88ab55bc67d8be6466fe5a2c11 -size 51843 +oid sha256:e6fcca95ef83f8fd57359ac3bb52aa2bb338a726845fbe0370c41e59b99f15d3 +size 52535 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 49141c40..cf996488 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:a0dc0294f990730da34fcbbc53f44280306ec6179826c20a6c9ee946e1148b61 -size 55042 +oid sha256:c15f24d4b9a969b7dc275a3402e2fc36a1b86f3bfaf4f43b8c3e7ae36634e70e +size 55729 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 e8f61ae7..73c70b4e 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:3004adfe5a864bdc768ceb42d1f09b6debcaf5413f8fea4d36b0aff99e4584f9 -size 55511 +oid sha256:58bbd42732e48c1792765dc0c48d57ef0e4441a8b4e97eed936d564bef661116 +size 56210 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 139648c3..69aa782b 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:b99360833f59a212a965a13d52485ab8ad0e6420b9288b2d6936507067c22a85 -size 36395 +oid sha256:8546adf43506733e48e3c8988f7e869bffb2a674629dc9d66e52a5aae0123653 +size 37132 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 10ad7603..cd8804dc 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:82aa004f668f0ac6b493717b4bff8436ccc1e991c7fb3fcde5b5f3a123c06b9f -size 36428 +oid sha256:aff779555f23d9360f58f1b7dc2686c72b848cc5d0a889ba4d5446fc4b252d65 +size 37112 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 9cd2d630..daabdb90 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:7e21bb01ae6e4226402a97b7086b49604cdde6b41a6770199df68dc940cd9a45 -size 64748 +oid sha256:7ad3e3de6e1c12eccd12750c44f52e863f28c3234cbc4f3091674e8c03a9d503 +size 66162 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 f881f639..586bf57e 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:0626bc45888ad250bf4b49c7f7f462a93ab91e3a2817fd7d0902411043c97132 -size 153289 +oid sha256:e9208c3b89665e8aab19ab5e7b427ed8251381c92c3b7c51a708f80c61be28b2 +size 152614 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 5b88cc53..62c85f87 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:919a82c95468300bcd09471eb31d53d25d50cdcb02c27ddbc759d24e65da92b6 -size 59398 +oid sha256:b55a25a1ccff076036b574c82a923d13ff353c2f7a4927f2d911d04121782c05 +size 60492 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 a1971cad..7e5f3baf 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:a55e39a640b0e2cc992286a86dcf38460f1abcc7b964df9022549ca1a94c4df5 -size 146408 +oid sha256:ae7992752e2fce96d0083143f07f216d27472ee057995ac2630cecccfeb44bcc +size 146455 diff --git a/crates/egui_kittest/tests/snapshots/combobox_closed.png b/crates/egui_kittest/tests/snapshots/combobox_closed.png index b7a105c8..01d7d4d0 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:bab1f08160bc43410b9d49ebfaae8a471309e670fccd31456a09176513361e6e -size 4417 +oid sha256:9e42d26fa8188790c1dfed8e6a1a9f36a01b066a798dd1c878eeb3f0d1fb7e52 +size 4475 diff --git a/crates/egui_kittest/tests/snapshots/combobox_opened.png b/crates/egui_kittest/tests/snapshots/combobox_opened.png index b406cf5d..7c392a7c 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:b3a4ea95569b812ea46bc706f91d5ac03fa18ef1707a726b729422e9e9b18680 -size 7305 +oid sha256:03564030d1ce4d1698b2e831df405d88d3930de2894ff2b601adf1723c160383 +size 7443 diff --git a/crates/egui_kittest/tests/snapshots/image_snapshots.png b/crates/egui_kittest/tests/snapshots/image_snapshots.png index 5c1bf9f4..7df240eb 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:c618906fe1ff781c20cb89747879fa1ac63a115c624a2695adb9eb6ae157cd40 -size 2095 +oid sha256:668999dda2ce857c5a43dd7bdaf88d2062105683f2628b7f41b8885c423693df +size 2136 diff --git a/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png b/crates/egui_kittest/tests/snapshots/menu/closed_hovered.png index 5e35fe18..3d8bfd20 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:29074de792c3c266b451ed28c940d7278d533570efecf5a64ae8bbae2b851a52 -size 10533 +oid sha256:d62d6e8eb73acaaa4851268f33ca6a9411f5c96eeaae5795bb5f71af4f8e31ba +size 10819 diff --git a/crates/egui_kittest/tests/snapshots/menu/opened.png b/crates/egui_kittest/tests/snapshots/menu/opened.png index 655eaf44..c52ecaf0 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:8a12bfee8b9c6b6845ff3cadc40bdb707375f2177095fcd7f0b9ad1fcf1e9f00 -size 21118 +oid sha256:670b2c2887f3be0d808faca41195caebf227420034a725494bb5a07122f4cabe +size 21881 diff --git a/crates/egui_kittest/tests/snapshots/menu/submenu.png b/crates/egui_kittest/tests/snapshots/menu/submenu.png index c4f20079..8dde92fe 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:0e70f7ec229d94919346192141272273ff2f56032e1ae3137cc04ffd21aabe51 -size 28361 +oid sha256:52318e0106cc60d9442b2caa9d4cfa6b0831e9a85e2ed5415be67e9cdb113303 +size 29122 diff --git a/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png b/crates/egui_kittest/tests/snapshots/menu/subsubmenu.png index 16d510ea..ceb49b1c 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:d3295fc14054c31efd7a5c6508f52c4a80b0fb8f91a452808bcfe3e4dddecc9c -size 32992 +oid sha256:10ac5ab3174646c2ec943c43ee954d7450f2d435f14b184bc824b858f1f036c2 +size 33901 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 036cdd00..7f3a5599 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:e2ef3a6fb7d43c85b0f8cdb0eb7a784aa7ae5af9b61ae296e0d1a41871eb2724 -size 19713 +oid sha256:89d172c28662826c8b0897a703730c629ca438755a14f040f029944d55f24353 +size 19966 diff --git a/crates/egui_kittest/tests/snapshots/readme_example.png b/crates/egui_kittest/tests/snapshots/readme_example.png index 2be9c9cd..eed33654 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:730bdd28319b140433802740728f096adda749014a1629114b18d6f674ee4d86 -size 1893 +oid sha256:b17893705837c90f589b23b1e5b418e5ce93c5601c4abf348b8fc6ef416e4278 +size 1947 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 bb592493..4a3f79eb 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:b8c872f818a2e88cce35d015d16406c225ab6792cc6bfd232de94dbf2665df26 -size 2142 +oid sha256:b0b3a6fdd415cfae89d08fe0d10b0dab2327bba5f0fdb2032d3db271811313e6 +size 2182 diff --git a/crates/egui_kittest/tests/snapshots/test_masking.png b/crates/egui_kittest/tests/snapshots/test_masking.png index 932e9d5e..def54053 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:cdb0c0b955e3d3773a00afa61d4c44999de447aa71dd737181563101f09f5ac9 -size 5444 +oid sha256:dc85c7d6a9fe285ad27693169fd9a9fead0286637e3f77a349e573e660a13c47 +size 5697 diff --git a/crates/egui_kittest/tests/snapshots/test_scroll_initial.png b/crates/egui_kittest/tests/snapshots/test_scroll_initial.png index 32969d74..00ff4584 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:70d76e55327de17163bc9c7e128c28153f95db3229dec919352a024eb80544f1 -size 7399 +oid sha256:dd0968233f5145a3708fe5ff771473abd824952e71182c2311670417c6a92f04 +size 7623 diff --git a/crates/egui_kittest/tests/snapshots/test_scroll_scrolled.png b/crates/egui_kittest/tests/snapshots/test_scroll_scrolled.png index 361925d0..8ac89d1a 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:b4b7b3145401b7cf9815a652a0914b230892ffda3b5e23fea530dafee9c0c3d3 -size 8110 +oid sha256:edc4149d67817420db2a2877a1eb83ad7569fd7aa8a4bf75a6dd93b2b59e9615 +size 8305 diff --git a/crates/egui_kittest/tests/snapshots/test_shrink.png b/crates/egui_kittest/tests/snapshots/test_shrink.png index 0004a0f6..dc83dbda 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:be6f0caa911d93543edb39ba6d07d7617ec283b37bc62622a68a18960eb840ab -size 2871 +oid sha256:99ec3f7a81bbe351d0a894005fad95129f36d5c8cc29b4648ddfb9ddce201913 +size 2983 diff --git a/crates/epaint/src/lib.rs b/crates/epaint/src/lib.rs index 5e6dc27e..1bf0285b 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, Galley}, + text::{FontFamily, FontId, Fonts, FontsView, Galley}, texture_atlas::TextureAtlas, texture_handle::TextureHandle, textures::TextureManager, diff --git a/crates/epaint/src/shapes/shape.rs b/crates/epaint/src/shapes/shape.rs index 10de38d1..8ee852c6 100644 --- a/crates/epaint/src/shapes/shape.rs +++ b/crates/epaint/src/shapes/shape.rs @@ -7,7 +7,7 @@ use emath::{Align2, Pos2, Rangef, Rect, TSTransform, Vec2, pos2}; use crate::{ Color32, CornerRadius, Mesh, Stroke, StrokeKind, TextureId, stroke::PathStroke, - text::{FontId, Fonts, Galley}, + text::{FontId, FontsView, Galley}, }; use super::{ @@ -299,7 +299,7 @@ impl Shape { #[expect(clippy::needless_pass_by_value)] pub fn text( - fonts: &Fonts, + fonts: &mut FontsView<'_>, pos: Pos2, anchor: Align2, text: impl ToString, diff --git a/crates/epaint/src/shapes/text_shape.rs b/crates/epaint/src/shapes/text_shape.rs index 9505dc49..349707ea 100644 --- a/crates/epaint/src/shapes/text_shape.rs +++ b/crates/epaint/src/shapes/text_shape.rs @@ -15,7 +15,7 @@ pub struct TextShape { /// Usually the top left corner of the first character. pub pos: Pos2, - /// The laid out text, from [`Fonts::layout_job`]. + /// The laid out text, from [`FontsView::layout_job`]. pub galley: Arc, /// Add this underline to the whole text. @@ -181,8 +181,7 @@ mod tests { #[test] fn text_bounding_box_under_rotation() { - let fonts = Fonts::new( - 1.0, + let mut fonts = Fonts::new( 1024, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -190,7 +189,7 @@ mod tests { let font = FontId::monospace(12.0); let mut t = crate::Shape::text( - &fonts, + &mut fonts.with_pixels_per_point(1.0), Pos2::ZERO, emath::Align2::CENTER_CENTER, "testing123", diff --git a/crates/epaint/src/text/font.rs b/crates/epaint/src/text/font.rs index dd095c44..f3d09899 100644 --- a/crates/epaint/src/text/font.rs +++ b/crates/epaint/src/text/font.rs @@ -1,12 +1,14 @@ use std::collections::BTreeMap; -use std::sync::Arc; -use emath::{GuiRounding as _, Vec2, vec2}; +use ab_glyph::{Font as _, OutlinedGlyph, PxScale}; +use emath::{GuiRounding as _, OrderedFloat, Vec2, vec2}; use crate::{ TextureAtlas, - mutex::{Mutex, RwLock}, - text::FontTweak, + text::{ + FontTweak, + fonts::{CachedFamily, FontFaceKey}, + }, }; // ---------------------------------------------------------------------------- @@ -34,108 +36,168 @@ impl UvRect { } } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct GlyphInfo { + /// Used for pair-kerning. + /// + /// Doesn't need to be unique. + /// + /// Is `None` for a special "invisible" glyph. + pub(crate) id: Option, + + /// In [`ab_glyph`]s "unscaled" coordinate system. + pub advance_width_unscaled: OrderedFloat, +} + +impl GlyphInfo { + /// A valid, but invisible, glyph of zero-width. + pub const INVISIBLE: Self = Self { + id: None, + advance_width_unscaled: OrderedFloat(0.0), + }; +} + +// Subpixel binning, taken from cosmic-text: +// https://github.com/pop-os/cosmic-text/blob/974ddaed96b334f560b606ebe5d2ca2d2f9f23ef/src/glyph_cache.rs + +/// Bin for subpixel positioning of glyphs. +/// +/// For accurate glyph positioning, we want to render each glyph at a subpixel coordinate. However, we also want to +/// cache each glyph's bitmap. As a compromise, we bin each subpixel offset into one of four fractional values. This +/// means one glyph can have up to four subpixel-positioned bitmaps in the cache. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub(super) enum SubpixelBin { + #[default] + Zero, + One, + Two, + Three, +} + +impl SubpixelBin { + /// Bin the given position and return the new integral coordinate. + fn new(pos: f32) -> (i32, Self) { + let trunc = pos as i32; + let fract = pos - trunc as f32; + + #[expect(clippy::collapsible_else_if)] + if pos.is_sign_negative() { + if fract > -0.125 { + (trunc, Self::Zero) + } else if fract > -0.375 { + (trunc - 1, Self::Three) + } else if fract > -0.625 { + (trunc - 1, Self::Two) + } else if fract > -0.875 { + (trunc - 1, Self::One) + } else { + (trunc - 1, Self::Zero) + } + } else { + if fract < 0.125 { + (trunc, Self::Zero) + } else if fract < 0.375 { + (trunc, Self::One) + } else if fract < 0.625 { + (trunc, Self::Two) + } else if fract < 0.875 { + (trunc, Self::Three) + } else { + (trunc + 1, Self::Zero) + } + } + } + + pub fn as_float(&self) -> f32 { + match self { + Self::Zero => 0.0, + Self::One => 0.25, + Self::Two => 0.5, + Self::Three => 0.75, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Default)] +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, - /// Unit: points. - pub advance_width: f32, + /// Unit: screen pixels. + pub advance_width_px: f32, - /// Texture coordinates. + /// UV rectangle for drawing. pub uv_rect: UvRect, } -impl Default for GlyphInfo { - /// Basically a zero-width space. - fn default() -> Self { - Self { - id: ab_glyph::GlyphId(0), - advance_width: 0.0, - uv_rect: Default::default(), - } +#[derive(Hash, PartialEq, Eq)] +struct GlyphCacheKey(u64); + +impl nohash_hasher::IsEnabled for GlyphCacheKey {} + +impl GlyphCacheKey { + fn new(glyph_id: ab_glyph::GlyphId, metrics: &ScaledMetrics, bin: SubpixelBin) -> Self { + let ScaledMetrics { + pixels_per_point, + px_scale_factor, + .. + } = *metrics; + debug_assert!( + 0.0 < pixels_per_point && pixels_per_point.is_finite(), + "Bad pixels_per_point {pixels_per_point}" + ); + debug_assert!( + 0.0 < px_scale_factor && px_scale_factor.is_finite(), + "Bad px_scale_factor: {px_scale_factor}" + ); + Self(crate::util::hash(( + glyph_id, + pixels_per_point.to_bits(), + px_scale_factor.to_bits(), + bin, + ))) } } // ---------------------------------------------------------------------------- -/// A specific font with a size. +/// A specific font face. /// The interface uses points as the unit for everything. pub struct FontImpl { name: String, ab_glyph_font: ab_glyph::FontArc, + tweak: FontTweak, + glyph_info_cache: ahash::HashMap, + glyph_alloc_cache: ahash::HashMap, +} - /// Maximum character height - scale_in_pixels: u32, +trait FontExt { + fn px_scale_factor(&self, scale: f32) -> f32; +} - height_in_points: f32, - - // move each character by this much (hack) - y_offset_in_points: f32, - - ascent: f32, - pixels_per_point: f32, - glyph_info_cache: RwLock>, // TODO(emilk): standard Mutex - atlas: Arc>, +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 + } } impl FontImpl { - pub fn new( - atlas: Arc>, - pixels_per_point: f32, - name: String, - ab_glyph_font: ab_glyph::FontArc, - scale_in_pixels: f32, - tweak: FontTweak, - ) -> Self { - assert!( - scale_in_pixels > 0.0, - "scale_in_pixels is smaller than 0, got: {scale_in_pixels:?}" - ); - assert!( - pixels_per_point > 0.0, - "pixels_per_point must be greater than 0, got: {pixels_per_point:?}" - ); - - use ab_glyph::{Font as _, ScaleFont as _}; - let scaled = ab_glyph_font.as_scaled(scale_in_pixels); - let ascent = (scaled.ascent() / pixels_per_point).round_ui(); - let descent = (scaled.descent() / pixels_per_point).round_ui(); - let line_gap = (scaled.line_gap() / pixels_per_point).round_ui(); - - // Tweak the scale as the user desired - let scale_in_pixels = scale_in_pixels * tweak.scale; - let scale_in_points = scale_in_pixels / pixels_per_point; - - let baseline_offset = (scale_in_points * tweak.baseline_offset_factor).round_ui(); - - let y_offset_points = - ((scale_in_points * tweak.y_offset_factor) + tweak.y_offset).round_ui(); - - // Center scaled glyphs properly: - let height = ascent + descent; - let y_offset_points = y_offset_points - (1.0 - tweak.scale) * 0.5 * height; - - // Round to an even number of physical pixels to get even kerning. - // See https://github.com/emilk/egui/issues/382 - let scale_in_pixels = scale_in_pixels.round() as u32; - - // Round to closest pixel: - let y_offset_in_points = (y_offset_points * pixels_per_point).round() / pixels_per_point; - + pub fn new(name: String, ab_glyph_font: ab_glyph::FontArc, tweak: FontTweak) -> Self { Self { name, ab_glyph_font, - scale_in_pixels, - height_in_points: ascent - descent + line_gap, - y_offset_in_points, - ascent: ascent + baseline_offset, - pixels_per_point, + tweak, glyph_info_cache: Default::default(), - atlas, + glyph_alloc_cache: Default::default(), } } @@ -161,7 +223,6 @@ impl FontImpl { /// An un-ordered iterator over all supported characters. fn characters(&self) -> impl Iterator + '_ { - use ab_glyph::Font as _; self.ab_glyph_font .codepoint_ids() .map(|(_, chr)| chr) @@ -169,11 +230,9 @@ impl FontImpl { } /// `\n` will result in `None` - fn glyph_info(&self, c: char) -> Option { - { - if let Some(glyph_info) = self.glyph_info_cache.read().get(&c) { - return Some(*glyph_info); - } + pub(super) fn glyph_info(&mut self, c: char) -> Option { + if let Some(glyph_info) = self.glyph_info_cache.get(&c) { + return Some(*glyph_info); } if self.ignore_character(c) { @@ -183,10 +242,12 @@ impl FontImpl { if c == '\t' { if let Some(space) = self.glyph_info(' ') { let glyph_info = GlyphInfo { - advance_width: crate::text::TAB_SIZE as f32 * space.advance_width, + advance_width_unscaled: (crate::text::TAB_SIZE as f32 + * space.advance_width_unscaled.0) + .into(), ..space }; - self.glyph_info_cache.write().insert(c, glyph_info); + self.glyph_info_cache.insert(c, glyph_info); return Some(glyph_info); } } @@ -197,91 +258,150 @@ impl FontImpl { // https://en.wikipedia.org/wiki/Thin_space if let Some(space) = self.glyph_info(' ') { - let em = self.height_in_points; // TODO(emilk): is this right? - let advance_width = f32::min(em / 6.0, space.advance_width * 0.5); + let em = self.ab_glyph_font.units_per_em().unwrap_or(1.0); + let advance_width = f32::min(em / 6.0, space.advance_width_unscaled.0 * 0.5); let glyph_info = GlyphInfo { - advance_width, + advance_width_unscaled: advance_width.into(), ..space }; - self.glyph_info_cache.write().insert(c, glyph_info); + self.glyph_info_cache.insert(c, glyph_info); return Some(glyph_info); } } if invisible_char(c) { - let glyph_info = GlyphInfo::default(); - self.glyph_info_cache.write().insert(c, glyph_info); + let glyph_info = GlyphInfo::INVISIBLE; + self.glyph_info_cache.insert(c, glyph_info); return Some(glyph_info); } // Add new character: - use ab_glyph::Font as _; let glyph_id = self.ab_glyph_font.glyph_id(c); if glyph_id.0 == 0 { None // unsupported character } else { - let glyph_info = self.allocate_glyph(glyph_id); - self.glyph_info_cache.write().insert(c, glyph_info); + 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) } } #[inline] - pub fn pair_kerning( + pub(super) fn pair_kerning_pixels( &self, + metrics: &ScaledMetrics, last_glyph_id: ab_glyph::GlyphId, glyph_id: ab_glyph::GlyphId, ) -> f32 { - use ab_glyph::{Font as _, ScaleFont as _}; - self.ab_glyph_font - .as_scaled(self.scale_in_pixels as f32) - .kern(last_glyph_id, glyph_id) - / self.pixels_per_point + self.ab_glyph_font.kern_unscaled(last_glyph_id, glyph_id) * metrics.px_scale_factor } - /// Height of one row of text in points. - /// - /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - #[inline(always)] - pub fn row_height(&self) -> f32 { - self.height_in_points + #[inline] + pub fn pair_kerning( + &self, + metrics: &ScaledMetrics, + last_glyph_id: ab_glyph::GlyphId, + glyph_id: ab_glyph::GlyphId, + ) -> f32 { + self.pair_kerning_pixels(metrics, last_glyph_id, glyph_id) / metrics.pixels_per_point } #[inline(always)] - pub fn pixels_per_point(&self) -> f32 { - self.pixels_per_point + 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 scale = font_size * self.tweak.scale * pixels_per_point; + let px_scale_factor = self.ab_glyph_font.px_scale_factor(scale); + + let y_offset_in_points = ((font_size * self.tweak.scale * self.tweak.y_offset_factor) + + self.tweak.y_offset) + .round_ui(); + + ScaledMetrics { + pixels_per_point, + px_scale_factor, + y_offset_in_points, + ascent, + row_height: ascent - descent + line_gap, + } } - /// This is the distance from the top to the baseline. - /// - /// Unit: points. - #[inline(always)] - pub fn ascent(&self) -> f32 { - self.ascent - } + pub fn allocate_glyph( + &mut self, + atlas: &mut TextureAtlas, + metrics: &ScaledMetrics, + glyph_info: GlyphInfo, + chr: char, + h_pos: f32, + ) -> (GlyphAllocation, i32) { + let advance_width_px = glyph_info.advance_width_unscaled.0 * metrics.px_scale_factor; - fn allocate_glyph(&self, glyph_id: ab_glyph::GlyphId) -> GlyphInfo { - assert!(glyph_id.0 != 0, "Can't allocate glyph for id 0"); - use ab_glyph::{Font as _, ScaleFont as _}; + let Some(glyph_id) = glyph_info.id else { + // Invisible. + return (GlyphAllocation::default(), h_pos as i32); + }; - let glyph = glyph_id.with_scale_and_position( - self.scale_in_pixels as f32, - ab_glyph::Point { x: 0.0, y: 0.0 }, - ); + // CJK scripts contain a lot of characters and could hog the glyph atlas if we stored 4 subpixel offsets per + // glyph. + let (h_pos_round, bin) = if is_cjk(chr) { + (h_pos.round() as i32, SubpixelBin::Zero) + } else { + SubpixelBin::new(h_pos) + }; - let uv_rect = self.ab_glyph_font.outline_glyph(glyph).map(|glyph| { - let bb = glyph.px_bounds(); + let entry = match self + .glyph_alloc_cache + .entry(GlyphCacheKey::new(glyph_id, metrics, bin)) + { + std::collections::hash_map::Entry::Occupied(glyph_alloc) => { + let mut glyph_alloc = *glyph_alloc.get(); + glyph_alloc.advance_width_px = advance_width_px; // Hack to get `\t` and thin space to work, since they use the same glyph id as ` ` (space). + return (glyph_alloc, h_pos_round); + } + std::collections::hash_map::Entry::Vacant(entry) => entry, + }; + + debug_assert!(glyph_id.0 != 0, "Can't allocate glyph for id 0"); + + 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 atlas = &mut self.atlas.lock(); let text_alpha_from_coverage = atlas.text_alpha_from_coverage; let (glyph_pos, image) = atlas.allocate((glyph_width, glyph_height)); - glyph.draw(|x, y, v| { + 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; @@ -292,11 +412,11 @@ impl FontImpl { }; let offset_in_pixels = vec2(bb.min.x, bb.min.y); - let offset = - offset_in_pixels / self.pixels_per_point + self.y_offset_in_points * Vec2::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) / self.pixels_per_point, + 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, @@ -307,79 +427,25 @@ impl FontImpl { }); let uv_rect = uv_rect.unwrap_or_default(); - let advance_width_in_points = self - .ab_glyph_font - .as_scaled(self.scale_in_pixels as f32) - .h_advance(glyph_id) - / self.pixels_per_point; - - GlyphInfo { + let allocation = GlyphAllocation { id: glyph_id, - advance_width: advance_width_in_points, + advance_width_px, uv_rect, - } + }; + entry.insert(allocation); + (allocation, h_pos_round) } } -type FontIndex = usize; - // TODO(emilk): rename? /// Wrapper over multiple [`FontImpl`] (e.g. a primary + fallbacks for emojis) -pub struct Font { - fonts: Vec>, - - /// Lazily calculated. - characters: Option>>, - - replacement_glyph: (FontIndex, GlyphInfo), - pixels_per_point: f32, - row_height: f32, - glyph_info_cache: ahash::HashMap, +pub struct Font<'a> { + pub(super) fonts_by_id: &'a mut nohash_hasher::IntMap, + pub(super) cached_family: &'a mut CachedFamily, + pub(super) atlas: &'a mut TextureAtlas, } -impl Font { - pub fn new(fonts: Vec>) -> Self { - if fonts.is_empty() { - return Self { - fonts, - characters: None, - replacement_glyph: Default::default(), - pixels_per_point: 1.0, - row_height: 0.0, - glyph_info_cache: Default::default(), - }; - } - - let pixels_per_point = fonts[0].pixels_per_point(); - let row_height = fonts[0].row_height(); - - let mut slf = Self { - fonts, - characters: None, - replacement_glyph: Default::default(), - pixels_per_point, - row_height, - glyph_info_cache: Default::default(), - }; - - const PRIMARY_REPLACEMENT_CHAR: char = '◻'; // white medium square - const FALLBACK_REPLACEMENT_CHAR: char = '?'; // fallback for the fallback - - let replacement_glyph = slf - .glyph_info_no_cache_or_fallback(PRIMARY_REPLACEMENT_CHAR) - .or_else(|| slf.glyph_info_no_cache_or_fallback(FALLBACK_REPLACEMENT_CHAR)) - .unwrap_or_else(|| { - #[cfg(feature = "log")] - log::warn!( - "Failed to find replacement characters {PRIMARY_REPLACEMENT_CHAR:?} or {FALLBACK_REPLACEMENT_CHAR:?}. Will use empty glyph." - ); - (0, GlyphInfo::default()) - }); - slf.replacement_glyph = replacement_glyph; - - slf - } - +impl Font<'_> { pub fn preload_characters(&mut self, s: &str) { for c in s.chars() { self.glyph_info(c); @@ -399,9 +465,10 @@ impl Font { /// All supported characters, and in which font they are available in. pub fn characters(&mut self) -> &BTreeMap> { - self.characters.get_or_insert_with(|| { + self.cached_family.characters.get_or_insert_with(|| { let mut characters: BTreeMap> = Default::default(); - for font in &self.fonts { + for font_id in &self.cached_family.fonts { + let font = self.fonts_by_id.get(font_id).expect("Nonexistent font ID"); for chr in font.characters() { characters.entry(chr).or_default().push(font.name.clone()); } @@ -410,34 +477,29 @@ impl Font { }) } - #[inline(always)] - pub fn round_to_pixel(&self, point: f32) -> f32 { - (point * self.pixels_per_point).round() / self.pixels_per_point - } - - /// Height of one row of text. In points. - /// - /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - #[inline(always)] - pub fn row_height(&self) -> f32 { - self.row_height - } - - pub fn uv_rect(&self, c: char) -> UvRect { - self.glyph_info_cache - .get(&c) - .map(|gi| gi.1.uv_rect) + pub fn scaled_metrics(&self, pixels_per_point: f32, font_size: f32) -> ScaledMetrics { + self.cached_family + .fonts + .first() + .and_then(|key| self.fonts_by_id.get(key)) + .map(|font_impl| font_impl.scaled_metrics(pixels_per_point, font_size)) .unwrap_or_default() } /// Width of this character in points. - pub fn glyph_width(&mut self, c: char) -> f32 { - self.glyph_info(c).1.advance_width + pub fn glyph_width(&mut self, c: char, font_size: f32) -> f32 { + let (key, glyph_info) = self.glyph_info(c); + let font = &self + .fonts_by_id + .get(&key) + .expect("Nonexistent font ID") + .ab_glyph_font; + glyph_info.advance_width_unscaled.0 * font.px_scale_factor(font_size) } /// Can we display this glyph? pub fn has_glyph(&mut self, c: char) -> bool { - self.glyph_info(c) != self.replacement_glyph // TODO(emilk): this is a false negative if the user asks about the replacement character itself 🤦‍♂️ + self.glyph_info(c) != self.cached_family.replacement_glyph // TODO(emilk): this is a false negative if the user asks about the replacement character itself 🤦‍♂️ } /// Can we display all the glyphs in this text? @@ -446,44 +508,46 @@ impl Font { } /// `\n` will (intentionally) show up as the replacement character. - fn glyph_info(&mut self, c: char) -> (FontIndex, GlyphInfo) { - if let Some(font_index_glyph_info) = self.glyph_info_cache.get(&c) { + pub(crate) fn glyph_info(&mut self, c: char) -> (FontFaceKey, GlyphInfo) { + if let Some(font_index_glyph_info) = self.cached_family.glyph_info_cache.get(&c) { return *font_index_glyph_info; } - let font_index_glyph_info = self.glyph_info_no_cache_or_fallback(c); - let font_index_glyph_info = font_index_glyph_info.unwrap_or(self.replacement_glyph); - self.glyph_info_cache.insert(c, font_index_glyph_info); + let font_index_glyph_info = self + .cached_family + .glyph_info_no_cache_or_fallback(c, self.fonts_by_id); + let font_index_glyph_info = + font_index_glyph_info.unwrap_or(self.cached_family.replacement_glyph); + self.cached_family + .glyph_info_cache + .insert(c, font_index_glyph_info); font_index_glyph_info } +} - #[inline] - pub(crate) fn font_impl_and_glyph_info(&mut self, c: char) -> (Option<&FontImpl>, GlyphInfo) { - if self.fonts.is_empty() { - return (None, self.replacement_glyph.1); - } - let (font_index, glyph_info) = self.glyph_info(c); - let font_impl = &self.fonts[font_index]; - (Some(font_impl), glyph_info) - } +/// Metrics for a font at a specific screen-space scale. +#[derive(Clone, Copy, Debug, PartialEq, Default)] +pub struct ScaledMetrics { + /// The DPI part of the screen-space scale. + pub pixels_per_point: f32, - pub(crate) fn ascent(&self) -> f32 { - if let Some(first) = self.fonts.first() { - first.ascent() - } else { - self.row_height - } - } + /// Scale factor, relative to the font's units per em (so, probably much less than 1). + /// + /// Translates "unscaled" units to physical (screen) pixels. + pub px_scale_factor: f32, - fn glyph_info_no_cache_or_fallback(&mut self, c: char) -> Option<(FontIndex, GlyphInfo)> { - for (font_index, font_impl) in self.fonts.iter().enumerate() { - if let Some(glyph_info) = font_impl.glyph_info(c) { - self.glyph_info_cache.insert(c, (font_index, glyph_info)); - return Some((font_index, glyph_info)); - } - } - None - } + /// Vertical offset, in UI points. + pub y_offset_in_points: f32, + + /// This is the distance from the top to the baseline. + /// + /// Unit: points. + pub ascent: f32, + + /// Height of one row of text in points. + /// + /// Returns a value rounded to [`emath::GUI_ROUNDING`]. + pub row_height: f32, } /// Code points that will always be invisible (zero width). @@ -532,3 +596,28 @@ fn invisible_char(c: char) -> bool { | '\u{FEFF}' // ZERO WIDTH NO-BREAK SPACE ) } + +#[inline] +pub(super) fn is_cjk_ideograph(c: char) -> bool { + ('\u{4E00}' <= c && c <= '\u{9FFF}') + || ('\u{3400}' <= c && c <= '\u{4DBF}') + || ('\u{2B740}' <= c && c <= '\u{2B81F}') +} + +#[inline] +pub(super) fn is_kana(c: char) -> bool { + ('\u{3040}' <= c && c <= '\u{309F}') // Hiragana block + || ('\u{30A0}' <= c && c <= '\u{30FF}') // Katakana block +} + +#[inline] +pub(super) fn is_cjk(c: char) -> bool { + // TODO(bigfarts): Add support for Korean Hangul. + is_cjk_ideograph(c) || is_kana(c) +} + +#[inline] +pub(super) fn is_cjk_break_allowed(c: char) -> bool { + // See: https://en.wikipedia.org/wiki/Line_breaking_rules_in_East_Asian_languages#Characters_not_permitted_on_the_start_of_a_line. + !")]}〕〉》」』】〙〗〟'\"⦆»ヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻‐゠–〜?!‼⁇⁈⁉・、:;,。.".contains(c) +} diff --git a/crates/epaint/src/text/fonts.rs b/crates/epaint/src/text/fonts.rs index f9c1f4f8..a78242fd 100644 --- a/crates/epaint/src/text/fonts.rs +++ b/crates/epaint/src/text/fonts.rs @@ -1,11 +1,16 @@ -use std::{collections::BTreeMap, sync::Arc}; +use std::{ + collections::BTreeMap, + sync::{ + Arc, + atomic::{AtomicU64, Ordering}, + }, +}; use crate::{ AlphaFromCoverage, TextureAtlas, - mutex::{Mutex, MutexGuard}, text::{ Galley, LayoutJob, LayoutSection, - font::{Font, FontImpl}, + font::{Font, FontImpl, GlyphInfo}, }, }; use emath::{NumExt as _, OrderedFloat}; @@ -179,13 +184,6 @@ pub struct FontTweak { /// /// Example value: `2.0`. pub y_offset: f32, - - /// When using this font's metrics to layout a row, - /// shift the entire row downwards by this fraction of the font size (in points). - /// - /// A positive value shifts the text downwards. - /// A negative value shifts it upwards. - pub baseline_offset_factor: f32, } impl Default for FontTweak { @@ -194,7 +192,6 @@ impl Default for FontTweak { scale: 1.0, y_offset_factor: 0.0, y_offset: 0.0, - baseline_offset_factor: 0.0, } } } @@ -407,6 +404,92 @@ impl FontDefinitions { } } +/// Unique ID for looking up a single font face/file. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub(crate) struct FontFaceKey(u64); + +impl FontFaceKey { + pub const INVALID: Self = Self(0); + + fn new() -> Self { + static KEY_COUNTER: AtomicU64 = AtomicU64::new(1); + Self(crate::util::hash( + KEY_COUNTER.fetch_add(1, Ordering::Relaxed), + )) + } +} + +// Safe, because we hash the value in the constructor. +impl nohash_hasher::IsEnabled for FontFaceKey {} + +/// Cached data for working with a font family (e.g. doing character lookups). +#[derive(Debug)] +pub(super) struct CachedFamily { + pub fonts: Vec, + + /// Lazily calculated. + pub characters: Option>>, + + pub replacement_glyph: (FontFaceKey, GlyphInfo), + + pub glyph_info_cache: ahash::HashMap, +} + +impl CachedFamily { + fn new( + fonts: Vec, + fonts_by_id: &mut nohash_hasher::IntMap, + ) -> Self { + if fonts.is_empty() { + return Self { + fonts, + characters: None, + replacement_glyph: (FontFaceKey::INVALID, GlyphInfo::INVISIBLE), + glyph_info_cache: Default::default(), + }; + } + + let mut slf = Self { + fonts, + characters: None, + replacement_glyph: (FontFaceKey::INVALID, GlyphInfo::INVISIBLE), + glyph_info_cache: Default::default(), + }; + + const PRIMARY_REPLACEMENT_CHAR: char = '◻'; // white medium square + const FALLBACK_REPLACEMENT_CHAR: char = '?'; // fallback for the fallback + + let replacement_glyph = slf + .glyph_info_no_cache_or_fallback(PRIMARY_REPLACEMENT_CHAR, fonts_by_id) + .or_else(|| slf.glyph_info_no_cache_or_fallback(FALLBACK_REPLACEMENT_CHAR, fonts_by_id)) + .unwrap_or_else(|| { + #[cfg(feature = "log")] + log::warn!( + "Failed to find replacement characters {PRIMARY_REPLACEMENT_CHAR:?} or {FALLBACK_REPLACEMENT_CHAR:?}. Will use empty glyph." + ); + (FontFaceKey::INVALID, GlyphInfo::INVISIBLE) + }); + slf.replacement_glyph = replacement_glyph; + + slf + } + + pub(crate) fn glyph_info_no_cache_or_fallback( + &mut self, + c: char, + 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) { + self.glyph_info_cache.insert(c, (*font_key, glyph_info)); + return Some((*font_key, glyph_info)); + } + } + None + } +} + // ---------------------------------------------------------------------------- /// The collection of fonts used by `epaint`. @@ -418,31 +501,25 @@ impl FontDefinitions { /// If you are using `egui`, use `egui::Context::set_fonts` and `egui::Context::fonts`. /// /// You need to call [`Self::begin_pass`] and [`Self::font_image_delta`] once every frame. -#[derive(Clone)] -pub struct Fonts(Arc>); +pub struct Fonts { + pub fonts: FontsImpl, + galley_cache: GalleyCache, +} impl Fonts { /// Create a new [`Fonts`] for text layout. /// This call is expensive, so only create one [`Fonts`] and then reuse it. /// - /// * `pixels_per_point`: how many physical pixels per logical "point". /// * `max_texture_side`: largest supported texture size (one side). pub fn new( - pixels_per_point: f32, max_texture_side: usize, text_alpha_from_coverage: AlphaFromCoverage, definitions: FontDefinitions, ) -> Self { - let fonts_and_cache = FontsAndCache { - fonts: FontsImpl::new( - pixels_per_point, - max_texture_side, - text_alpha_from_coverage, - definitions, - ), + Self { + fonts: FontsImpl::new(max_texture_side, text_alpha_from_coverage, definitions), galley_cache: Default::default(), - }; - Self(Arc::new(Mutex::new(fonts_and_cache))) + } } /// Call at the start of each frame with the latest known @@ -453,114 +530,156 @@ impl Fonts { /// This function will react to changes in `pixels_per_point`, `max_texture_side`, and `text_alpha_from_coverage`, /// as well as notice when the font atlas is getting full, and handle that. pub fn begin_pass( - &self, - pixels_per_point: f32, + &mut self, max_texture_side: usize, text_alpha_from_coverage: AlphaFromCoverage, ) { - let mut fonts_and_cache = self.0.lock(); - - let pixels_per_point_changed = fonts_and_cache.fonts.pixels_per_point != pixels_per_point; - let max_texture_side_changed = fonts_and_cache.fonts.max_texture_side != max_texture_side; + let max_texture_side_changed = self.fonts.max_texture_side != max_texture_side; let text_alpha_from_coverage_changed = - fonts_and_cache.fonts.atlas.lock().text_alpha_from_coverage != text_alpha_from_coverage; - let font_atlas_almost_full = fonts_and_cache.fonts.atlas.lock().fill_ratio() > 0.8; - let needs_recreate = pixels_per_point_changed - || max_texture_side_changed - || text_alpha_from_coverage_changed - || font_atlas_almost_full; + self.fonts.atlas.text_alpha_from_coverage != text_alpha_from_coverage; + 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; if needs_recreate { - let definitions = fonts_and_cache.fonts.definitions.clone(); + let definitions = self.fonts.definitions.clone(); - *fonts_and_cache = FontsAndCache { - fonts: FontsImpl::new( - pixels_per_point, - max_texture_side, - text_alpha_from_coverage, - definitions, - ), + *self = Self { + fonts: FontsImpl::new(max_texture_side, text_alpha_from_coverage, definitions), galley_cache: Default::default(), }; } - fonts_and_cache.galley_cache.flush_cache(); + self.galley_cache.flush_cache(); } /// Call at the end of each frame (before painting) to get the change to the font texture since last call. - pub fn font_image_delta(&self) -> Option { - self.lock().fonts.atlas.lock().take_delta() - } - - /// Access the underlying [`FontsAndCache`]. - #[doc(hidden)] - #[inline] - pub fn lock(&self) -> MutexGuard<'_, FontsAndCache> { - self.0.lock() - } - - #[inline] - pub fn pixels_per_point(&self) -> f32 { - self.lock().fonts.pixels_per_point + pub fn font_image_delta(&mut self) -> Option { + self.fonts.atlas.take_delta() } #[inline] pub fn max_texture_side(&self) -> usize { - self.lock().fonts.max_texture_side + self.fonts.max_texture_side + } + + #[inline] + pub fn definitions(&self) -> &FontDefinitions { + &self.fonts.definitions } /// The font atlas. /// Pass this to [`crate::Tessellator`]. - pub fn texture_atlas(&self) -> Arc> { - self.lock().fonts.atlas.clone() + pub fn texture_atlas(&self) -> &TextureAtlas { + &self.fonts.atlas } /// The full font atlas image. #[inline] pub fn image(&self) -> crate::ColorImage { - self.lock().fonts.atlas.lock().image().clone() + self.fonts.atlas.image().clone() } /// Current size of the font image. /// Pass this to [`crate::Tessellator`]. pub fn font_image_size(&self) -> [usize; 2] { - self.lock().fonts.atlas.lock().size() - } - - /// Width of this character in points. - #[inline] - pub fn glyph_width(&self, font_id: &FontId, c: char) -> f32 { - self.lock().fonts.glyph_width(font_id, c) + self.fonts.atlas.size() } /// Can we display this glyph? - #[inline] - pub fn has_glyph(&self, font_id: &FontId, c: char) -> bool { - self.lock().fonts.has_glyph(font_id, c) + pub fn has_glyph(&mut self, font_id: &FontId, c: char) -> bool { + self.fonts.font(&font_id.family).has_glyph(c) } /// Can we display all the glyphs in this text? - pub fn has_glyphs(&self, font_id: &FontId, s: &str) -> bool { - self.lock().fonts.has_glyphs(font_id, s) + pub fn has_glyphs(&mut self, font_id: &FontId, s: &str) -> bool { + self.fonts.font(&font_id.family).has_glyphs(s) + } + + pub fn num_galleys_in_cache(&self) -> usize { + self.galley_cache.num_galleys_in_cache() + } + + /// How full is the font atlas? + /// + /// This increases as new fonts and/or glyphs are used, + /// but can also decrease in a call to [`Self::begin_pass`]. + pub fn font_atlas_fill_ratio(&self) -> f32 { + self.fonts.atlas.fill_ratio() + } + + /// Returns a [`FontsView`] with the given `pixels_per_point` that can be used to do text layout. + pub fn with_pixels_per_point(&mut self, pixels_per_point: f32) -> FontsView<'_> { + FontsView { + fonts: &mut self.fonts, + galley_cache: &mut self.galley_cache, + pixels_per_point, + } + } +} + +// ---------------------------------------------------------------------------- + +/// The context's collection of fonts, with this context's `pixels_per_point`. This is what you use to do text layout. +pub struct FontsView<'a> { + pub fonts: &'a mut FontsImpl, + galley_cache: &'a mut GalleyCache, + pixels_per_point: f32, +} + +impl FontsView<'_> { + #[inline] + pub fn max_texture_side(&self) -> usize { + self.fonts.max_texture_side + } + + #[inline] + pub fn definitions(&self) -> &FontDefinitions { + &self.fonts.definitions + } + + /// The full font atlas image. + #[inline] + pub fn image(&self) -> crate::ColorImage { + self.fonts.atlas.image().clone() + } + + /// Current size of the font image. + /// Pass this to [`crate::Tessellator`]. + pub fn font_image_size(&self) -> [usize; 2] { + self.fonts.atlas.size() + } + + /// Width of this character in points. + pub fn glyph_width(&mut self, font_id: &FontId, c: char) -> f32 { + self.fonts + .font(&font_id.family) + .glyph_width(c, font_id.size) + } + + /// Can we display this glyph? + pub fn has_glyph(&mut self, font_id: &FontId, c: char) -> bool { + self.fonts.font(&font_id.family).has_glyph(c) + } + + /// Can we display all the glyphs in this text? + pub fn has_glyphs(&mut self, font_id: &FontId, s: &str) -> bool { + self.fonts.font(&font_id.family).has_glyphs(s) } /// Height of one row of text in points. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - #[inline] - pub fn row_height(&self, font_id: &FontId) -> f32 { - self.lock().fonts.row_height(font_id) + pub fn row_height(&mut self, font_id: &FontId) -> f32 { + self.fonts + .font(&font_id.family) + .scaled_metrics(self.pixels_per_point, font_id.size) + .row_height } /// List of all known font families. pub fn families(&self) -> Vec { - self.lock() - .fonts - .definitions - .families - .keys() - .cloned() - .collect() + self.fonts.definitions.families.keys().cloned().collect() } /// Layout some text. @@ -571,27 +690,33 @@ impl Fonts { /// /// The implementation uses memoization so repeated calls are cheap. #[inline] - pub fn layout_job(&self, job: LayoutJob) -> Arc { - self.lock().layout_job(job) + pub fn layout_job(&mut self, job: LayoutJob) -> Arc { + let allow_split_paragraphs = true; // Optimization for editing text with many paragraphs. + self.galley_cache.layout( + self.fonts, + self.pixels_per_point, + job, + allow_split_paragraphs, + ) } pub fn num_galleys_in_cache(&self) -> usize { - self.lock().galley_cache.num_galleys_in_cache() + self.galley_cache.num_galleys_in_cache() } /// How full is the font atlas? /// /// This increases as new fonts and/or glyphs are used, - /// but can also decrease in a call to [`Self::begin_pass`]. + /// but can also decrease in a call to [`Fonts::begin_pass`]. pub fn font_atlas_fill_ratio(&self) -> f32 { - self.lock().fonts.atlas.lock().fill_ratio() + self.fonts.atlas.fill_ratio() } /// Will wrap text at the given width and line break at `\n`. /// /// The implementation uses memoization so repeated calls are cheap. pub fn layout( - &self, + &mut self, text: String, font_id: FontId, color: crate::Color32, @@ -605,7 +730,7 @@ impl Fonts { /// /// The implementation uses memoization so repeated calls are cheap. pub fn layout_no_wrap( - &self, + &mut self, text: String, font_id: FontId, color: crate::Color32, @@ -618,7 +743,7 @@ impl Fonts { /// /// The implementation uses memoization so repeated calls are cheap. pub fn layout_delayed_color( - &self, + &mut self, text: String, font_id: FontId, wrap_width: f32, @@ -629,118 +754,75 @@ impl Fonts { // ---------------------------------------------------------------------------- -pub struct FontsAndCache { - pub fonts: FontsImpl, - galley_cache: GalleyCache, -} - -impl FontsAndCache { - fn layout_job(&mut self, job: LayoutJob) -> Arc { - let allow_split_paragraphs = true; // Optimization for editing text with many paragraphs. - self.galley_cache - .layout(&mut self.fonts, job, allow_split_paragraphs) - } -} - -// ---------------------------------------------------------------------------- - /// The collection of fonts used by `epaint`. /// /// Required in order to paint text. pub struct FontsImpl { - pixels_per_point: f32, max_texture_side: usize, definitions: FontDefinitions, - atlas: Arc>, - font_impl_cache: FontImplCache, - sized_family: ahash::HashMap<(OrderedFloat, FontFamily), Font>, + atlas: TextureAtlas, + fonts_by_id: nohash_hasher::IntMap, + fonts_by_name: ahash::HashMap, + family_cache: ahash::HashMap, } 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( - pixels_per_point: f32, max_texture_side: usize, text_alpha_from_coverage: AlphaFromCoverage, definitions: FontDefinitions, ) -> Self { - assert!( - 0.0 < pixels_per_point && pixels_per_point < 100.0, - "pixels_per_point out of range: {pixels_per_point}" - ); - let texture_width = 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 = Arc::new(Mutex::new(atlas)); - - let font_impl_cache = - FontImplCache::new(atlas.clone(), pixels_per_point, &definitions.font_data); + let mut fonts_by_id: nohash_hasher::IntMap = Default::default(); + let mut font_impls: 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 key = FontFaceKey::new(); + fonts_by_id.insert(key, font_impl); + font_impls.insert(name.clone(), key); + } Self { - pixels_per_point, max_texture_side, definitions, atlas, - font_impl_cache, - sized_family: Default::default(), + fonts_by_id, + fonts_by_name: font_impls, + family_cache: Default::default(), } } - #[inline(always)] - pub fn pixels_per_point(&self) -> f32 { - self.pixels_per_point - } + /// 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(|| { + let fonts = &self.definitions.families.get(family); + let fonts = + fonts.unwrap_or_else(|| panic!("FontFamily::{family:?} is not bound to any fonts")); - #[inline] - pub fn definitions(&self) -> &FontDefinitions { - &self.definitions - } + let fonts: Vec = fonts + .iter() + .map(|font_name| { + *self + .fonts_by_name + .get(font_name) + .unwrap_or_else(|| panic!("No font data found for {font_name:?}")) + }) + .collect(); - /// Get the right font implementation from size and [`FontFamily`]. - pub fn font(&mut self, font_id: &FontId) -> &mut Font { - let FontId { size, family } = font_id; - let mut size = *size; - size = size.at_least(0.1).at_most(2048.0); - - self.sized_family - .entry((OrderedFloat(size), family.clone())) - .or_insert_with(|| { - let fonts = &self.definitions.families.get(family); - let fonts = fonts - .unwrap_or_else(|| panic!("FontFamily::{family:?} is not bound to any fonts")); - - let fonts: Vec> = fonts - .iter() - .map(|font_name| self.font_impl_cache.font_impl(size, font_name)) - .collect(); - - Font::new(fonts) - }) - } - - /// Width of this character in points. - fn glyph_width(&mut self, font_id: &FontId, c: char) -> f32 { - self.font(font_id).glyph_width(c) - } - - /// Can we display this glyph? - pub fn has_glyph(&mut self, font_id: &FontId, c: char) -> bool { - self.font(font_id).has_glyph(c) - } - - /// Can we display all the glyphs in this text? - pub fn has_glyphs(&mut self, font_id: &FontId, s: &str) -> bool { - self.font(font_id).has_glyphs(s) - } - - /// Height of one row of text in points. - /// - /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - fn row_height(&mut self, font_id: &FontId) -> f32 { - self.font(font_id).row_height() + CachedFamily::new(fonts, &mut self.fonts_by_id) + }); + Font { + fonts_by_id: &mut self.fonts_by_id, + cached_family, + atlas: &mut self.atlas, + } } } @@ -770,6 +852,7 @@ impl GalleyCache { &mut self, fonts: &mut FontsImpl, mut job: LayoutJob, + pixels_per_point: f32, allow_split_paragraphs: bool, ) -> (u64, Arc) { if job.wrap.max_width.is_finite() { @@ -797,7 +880,7 @@ impl GalleyCache { job.wrap.max_width = job.wrap.max_width.round(); } - let hash = crate::util::hash(&job); // TODO(emilk): even faster hasher? + let hash = crate::util::hash((&job, OrderedFloat(pixels_per_point))); // TODO(emilk): even faster hasher? let galley = match self.cache.entry(hash) { std::collections::hash_map::Entry::Occupied(entry) => { @@ -825,14 +908,13 @@ impl GalleyCache { let job = Arc::new(job); if allow_split_paragraphs && should_cache_each_paragraph_individually(&job) { let (child_galleys, child_hashes) = - self.layout_each_paragraph_individually(fonts, &job); + self.layout_each_paragraph_individually(fonts, &job, pixels_per_point); debug_assert_eq!( child_hashes.len(), child_galleys.len(), "Bug in `layout_each_paragraph_individuallly`" ); - let galley = - Arc::new(Galley::concat(job, &child_galleys, fonts.pixels_per_point)); + let galley = Arc::new(Galley::concat(job, &child_galleys, pixels_per_point)); self.cache.insert( hash, @@ -844,7 +926,7 @@ impl GalleyCache { ); galley } else { - let galley = super::layout(fonts, job); + let galley = super::layout(fonts, pixels_per_point, job); let galley = Arc::new(galley); entry.insert(CachedGalley { last_used: self.generation, @@ -862,10 +944,12 @@ impl GalleyCache { fn layout( &mut self, fonts: &mut FontsImpl, + pixels_per_point: f32, job: LayoutJob, allow_split_paragraphs: bool, ) -> Arc { - self.layout_internal(fonts, job, allow_split_paragraphs).1 + self.layout_internal(fonts, job, pixels_per_point, allow_split_paragraphs) + .1 } /// Split on `\n` and lay out (and cache) each paragraph individually. @@ -873,6 +957,7 @@ impl GalleyCache { &mut self, fonts: &mut FontsImpl, job: &LayoutJob, + pixels_per_point: f32, ) -> (Vec>, Vec) { profiling::function_scope!(); @@ -952,7 +1037,8 @@ impl GalleyCache { } // TODO(emilk): we could lay out each paragraph in parallel to get a nice speedup on multicore machines. - let (hash, galley) = self.layout_internal(fonts, paragraph_job, false); + let (hash, galley) = + self.layout_internal(fonts, paragraph_job, pixels_per_point, false); child_hashes.push(hash); // This will prevent us from invalidating cache entries unnecessarily: @@ -996,77 +1082,6 @@ fn should_cache_each_paragraph_individually(job: &LayoutJob) -> bool { job.break_on_newline && job.wrap.max_rows == usize::MAX && job.text.contains('\n') } -// ---------------------------------------------------------------------------- - -struct FontImplCache { - atlas: Arc>, - pixels_per_point: f32, - ab_glyph_fonts: BTreeMap, - - /// Map font pixel sizes and names to the cached [`FontImpl`]. - cache: ahash::HashMap<(u32, String), Arc>, -} - -impl FontImplCache { - pub fn new( - atlas: Arc>, - pixels_per_point: f32, - font_data: &BTreeMap>, - ) -> Self { - let ab_glyph_fonts = font_data - .iter() - .map(|(name, font_data)| { - let tweak = font_data.tweak; - let ab_glyph = ab_glyph_font_from_font_data(name, font_data); - (name.clone(), (tweak, ab_glyph)) - }) - .collect(); - - Self { - atlas, - pixels_per_point, - ab_glyph_fonts, - cache: Default::default(), - } - } - - pub fn font_impl(&mut self, scale_in_points: f32, font_name: &str) -> Arc { - use ab_glyph::Font as _; - - let (tweak, ab_glyph_font) = self - .ab_glyph_fonts - .get(font_name) - .unwrap_or_else(|| panic!("No font data found for {font_name:?}")) - .clone(); - - let scale_in_pixels = self.pixels_per_point * scale_in_points; - - // Scale the font properly (see https://github.com/emilk/egui/issues/2068). - let units_per_em = ab_glyph_font.units_per_em().unwrap_or_else(|| { - panic!("The font unit size of {font_name:?} exceeds the expected range (16..=16384)") - }); - let font_scaling = ab_glyph_font.height_unscaled() / units_per_em; - let scale_in_pixels = scale_in_pixels * font_scaling; - - self.cache - .entry(( - (scale_in_pixels * tweak.scale).round() as u32, - font_name.to_owned(), - )) - .or_insert_with(|| { - Arc::new(FontImpl::new( - self.atlas.clone(), - self.pixels_per_point, - font_name.to_owned(), - ab_glyph_font, - scale_in_pixels, - tweak, - )) - }) - .clone() - } -} - #[cfg(feature = "default_fonts")] #[cfg(test)] mod tests { @@ -1178,7 +1193,6 @@ mod tests { for pixels_per_point in [1.0, 2.0_f32.sqrt(), 2.0] { let max_texture_side = 4096; let mut fonts = FontsImpl::new( - pixels_per_point, max_texture_side, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -1190,9 +1204,19 @@ mod tests { job.halign = halign; job.justify = justify; - let whole = GalleyCache::default().layout(&mut fonts, job.clone(), false); + let whole = GalleyCache::default().layout( + &mut fonts, + pixels_per_point, + job.clone(), + false, + ); - let split = GalleyCache::default().layout(&mut fonts, job.clone(), true); + let split = GalleyCache::default().layout( + &mut fonts, + pixels_per_point, + job.clone(), + true, + ); for (i, row) in whole.rows.iter().enumerate() { println!( @@ -1231,7 +1255,6 @@ mod tests { for pixels_per_point in pixels_per_point { let mut fonts = FontsImpl::new( - pixels_per_point, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -1244,12 +1267,13 @@ mod tests { job.round_output_to_gui = round_output_to_gui; - let galley_wrapped = layout(&mut fonts, job.clone().into()); + let galley_wrapped = + layout(&mut fonts, pixels_per_point, job.clone().into()); job.wrap = TextWrapping::no_max_width(); let text = job.text.clone(); - let galley_unwrapped = layout(&mut fonts, job.into()); + let galley_unwrapped = layout(&mut fonts, pixels_per_point, job.into()); let intrinsic_size = galley_wrapped.intrinsic_size(); let unwrapped_size = galley_unwrapped.size(); diff --git a/crates/epaint/src/text/mod.rs b/crates/epaint/src/text/mod.rs index cf5c8ebf..e0f4a3a9 100644 --- a/crates/epaint/src/text/mod.rs +++ b/crates/epaint/src/text/mod.rs @@ -12,7 +12,7 @@ pub const TAB_SIZE: usize = 4; pub use { fonts::{ FontData, FontDefinitions, FontFamily, FontId, FontInsert, FontPriority, FontTweak, Fonts, - FontsImpl, InsertFontFamily, + FontsImpl, FontsView, InsertFontFamily, }, text_layout::*, text_layout_types::*, diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs index fd71506e..e65f1070 100644 --- a/crates/epaint/src/text/text_layout.rs +++ b/crates/epaint/src/text/text_layout.rs @@ -2,7 +2,14 @@ use std::sync::Arc; use emath::{Align, GuiRounding as _, NumExt as _, Pos2, Rect, Vec2, pos2, vec2}; -use crate::{Color32, Mesh, Stroke, Vertex, stroke::PathStroke, text::font::Font}; +use crate::{ + Color32, Mesh, Stroke, Vertex, + stroke::PathStroke, + text::{ + font::{ScaledMetrics, is_cjk, is_cjk_break_allowed}, + fonts::FontFaceKey, + }, +}; use super::{FontsImpl, Galley, Glyph, LayoutJob, LayoutSection, PlacedRow, Row, RowVisuals}; @@ -41,8 +48,8 @@ impl PointScale { /// Temporary storage before line-wrapping. #[derive(Clone)] struct Paragraph { - /// Start of the next glyph to be added. - pub cursor_x: f32, + /// Start of the next glyph to be added. In screen-space / physical pixels. + pub cursor_x_px: f32, /// This is included in case there are no glyphs pub section_index_at_start: u32, @@ -56,7 +63,7 @@ struct Paragraph { impl Paragraph { pub fn from_section_index(section_index_at_start: u32) -> Self { Self { - cursor_x: 0.0, + cursor_x_px: 0.0, section_index_at_start, glyphs: vec![], empty_paragraph_height: 0.0, @@ -66,9 +73,9 @@ impl Paragraph { /// Layout text into a [`Galley`]. /// -/// In most cases you should use [`crate::Fonts::layout_job`] instead +/// In most cases you should use [`crate::FontsView::layout_job`] instead /// since that memoizes the input, making subsequent layouting of the same text much faster. -pub fn layout(fonts: &mut FontsImpl, job: Arc) -> Galley { +pub fn layout(fonts: &mut FontsImpl, pixels_per_point: f32, job: Arc) -> Galley { profiling::function_scope!(); if job.wrap.max_rows == 0 { @@ -80,7 +87,7 @@ pub fn layout(fonts: &mut FontsImpl, job: Arc) -> Galley { mesh_bounds: Rect::NOTHING, num_vertices: 0, num_indices: 0, - pixels_per_point: fonts.pixels_per_point(), + pixels_per_point, elided: true, intrinsic_size: Vec2::ZERO, }; @@ -90,10 +97,17 @@ pub fn layout(fonts: &mut FontsImpl, job: Arc) -> Galley { let mut paragraphs = vec![Paragraph::from_section_index(0)]; for (section_index, section) in job.sections.iter().enumerate() { - layout_section(fonts, &job, section_index as u32, section, &mut paragraphs); + layout_section( + fonts, + pixels_per_point, + &job, + section_index as u32, + section, + &mut paragraphs, + ); } - let point_scale = PointScale::new(fonts.pixels_per_point()); + let point_scale = PointScale::new(pixels_per_point); let intrinsic_size = calculate_intrinsic_size(point_scale, &job, ¶graphs); @@ -102,7 +116,7 @@ pub fn layout(fonts: &mut FontsImpl, job: Arc) -> Galley { if elided { if let Some(last_placed) = rows.last_mut() { let last_row = Arc::make_mut(&mut last_placed.row); - replace_last_glyph_with_overflow_character(fonts, &job, last_row); + replace_last_glyph_with_overflow_character(fonts, pixels_per_point, &job, last_row); if let Some(last) = last_row.glyphs.last() { last_row.size.x = last.max_x(); } @@ -133,6 +147,7 @@ pub fn layout(fonts: &mut FontsImpl, job: Arc) -> Galley { // Ignores the Y coordinate. fn layout_section( fonts: &mut FontsImpl, + pixels_per_point: f32, job: &LayoutJob, section_index: u32, section: &LayoutSection, @@ -143,11 +158,13 @@ fn layout_section( byte_range, format, } = section; - let font = fonts.font(&format.font_id); + let mut font = fonts.font(&format.font_id.family); + let font_size = format.font_id.size; + let font_metrics = font.scaled_metrics(pixels_per_point, font_size); let line_height = section .format .line_height - .unwrap_or_else(|| font.row_height()); + .unwrap_or(font_metrics.row_height); let extra_letter_spacing = section.format.extra_letter_spacing; let mut paragraph = out_paragraphs.last_mut().unwrap(); @@ -155,40 +172,70 @@ fn layout_section( paragraph.empty_paragraph_height = line_height; // TODO(emilk): replace this hack with actually including `\n` in the glyphs? } - paragraph.cursor_x += leading_space; + paragraph.cursor_x_px += leading_space * pixels_per_point; let mut last_glyph_id = None; + // Optimization: only recompute `ScaledMetrics` when the concrete `FontImpl` changes. + let mut current_font = FontFaceKey::INVALID; + let mut current_font_impl_metrics = ScaledMetrics::default(); + for chr in job.text[byte_range.clone()].chars() { if job.break_on_newline && chr == '\n' { out_paragraphs.push(Paragraph::from_section_index(section_index)); paragraph = out_paragraphs.last_mut().unwrap(); paragraph.empty_paragraph_height = line_height; // TODO(emilk): replace this hack with actually including `\n` in the glyphs? } else { - let (font_impl, glyph_info) = font.font_impl_and_glyph_info(chr); - if let Some(font_impl) = font_impl { - if let Some(last_glyph_id) = last_glyph_id { - paragraph.cursor_x += font_impl.pair_kerning(last_glyph_id, glyph_info.id); - paragraph.cursor_x += extra_letter_spacing; - } + let (font_id, glyph_info) = font.glyph_info(chr); + let mut font_impl = font.fonts_by_id.get_mut(&font_id); + if current_font != font_id { + current_font = font_id; + current_font_impl_metrics = font_impl + .as_ref() + .map(|font_impl| font_impl.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) + { + paragraph.cursor_x_px += font_impl.pair_kerning_pixels( + ¤t_font_impl_metrics, + last_glyph_id, + glyph_id, + ); + + // Only apply extra_letter_spacing to glyphs after the first one: + 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( + font.atlas, + ¤t_font_impl_metrics, + glyph_info, + chr, + paragraph.cursor_x_px, + ) + } else { + Default::default() + }; + paragraph.glyphs.push(Glyph { chr, - pos: pos2(paragraph.cursor_x, f32::NAN), - advance_width: glyph_info.advance_width, + 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: font_impl.map_or(0.0, |f| f.row_height()), - font_impl_ascent: font_impl.map_or(0.0, |f| f.ascent()), - font_height: font.row_height(), - font_ascent: font.ascent(), - uv_rect: glyph_info.uv_rect, + font_impl_height: current_font_impl_metrics.row_height, + font_impl_ascent: current_font_impl_metrics.ascent, + font_height: font_metrics.row_height, + font_ascent: font_metrics.ascent, + uv_rect: glyph_alloc.uv_rect, section_index, }); - paragraph.cursor_x += glyph_info.advance_width; - paragraph.cursor_x = font.round_to_pixel(paragraph.cursor_x); - last_glyph_id = Some(glyph_info.id); + paragraph.cursor_x_px += glyph_alloc.advance_width_px; + last_glyph_id = Some(glyph_alloc.id); } } } @@ -398,149 +445,105 @@ fn line_break( /// Called before we have any Y coordinates. fn replace_last_glyph_with_overflow_character( fonts: &mut FontsImpl, + pixels_per_point: f32, job: &LayoutJob, row: &mut Row, ) { - fn row_width(row: &Row) -> f32 { - if let (Some(first), Some(last)) = (row.glyphs.first(), row.glyphs.last()) { - last.max_x() - first.pos.x - } else { - 0.0 - } - } - - fn row_height(section: &LayoutSection, font: &Font) -> f32 { - section - .format - .line_height - .unwrap_or_else(|| font.row_height()) - } - let Some(overflow_character) = job.wrap.overflow_character else { return; }; - // We always try to just append the character first: - if let Some(last_glyph) = row.glyphs.last() { - let section_index = last_glyph.section_index; - let section = &job.sections[section_index as usize]; - let font = fonts.font(§ion.format.font_id); - let line_height = row_height(section, font); - - let (_, last_glyph_info) = font.font_impl_and_glyph_info(last_glyph.chr); - - let mut x = last_glyph.pos.x + last_glyph.advance_width; - - let (font_impl, replacement_glyph_info) = font.font_impl_and_glyph_info(overflow_character); - - { - // Kerning: - x += section.format.extra_letter_spacing; - if let Some(font_impl) = font_impl { - x += font_impl.pair_kerning(last_glyph_info.id, replacement_glyph_info.id); - } - } - - row.glyphs.push(Glyph { - chr: overflow_character, - pos: pos2(x, f32::NAN), - advance_width: replacement_glyph_info.advance_width, - line_height, - font_impl_height: font_impl.map_or(0.0, |f| f.row_height()), - font_impl_ascent: font_impl.map_or(0.0, |f| f.ascent()), - font_height: font.row_height(), - font_ascent: font.ascent(), - uv_rect: replacement_glyph_info.uv_rect, - section_index, - }); - } else { - let section_index = row.section_index_at_start; - let section = &job.sections[section_index as usize]; - let font = fonts.font(§ion.format.font_id); - let line_height = row_height(section, font); - - let x = 0.0; // TODO(emilk): heed paragraph leading_space 😬 - - let (font_impl, replacement_glyph_info) = font.font_impl_and_glyph_info(overflow_character); - - row.glyphs.push(Glyph { - chr: overflow_character, - pos: pos2(x, f32::NAN), - advance_width: replacement_glyph_info.advance_width, - line_height, - font_impl_height: font_impl.map_or(0.0, |f| f.row_height()), - font_impl_ascent: font_impl.map_or(0.0, |f| f.ascent()), - font_height: font.row_height(), - font_ascent: font.ascent(), - uv_rect: replacement_glyph_info.uv_rect, - section_index, - }); - } - - if row_width(row) <= job.effective_wrap_width() || row.glyphs.len() == 1 { - return; // we are done - } - - // We didn't fit it. Remove it again… - row.glyphs.pop(); - - // …then go into a loop where we replace the last character with the overflow character - // until we fit within the max_width: - + let mut section_index = row + .glyphs + .last() + .map(|g| g.section_index) + .unwrap_or(row.section_index_at_start); loop { - let (prev_glyph, last_glyph) = match row.glyphs.as_mut_slice() { - [.., prev, last] => (Some(prev), last), - [.., last] => (None, last), - _ => { - unreachable!("We've already explicitly handled the empty row"); - } + let section = &job.sections[section_index as usize]; + let extra_letter_spacing = section.format.extra_letter_spacing; + let mut font = fonts.font(§ion.format.font_id.family); + 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 + .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 + .as_mut() + .map(|font_impl| { + 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_impl.pair_kerning(&font_impl_metrics, prev_glyph_id, overflow_glyph_id) + } else { + 0.0 + } + }) + .unwrap_or_default(); + + prev_glyph.max_x() + extra_letter_spacing + pair_kerning + } else { + 0.0 // TODO(emilk): heed paragraph leading_space 😬 }; - let section = &job.sections[last_glyph.section_index as usize]; - let extra_letter_spacing = section.format.extra_letter_spacing; - let font = fonts.font(§ion.format.font_id); + let replacement_glyph_width = font_impl + .as_mut() + .and_then(|f| f.glyph_info(overflow_character)) + .map(|i| i.advance_width_unscaled.0 * font_impl_metrics.px_scale_factor) + .unwrap_or_default(); - if let Some(prev_glyph) = prev_glyph { - let prev_glyph_id = font.font_impl_and_glyph_info(prev_glyph.chr).1.id; + // Check if we're within width budget: + if overflow_glyph_x + replacement_glyph_width <= job.effective_wrap_width() + || row.glyphs.is_empty() + { + // we are done - // Undo kerning with previous glyph: - let (font_impl, glyph_info) = font.font_impl_and_glyph_info(last_glyph.chr); - last_glyph.pos.x -= extra_letter_spacing; - if let Some(font_impl) = font_impl { - last_glyph.pos.x -= font_impl.pair_kerning(prev_glyph_id, glyph_info.id); - } + let (replacement_glyph_alloc, physical_x) = font_impl + .as_mut() + .map(|f| { + f.allocate_glyph( + font.atlas, + &font_impl_metrics, + glyph_info, + overflow_character, + overflow_glyph_x * pixels_per_point, + ) + }) + .unwrap_or_default(); - // Replace the glyph: - last_glyph.chr = overflow_character; - let (font_impl, glyph_info) = font.font_impl_and_glyph_info(last_glyph.chr); - last_glyph.advance_width = glyph_info.advance_width; - last_glyph.font_impl_ascent = font_impl.map_or(0.0, |f| f.ascent()); - last_glyph.font_impl_height = font_impl.map_or(0.0, |f| f.row_height()); - last_glyph.uv_rect = glyph_info.uv_rect; + let font_metrics = font.scaled_metrics(pixels_per_point, font_size); + let line_height = section + .format + .line_height + .unwrap_or(font_metrics.row_height); - // Reapply kerning: - last_glyph.pos.x += extra_letter_spacing; - if let Some(font_impl) = font_impl { - last_glyph.pos.x += font_impl.pair_kerning(prev_glyph_id, glyph_info.id); - } - - // Check if we're within width budget: - if row_width(row) <= job.effective_wrap_width() || row.glyphs.len() == 1 { - return; // We are done - } - - // We didn't fit - pop the last glyph and try again. - row.glyphs.pop(); - } else { - // Just replace and be done with it. - last_glyph.chr = overflow_character; - let (font_impl, glyph_info) = font.font_impl_and_glyph_info(last_glyph.chr); - last_glyph.advance_width = glyph_info.advance_width; - last_glyph.font_impl_ascent = font_impl.map_or(0.0, |f| f.ascent()); - last_glyph.font_impl_height = font_impl.map_or(0.0, |f| f.row_height()); - last_glyph.uv_rect = glyph_info.uv_rect; + row.glyphs.push(Glyph { + chr: 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_height: font_metrics.row_height, + font_ascent: font_metrics.ascent, + uv_rect: replacement_glyph_alloc.uv_rect, + section_index, + }); return; } + + // We didn't fit - pop the last glyph and try again. + if let Some(last_glyph) = row.glyphs.pop() { + section_index = last_glyph.section_index; + } else { + section_index = row.section_index_at_start; + } } } @@ -1043,31 +1046,6 @@ impl RowBreakCandidates { } } -#[inline] -fn is_cjk_ideograph(c: char) -> bool { - ('\u{4E00}' <= c && c <= '\u{9FFF}') - || ('\u{3400}' <= c && c <= '\u{4DBF}') - || ('\u{2B740}' <= c && c <= '\u{2B81F}') -} - -#[inline] -fn is_kana(c: char) -> bool { - ('\u{3040}' <= c && c <= '\u{309F}') // Hiragana block - || ('\u{30A0}' <= c && c <= '\u{30FF}') // Katakana block -} - -#[inline] -fn is_cjk(c: char) -> bool { - // TODO(bigfarts): Add support for Korean Hangul. - is_cjk_ideograph(c) || is_kana(c) -} - -#[inline] -fn is_cjk_break_allowed(c: char) -> bool { - // See: https://en.wikipedia.org/wiki/Line_breaking_rules_in_East_Asian_languages#Characters_not_permitted_on_the_start_of_a_line. - !")]}〕〉》」』】〙〗〟'\"⦆»ヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻‐゠–〜?!‼⁇⁈⁉・、:;,。.".contains(c) -} - // ---------------------------------------------------------------------------- #[cfg(test)] @@ -1078,15 +1056,15 @@ mod tests { #[test] fn test_zero_max_width() { + let pixels_per_point = 1.0; let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::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, layout_job.into()); + let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); assert_eq!(galley.rows.len(), 1); } @@ -1094,8 +1072,9 @@ mod tests { fn test_truncate_with_newline() { // No matter where we wrap, we should be appending the newline character. + let pixels_per_point = 1.0; + let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -1114,7 +1093,7 @@ mod tests { layout_job.wrap.max_rows = 1; layout_job.wrap.break_anywhere = break_anywhere; - let galley = layout(&mut fonts, layout_job.into()); + let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); assert!(galley.elided); assert_eq!(galley.rows.len(), 1); @@ -1133,7 +1112,7 @@ mod tests { layout_job.wrap.max_rows = 1; layout_job.wrap.break_anywhere = false; - let galley = layout(&mut fonts, layout_job.into()); + let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); assert!(galley.elided); assert_eq!(galley.rows.len(), 1); @@ -1144,8 +1123,8 @@ mod tests { #[test] fn test_cjk() { + let pixels_per_point = 1.0; let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -1155,7 +1134,7 @@ mod tests { TextFormat::default(), ); layout_job.wrap.max_width = 90.0; - let galley = layout(&mut fonts, layout_job.into()); + let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); assert_eq!( galley.rows.iter().map(|row| row.text()).collect::>(), vec!["日本語と", "Englishの混在", "した文章"] @@ -1164,8 +1143,8 @@ mod tests { #[test] fn test_pre_cjk() { + let pixels_per_point = 1.0; let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -1175,7 +1154,7 @@ mod tests { TextFormat::default(), ); layout_job.wrap.max_width = 110.0; - let galley = layout(&mut fonts, layout_job.into()); + let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); assert_eq!( galley.rows.iter().map(|row| row.text()).collect::>(), vec!["日本語とEnglish", "の混在した文章"] @@ -1184,8 +1163,8 @@ mod tests { #[test] fn test_truncate_width() { + let pixels_per_point = 1.0; let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), @@ -1195,7 +1174,7 @@ mod tests { layout_job.wrap.max_width = f32::INFINITY; layout_job.wrap.max_rows = 1; layout_job.round_output_to_gui = false; - let galley = layout(&mut fonts, layout_job.into()); + let galley = layout(&mut fonts, pixels_per_point, layout_job.into()); assert!(galley.elided); assert_eq!( galley.rows.iter().map(|row| row.text()).collect::>(), @@ -1208,19 +1187,22 @@ mod tests { #[test] fn test_empty_row() { + let pixels_per_point = 1.0; let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), ); let font_id = FontId::default(); - let font_height = fonts.font(&font_id).row_height(); + let font_height = fonts + .font(&font_id.family) + .scaled_metrics(pixels_per_point, font_id.size) + .row_height; let job = LayoutJob::simple(String::new(), font_id, Color32::WHITE, f32::INFINITY); - let galley = layout(&mut fonts, job.into()); + let galley = layout(&mut fonts, pixels_per_point, job.into()); assert_eq!(galley.rows.len(), 1, "Expected one row"); assert_eq!( @@ -1242,19 +1224,22 @@ mod tests { #[test] fn test_end_with_newline() { + let pixels_per_point = 1.0; let mut fonts = FontsImpl::new( - 1.0, 1024, AlphaFromCoverage::default(), FontDefinitions::default(), ); let font_id = FontId::default(); - let font_height = fonts.font(&font_id).row_height(); + let font_height = fonts + .font(&font_id.family) + .scaled_metrics(pixels_per_point, font_id.size) + .row_height; let job = LayoutJob::simple("Hi!\n".to_owned(), font_id, Color32::WHITE, f32::INFINITY); - let galley = layout(&mut fonts, job.into()); + let galley = layout(&mut fonts, pixels_per_point, job.into()); assert_eq!(galley.rows.len(), 2, "Expected two rows"); assert_eq!( diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index 7635dced..e6a0c660 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -8,14 +8,14 @@ use super::{ cursor::{CCursor, LayoutCursor}, font::UvRect, }; -use crate::{Color32, FontId, Mesh, Stroke}; +use crate::{Color32, FontId, Mesh, Stroke, text::FontsView}; use emath::{Align, GuiRounding as _, NumExt as _, OrderedFloat, Pos2, Rect, Vec2, pos2, vec2}; /// Describes the task of laying out text. /// /// This supports mixing different fonts, color and formats (underline etc). /// -/// Pass this to [`crate::Fonts::layout_job`] or [`crate::text::layout`]. +/// Pass this to [`crate::FontsView::layout_job`] or [`crate::text::layout`]. /// /// ## Example: /// ``` @@ -184,7 +184,7 @@ impl LayoutJob { /// The height of the tallest font used in the job. /// /// Returns a value rounded to [`emath::GUI_ROUNDING`]. - pub fn font_height(&self, fonts: &crate::Fonts) -> f32 { + pub fn font_height(&self, fonts: &mut FontsView<'_>) -> f32 { let mut max_height = 0.0_f32; for section in &self.sections { max_height = max_height.max(fonts.row_height(§ion.format.font_id)); @@ -504,7 +504,7 @@ impl TextWrapping { /// Text that has been laid out, ready for painting. /// -/// You can create a [`Galley`] using [`crate::Fonts::layout_job`]; +/// You can create a [`Galley`] using [`crate::FontsView::layout_job`]; /// /// Needs to be recreated if the underlying font atlas texture changes, which /// happens under the following conditions: diff --git a/tests/egui_tests/tests/snapshots/grow_all.png b/tests/egui_tests/tests/snapshots/grow_all.png index 7ef69ea1..e065c70f 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:34f0c49cef96c7c3d08dbe835efd9366a4ced6ad2c6aa7facb0de08fd1a44648 -size 14011 +oid sha256:4d815e6dd4f35df988cd8f52d19e607aa51f56ba0fdb7391a1c010ea769200aa +size 14237 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 9aa37308..46492a25 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:dc03cdc22b410ed90fdbbc45ced5c61027463132c490673170aab9044d683f88 -size 10254 +oid sha256:880b50269a3b7a544901655f199dd2fe0bd7f004e180c6d3a1375000f6d138a5 +size 10271 diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_image.png b/tests/egui_tests/tests/snapshots/layout/atoms_image.png index 759c10b7..d1567618 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:a46aebd7c611b01885819c80a4622eea44681de7f4902cf4b5debccd4b8fc000 -size 387626 +oid sha256:bedaa1bc229b0135f39ab79db1e0e62ff9c86b057aa4a2c6d1f9e6c051f12eaf +size 404014 diff --git a/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png b/tests/egui_tests/tests/snapshots/layout/atoms_minimal.png index a4b0861e..91a7d0d3 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:73423d2df441a5851d7fb8100455b1126d83ada4409b191865d42609cb8badde -size 384699 +oid sha256:6028b96a4d209b654f5a376e594ac4f680bb4cd8796d96d9acafb2f8b74fff6f +size 396750 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 4ecf7a4e..7bdfdc46 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:fd3f36929cd6ba4caf12eee5e366387c8fc30addabc0fb0e34188aa8c0c8f5ef -size 299564 +oid sha256:963e4a024d6bea8e1554305286c59a28e8fbf09e3bbfb57cb93c85b7868b0fe9 +size 303826 diff --git a/tests/egui_tests/tests/snapshots/layout/button.png b/tests/egui_tests/tests/snapshots/layout/button.png index 51b6004b..ef67e84e 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:4caea23dd3b110412bb17aabfaeb99328c2f33c57426476e60ea96cedb58c1dd -size 315644 +oid sha256:455888286bea147481f797edf31e4d119118d3d38933b7e5f41a6c3d82146751 +size 323220 diff --git a/tests/egui_tests/tests/snapshots/layout/button_image.png b/tests/egui_tests/tests/snapshots/layout/button_image.png index 59c41c2f..4e690827 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:8659eefdffe496e06c4c46906f1821e8a481b2b5e58bc4a0589e26edbf97d3a9 -size 339845 +oid sha256:6811a7d4d041fdb2155d32d0e6ebfe4425a94bc5e3fff2f0380f65003487854b +size 347791 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 41bbdd06..05e9e430 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:f4ceba068adcac969ddb20c3f249ab057e4f914a62b59fee0222b54b15ec8813 -size 424828 +oid sha256:1a481554267ad3e4c65f3552c64181d7cf0602193795ec4560e511a33586e879 +size 430746 diff --git a/tests/egui_tests/tests/snapshots/layout/checkbox.png b/tests/egui_tests/tests/snapshots/layout/checkbox.png index b11e71ad..c60b6118 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:af4d7c3b64ac66df76a10283a4762382a8afd5cb0872bf28c000d771dced583d -size 386444 +oid sha256:08d455bd1b3bc259ab051ad6fcea713271a00ac11cb4a97399655457249e8abe +size 398447 diff --git a/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png b/tests/egui_tests/tests/snapshots/layout/checkbox_checked.png index ba2cdfb4..8a84f35f 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:bccccd5a51455ccb7f6963baf8c8ce36b2097458f7e85c77333736bab27288f3 -size 416329 +oid sha256:9df1bcba7179ef9a6e1a7478049918c5019b21e93f623fb01c6c5c26225632b4 +size 428446 diff --git a/tests/egui_tests/tests/snapshots/layout/drag_value.png b/tests/egui_tests/tests/snapshots/layout/drag_value.png index 3433e6bd..495712a8 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:cf56d809f8fbb63462c4112217a869820d32be906565c2122d4fd1938c2206c2 -size 239539 +oid sha256:e544781b4d83dca5d938657bf488db7df37a9bda5334b48c34cd6a15642b0ecc +size 244477 diff --git a/tests/egui_tests/tests/snapshots/layout/radio.png b/tests/egui_tests/tests/snapshots/layout/radio.png index f71421a0..7642aa18 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:4a943ef2ebd13bcf87fc7d480b0eb1e91243236eb4affa6e17a9fd2c3ce14c4d -size 336517 +oid sha256:33fe0d203e53c9adab6317f8fccfc742e68a7e12efcb972825c4ec5b3f34753d +size 339179 diff --git a/tests/egui_tests/tests/snapshots/layout/radio_checked.png b/tests/egui_tests/tests/snapshots/layout/radio_checked.png index fc2b0b36..19faf9b4 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:591f5001e8c5a63d063929a7bb357658a1f07b2a1be93adac3790938de1fbbc4 -size 356858 +oid sha256:523d529c9c12af56f8e1de2a325287ca7c8f97421d7fa20464e49fbfd08a17e6 +size 359389 diff --git a/tests/egui_tests/tests/snapshots/layout/selectable_value.png b/tests/egui_tests/tests/snapshots/layout/selectable_value.png index e3ea1e02..f6825f60 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:c3018bc027223a535541fa7e87d3654ab9604c5c4ca9db5751f9ff1f8e9f5e76 -size 389206 +oid sha256:6c10baa7eb1d6e4fbf7503f1bc15de623f7bab104cb1af9f4d7912de612cb45a +size 404088 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 baae7aaf..0b46f297 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:fe816c0eff10c65f4634b0e795ac49d07ebfb064cba7199561028db8fa85c05c -size 402833 +oid sha256:b84eede8fae61c6417ecb59908efa13170cce843e5ed20f810360bd7c1acb8b4 +size 416638 diff --git a/tests/egui_tests/tests/snapshots/layout/slider.png b/tests/egui_tests/tests/snapshots/layout/slider.png index a84359b5..d1a39e2f 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:ce99e4a0da54c6349e270b4fdf6572db95eb997df6221cdc21f4aba8e123c7a3 -size 336775 +oid sha256:7db0cec954ff4eccd1e814107034b205ee0af6ba7d4ee523bd5f22d6631dd871 +size 341575 diff --git a/tests/egui_tests/tests/snapshots/layout/text_edit.png b/tests/egui_tests/tests/snapshots/layout/text_edit.png index 459b974e..dfe942fc 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:7825ca0dac7c330c269f4469ecf35c02cc147ed9d966ace5576fb2f52599449c -size 233025 +oid sha256:0a2fb352590e99ea3593ad1b9be8ae4de422892567468c979dd35bd675390730 +size 239449 diff --git a/tests/egui_tests/tests/snapshots/max_width.png b/tests/egui_tests/tests/snapshots/max_width.png index 43f3a59f..5fc8690a 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:c2a324562613323b6c94eaab6b7975576eb85f6d095ff818d2d36e116d370a8e -size 8752 +oid sha256:e014a3d42234c9fe2d7f78ad79cd290e53e387688347b91991a4ec557f809f82 +size 9041 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 8f261d32..6f61d9c4 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:73e61063bf68035aebc244236747dd3af13d1c80df2c4cbbdacda8f796342e62 -size 8754 +oid sha256:8301a3ea55b19269bada62cb7dd4ac296b9c2f7f3d11954f3eb9478641e3597b +size 9043 diff --git a/tests/egui_tests/tests/snapshots/shrink_first_text.png b/tests/egui_tests/tests/snapshots/shrink_first_text.png index fb415287..36210b71 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:7bcc46a2cf63d6361b28cf7b730a3bf717dbe87065c24c3ead6fddf593ea3080 -size 11606 +oid sha256:904f5fad4c9548bdd3df1e0350066d6ceac36fd8573573f6201e326e867eb029 +size 12032 diff --git a/tests/egui_tests/tests/snapshots/shrink_last_text.png b/tests/egui_tests/tests/snapshots/shrink_last_text.png index 8cbdc8c0..e9294bac 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:db71fdcc89ca9f058559a2c2cd6bd1f0b7df1a0875d1d57f89a9437f14dfe649 -size 12136 +oid sha256:8d0b548a375ca69f4427ec7008d7bf3f452272d33b7d18d5b63a587f63041c61 +size 12623 diff --git a/tests/egui_tests/tests/snapshots/sides/default_long.png b/tests/egui_tests/tests/snapshots/sides/default_long.png index 26e40ed6..4c1ba903 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:c4866b8bbefe79275480578f5465ec7485a642253f7ef66423e0f0e84b33a8d8 -size 7890 +oid sha256:d8b7ee31e8c1b8ec2f46cc5e9d61d7925d68a5e0bfa8a6fe1cf511111c8129e7 +size 8191 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 15e9dc46..cb1aa5ac 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:931af33f4548924b3bb75a2e513b9e689bce94436b10a9f811140eb11e9d6442 -size 8552 +oid sha256:f89796ebda793d34c8e2a14e67b704bc59d3c2538070f28a544dc1be17bb7f88 +size 8971 diff --git a/tests/egui_tests/tests/snapshots/sides/default_short.png b/tests/egui_tests/tests/snapshots/sides/default_short.png index 756a3068..8783d2a4 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:6448d44c1c9bed08cd6a4af39b141f3a4ca203ca5f7b967cbc0e0d0c2b4fb73f -size 1647 +oid sha256:4e851957d66bb7b15ad558e3a67a12155146545a3db308f964a5088784d36810 +size 1718 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 6f318926..e137eb31 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:44622002ebe287208d26359a06804b1f8737f86eb482322bdf3881a1fe53941f -size 1276 +oid sha256:2ab59052273826057aca96159596ee4333357ffdd22ad1310eaddce7c025b042 +size 1318 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 39e1bab9..ec941bf8 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:88e1557dffa7295e7e7e37ed175fcec40aab939f9b67137a1ce33811e8ae4722 -size 7148 +oid sha256:1ee1cb1948c5d070c79248fe12727626872ff57ff3ce027d957f33eeb1d309ac +size 7450 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 15e9dc46..cb1aa5ac 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:931af33f4548924b3bb75a2e513b9e689bce94436b10a9f811140eb11e9d6442 -size 8552 +oid sha256:f89796ebda793d34c8e2a14e67b704bc59d3c2538070f28a544dc1be17bb7f88 +size 8971 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 756a3068..8783d2a4 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:6448d44c1c9bed08cd6a4af39b141f3a4ca203ca5f7b967cbc0e0d0c2b4fb73f -size 1647 +oid sha256:4e851957d66bb7b15ad558e3a67a12155146545a3db308f964a5088784d36810 +size 1718 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 6f318926..e137eb31 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:44622002ebe287208d26359a06804b1f8737f86eb482322bdf3881a1fe53941f -size 1276 +oid sha256:2ab59052273826057aca96159596ee4333357ffdd22ad1310eaddce7c025b042 +size 1318 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 3326d952..43522519 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:508209ca303751ef323301b25bb3878410742ea79339b75363d2681b98d2712b -size 7068 +oid sha256:b1f7df988359773b96ac7645eb919260076b090eb980fe900a46ad765c69bc4f +size 7353 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 15e9dc46..cb1aa5ac 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:931af33f4548924b3bb75a2e513b9e689bce94436b10a9f811140eb11e9d6442 -size 8552 +oid sha256:f89796ebda793d34c8e2a14e67b704bc59d3c2538070f28a544dc1be17bb7f88 +size 8971 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 756a3068..8783d2a4 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:6448d44c1c9bed08cd6a4af39b141f3a4ca203ca5f7b967cbc0e0d0c2b4fb73f -size 1647 +oid sha256:4e851957d66bb7b15ad558e3a67a12155146545a3db308f964a5088784d36810 +size 1718 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 6f318926..e137eb31 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:44622002ebe287208d26359a06804b1f8737f86eb482322bdf3881a1fe53941f -size 1276 +oid sha256:2ab59052273826057aca96159596ee4333357ffdd22ad1310eaddce7c025b042 +size 1318 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 36929a41..f6cfcde2 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:a0c9e39c18fc5bb1fc02a86dbf02e3ffca5537dbe8986d5c5b50cb4984c97466 -size 9085 +oid sha256:510dde01a46ce7fdf1142bc88e7873ba83c5d52a6a93a6f375ff565c1ad5d11f +size 9468 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 15e9dc46..cb1aa5ac 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:931af33f4548924b3bb75a2e513b9e689bce94436b10a9f811140eb11e9d6442 -size 8552 +oid sha256:f89796ebda793d34c8e2a14e67b704bc59d3c2538070f28a544dc1be17bb7f88 +size 8971 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 756a3068..8783d2a4 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:6448d44c1c9bed08cd6a4af39b141f3a4ca203ca5f7b967cbc0e0d0c2b4fb73f -size 1647 +oid sha256:4e851957d66bb7b15ad558e3a67a12155146545a3db308f964a5088784d36810 +size 1718 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 6f318926..e137eb31 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:44622002ebe287208d26359a06804b1f8737f86eb482322bdf3881a1fe53941f -size 1276 +oid sha256:2ab59052273826057aca96159596ee4333357ffdd22ad1310eaddce7c025b042 +size 1318 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 47398293..76de1f27 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:a6e9ba0acb573853ef5b3dedb1156d99cdf80338ccb160093960e8aaa41bd5df -size 9048 +oid sha256:25c0c51f39b515609a51a07514606c474c4bd8516e5597569b58a31dfedfb790 +size 9448 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 15e9dc46..cb1aa5ac 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:931af33f4548924b3bb75a2e513b9e689bce94436b10a9f811140eb11e9d6442 -size 8552 +oid sha256:f89796ebda793d34c8e2a14e67b704bc59d3c2538070f28a544dc1be17bb7f88 +size 8971 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 756a3068..8783d2a4 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:6448d44c1c9bed08cd6a4af39b141f3a4ca203ca5f7b967cbc0e0d0c2b4fb73f -size 1647 +oid sha256:4e851957d66bb7b15ad558e3a67a12155146545a3db308f964a5088784d36810 +size 1718 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 6f318926..e137eb31 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:44622002ebe287208d26359a06804b1f8737f86eb482322bdf3881a1fe53941f -size 1276 +oid sha256:2ab59052273826057aca96159596ee4333357ffdd22ad1310eaddce7c025b042 +size 1318 diff --git a/tests/egui_tests/tests/snapshots/size_max_size.png b/tests/egui_tests/tests/snapshots/size_max_size.png index 742ae57f..4a221a5b 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:161522c5bc65a03f3a12615729788b0a13b24a8b0d4d42de7f2c8a8f0ff46687 -size 8727 +oid sha256:08c69a55622468c906581534fe874f1b51515922ec4e92b2d219feec56dbf941 +size 8992 diff --git a/tests/egui_tests/tests/snapshots/visuals/button.png b/tests/egui_tests/tests/snapshots/visuals/button.png index 364f7771..b874abe6 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:a573976aacbb629c88c285089fca28ba7998a0c28ecee9f783920d67929a1e2d -size 9735 +oid sha256:db667120ae1f7909c8f1a9f956ec435d415ea5759c5ea40b8af4bc37cd477da1 +size 10004 diff --git a/tests/egui_tests/tests/snapshots/visuals/button_image.png b/tests/egui_tests/tests/snapshots/visuals/button_image.png index c38571a6..1a287023 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:9fbb9aca2006aeca555c138f1ebdb89409026f1bed48da74cd0fa03dcd8facbe -size 10746 +oid sha256:24105bf3867e453ebe6457d30ba3c6e7356f6522137bab46bca01b28ac19c372 +size 11205 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 f633bd59..5cc89426 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:7390b7a44bd0132d61f71598c3c8f13f0feba4f2e28b019dce9ab74ae17d9e14 -size 13783 +oid sha256:773f4bb9e40340bd07e18ff98f95a34c5ddb3daae797625383c79bc54d406837 +size 13897 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 bcf0f01c..c750d4d6 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:e3f62e86ef77c26dd2d54c5f94221506d8ad1517eeb26c107c6c321f9e94af6c -size 13474 +oid sha256:6ad507f427d9cf10778aa9289f499a7364f08c55c8d8d8fec565d9d0363467ee +size 13553 diff --git a/tests/egui_tests/tests/snapshots/visuals/checkbox.png b/tests/egui_tests/tests/snapshots/visuals/checkbox.png index 00f4bd8b..11608685 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:befff30cab57644f4e19e90d5d8a7d59093d57b8af3865c94ecffcb7ece9f2fb -size 12327 +oid sha256:4bdfc4468b385f3b83ed7bfa72f0cd7cf07e6d6a60c07db876c9c55c009fc721 +size 12723 diff --git a/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png b/tests/egui_tests/tests/snapshots/visuals/checkbox_checked.png index f1b144d2..4ebe6b42 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:a5dffe081a596a17928e1fd53df04c4eac69c0bcebc75ecec7fbc9133a5380b0 -size 13461 +oid sha256:289f3202b84d5e17cdda65edd8ed9c4201278e1e9a8422eab1579972e2d8baf2 +size 13807 diff --git a/tests/egui_tests/tests/snapshots/visuals/drag_value.png b/tests/egui_tests/tests/snapshots/visuals/drag_value.png index 56b5bb0e..be898173 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:c7e66a490236b306ce03c504d29490cdadc3708a79e21e3b46d11df8eb22a26b -size 7309 +oid sha256:100ae526549f0d85466fa41c3f8cb60dc0d2501729444fff7ed566b09fa9d457 +size 7493 diff --git a/tests/egui_tests/tests/snapshots/visuals/radio.png b/tests/egui_tests/tests/snapshots/visuals/radio.png index 8a364b32..0af77773 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:297dda97ae7cc4415c6679ad914a5fbee96cad527e98f2afc797b665d9b7f48f -size 11070 +oid sha256:9f78fc2de7c20d08c98909a5f53517e91d0ac46f98c0c76ff350d858e2867907 +size 11170 diff --git a/tests/egui_tests/tests/snapshots/visuals/radio_checked.png b/tests/egui_tests/tests/snapshots/visuals/radio_checked.png index 32e8a394..1efaa705 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:0bb35eac75aed7f0fcef4d467d894e4af459f0f3efe43c265384e25f31cde4c4 -size 11744 +oid sha256:1ae4d4a7d079b2557f1b7b505d91cc7438f4052db6f6a149990bd11754b1ca49 +size 11845 diff --git a/tests/egui_tests/tests/snapshots/visuals/selectable_value.png b/tests/egui_tests/tests/snapshots/visuals/selectable_value.png index 49ddf607..cdec6780 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:96057a478dd4242aa74fea9d11ff4f5181a0c414291dbabb536076af85b83542 -size 12453 +oid sha256:52babe11fc4af5eb9d9137107594a59b7987cc9d3116e444cc8d739408f35cba +size 12871 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 c9d3e32d..7405322a 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:b02284574a8b5959d473cdc786ac4b323e0d7c0ebeca2933688cf51ef62a391d -size 12513 +oid sha256:130704c3320a88309e7ad7a3ca441741727fe891c080e0593377c083f5b548c8 +size 13104 diff --git a/tests/egui_tests/tests/snapshots/visuals/slider.png b/tests/egui_tests/tests/snapshots/visuals/slider.png index 1129add0..8ad98c15 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:c4f3597075a77afbde2ddb7513d3309eb60f78cea6e5d4c108bbc5faed3ec937 -size 11035 +oid sha256:af0764e450a544af4eab1c9c123fe4c46f313b84f070c0e0b756c273db2d2fed +size 11204 diff --git a/tests/egui_tests/tests/snapshots/visuals/text_edit.png b/tests/egui_tests/tests/snapshots/visuals/text_edit.png index 1e1e4d39..bf87660f 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:9353e6d39d309e7a6e6c0a17be819809c2dbea8979e9e73b3c73b67b07124a36 -size 7031 +oid sha256:078a3d58c6e2cc2e9189d257b09f3c2c19721c09666bfe48103884005fb4eb6c +size 7228