From 83254718a335b358f062c7401bdd4ae0faae814b Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 30 Mar 2025 13:15:41 +0200 Subject: [PATCH 1/5] Clean up strikethrough/underline code in epaint --- crates/epaint/src/text/text_layout.rs | 36 ++++++--------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs index eb1adf5fb..7ce726f79 100644 --- a/crates/epaint/src/text/text_layout.rs +++ b/crates/epaint/src/text/text_layout.rs @@ -856,9 +856,15 @@ fn add_row_hline( mesh: &mut Mesh, stroke_and_y: impl Fn(&Glyph) -> (Stroke, f32), ) { + let mut path = crate::tessellator::Path::default(); // reusing path to avoid re-allocations. + let mut end_line = |start: Option<(Stroke, Pos2)>, stop_x: f32| { if let Some((stroke, start)) = start { - add_hline(point_scale, [start, pos2(stop_x, start.y)], stroke, mesh); + let stop = pos2(stop_x, start.y); + path.clear(); + path.add_line_segment([start, stop]); + let feathering = 1.0 / point_scale.pixels_per_point(); + path.stroke_open(feathering, &PathStroke::from(stroke), mesh); } }; @@ -888,34 +894,6 @@ fn add_row_hline( end_line(line_start.take(), last_right_x); } -fn add_hline(point_scale: PointScale, [start, stop]: [Pos2; 2], stroke: Stroke, mesh: &mut Mesh) { - let antialiased = true; - - if antialiased { - let mut path = crate::tessellator::Path::default(); // TODO(emilk): reuse this to avoid re-allocations. - path.add_line_segment([start, stop]); - let feathering = 1.0 / point_scale.pixels_per_point(); - path.stroke_open(feathering, &PathStroke::from(stroke), mesh); - } else { - // Thin lines often lost, so this is a bad idea - - assert_eq!( - start.y, stop.y, - "Horizontal line must be horizontal, but got: {start:?} -> {stop:?}" - ); - - let min_y = point_scale.round_to_pixel(start.y - 0.5 * stroke.width); - let max_y = point_scale.round_to_pixel(min_y + stroke.width); - - let rect = Rect::from_min_max( - pos2(point_scale.round_to_pixel(start.x), min_y), - pos2(point_scale.round_to_pixel(stop.x), max_y), - ); - - mesh.add_colored_rect(rect, stroke.color); - } -} - // ---------------------------------------------------------------------------- /// Keeps track of good places to break a long row of text. From ab0f0b7b64fa85e8186d6596df6df3253a210b46 Mon Sep 17 00:00:00 2001 From: Timo von Hartz Date: Sun, 30 Mar 2025 14:00:46 +0200 Subject: [PATCH 2/5] Rename `should_propagate_event` & add `should_prevent_default` (#5779) * [x] I have followed the instructions in the PR template Currently eframe [calls `prevent_default()`](https://github.com/emilk/egui/blob/962c7c75166dff3369d20675bcfd527d3287149f/crates/eframe/src/web/events.rs#L307-L369) for all copy / paste events on the [*document*](https://github.com/emilk/egui/blob/962c7c75166dff3369d20675bcfd527d3287149f/crates/eframe/src/web/events.rs#L88), making embedding an egui application in a page (e.g. an react application) hard (as all copy & paste functionality for other elements on the page is broken by this). I'm not sure what the motivation for this is, if any. This commit / PR adds a callback (`should_prevent_default`), similar to `should_propgate_event`, that an egui application can use to overwrite this behavior. It defaults to returning `true` for all events, to keep the existing behavior. I call `should_prevent_default` in every place that `should_propagate_event` is called (which is not all places that `prevent_default` is called!). I'm not sure for the motivation of not calling `should_propagate_event` everywhere that `stop_propagation` is called, but I kept that behavior for the `should_prevent_default` callback too. Please let me know if I'm missing some existing functionality that would allow me to do this, or if there's a reason that we don't want applications to be able to customize this (i.e. if there's a reason to always `prevent_default` for all copy / paste events on the whole document) --- crates/eframe/src/epi.rs | 15 +++- crates/eframe/src/web/events.rs | 141 ++++++++++++++++++++++---------- 2 files changed, 108 insertions(+), 48 deletions(-) diff --git a/crates/eframe/src/epi.rs b/crates/eframe/src/epi.rs index fb589fe2e..562311dc6 100644 --- a/crates/eframe/src/epi.rs +++ b/crates/eframe/src/epi.rs @@ -499,10 +499,16 @@ pub struct WebOptions { /// If the web event corresponding to an egui event should be propagated /// to the rest of the web page. /// - /// The default is `false`, meaning + /// The default is `true`, meaning /// [`stopPropagation`](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation) - /// is called on every event. - pub should_propagate_event: Box bool>, + /// is called on every event, and the event is not propagated to the rest of the web page. + pub should_stop_propagation: Box bool>, + + /// Whether the web event corresponding to an egui event should have `prevent_default` called + /// on it or not. + /// + /// Defaults to true. + pub should_prevent_default: Box bool>, } #[cfg(target_arch = "wasm32")] @@ -519,7 +525,8 @@ impl Default for WebOptions { dithering: true, - should_propagate_event: Box::new(|_| false), + should_stop_propagation: Box::new(|_| true), + should_prevent_default: Box::new(|_| true), } } } diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index 6a1b7b6db..32fba9ef0 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -139,15 +139,20 @@ fn install_keydown(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), J { if let Some(text) = text_from_keyboard_event(&event) { let egui_event = egui::Event::Text(text); - let should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + let should_stop_propagation = + (runner.web_options.should_stop_propagation)(&egui_event); + let should_prevent_default = + (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); runner.needs_repaint.repaint_asap(); // If this is indeed text, then prevent any other action. - event.prevent_default(); + if should_prevent_default { + event.prevent_default(); + } // Use web options to tell if the event should be propagated to parent elements. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } } @@ -184,7 +189,7 @@ pub(crate) fn on_keydown(event: web_sys::KeyboardEvent, runner: &mut AppRunner) repeat: false, // egui will fill this in for us! modifiers, }; - let should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + let should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); runner.input.raw.events.push(egui_event); runner.needs_repaint.repaint_asap(); @@ -201,7 +206,7 @@ pub(crate) fn on_keydown(event: web_sys::KeyboardEvent, runner: &mut AppRunner) } // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } } @@ -261,7 +266,7 @@ pub(crate) fn on_keyup(event: web_sys::KeyboardEvent, runner: &mut AppRunner) { let modifiers = modifiers_from_kb_event(&event); runner.input.raw.modifiers = modifiers; - let mut propagate_event = false; + let mut should_stop_propagation = true; if let Some(key) = translate_key(&event.key()) { let egui_event = egui::Event::Key { @@ -271,7 +276,7 @@ pub(crate) fn on_keyup(event: web_sys::KeyboardEvent, runner: &mut AppRunner) { repeat: false, modifiers, }; - propagate_event |= (runner.web_options.should_propagate_event)(&egui_event); + should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui_event); runner.input.raw.events.push(egui_event); } @@ -290,7 +295,7 @@ pub(crate) fn on_keyup(event: web_sys::KeyboardEvent, runner: &mut AppRunner) { repeat: false, modifiers, }; - propagate_event |= (runner.web_options.should_propagate_event)(&egui_event); + should_stop_propagation &= (runner.web_options.should_stop_propagation)(&egui_event); runner.input.raw.events.push(egui_event); } } @@ -299,7 +304,7 @@ pub(crate) fn on_keyup(event: web_sys::KeyboardEvent, runner: &mut AppRunner) { // Use web options to tell if the web event should be propagated to parent elements based on the egui event. let has_focus = runner.input.raw.focused; - if has_focus && !propagate_event { + if has_focus && should_stop_propagation { event.stop_propagation(); } } @@ -310,19 +315,26 @@ fn install_copy_cut_paste(runner_ref: &WebRunner, target: &EventTarget) -> Resul if let Ok(text) = data.get_data("text") { let text = text.replace("\r\n", "\n"); - let mut should_propagate = false; + let mut should_stop_propagation = true; + let mut should_prevent_default = true; if !text.is_empty() && runner.input.raw.focused { let egui_event = egui::Event::Paste(text); - should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + should_stop_propagation = + (runner.web_options.should_stop_propagation)(&egui_event); + should_prevent_default = + (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); runner.needs_repaint.repaint_asap(); } // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } - event.prevent_default(); + + if should_prevent_default { + event.prevent_default(); + } } } })?; @@ -340,10 +352,13 @@ fn install_copy_cut_paste(runner_ref: &WebRunner, target: &EventTarget) -> Resul } // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !(runner.web_options.should_propagate_event)(&egui::Event::Cut) { + if (runner.web_options.should_stop_propagation)(&egui::Event::Cut) { event.stop_propagation(); } - event.prevent_default(); + + if (runner.web_options.should_prevent_default)(&egui::Event::Cut) { + event.prevent_default(); + } })?; runner_ref.add_event_listener(target, "copy", |event: web_sys::ClipboardEvent, runner| { @@ -359,10 +374,13 @@ fn install_copy_cut_paste(runner_ref: &WebRunner, target: &EventTarget) -> Resul } // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !(runner.web_options.should_propagate_event)(&egui::Event::Copy) { + if (runner.web_options.should_stop_propagation)(&egui::Event::Copy) { event.stop_propagation(); } - event.prevent_default(); + + if (runner.web_options.should_prevent_default)(&egui::Event::Copy) { + event.prevent_default(); + } })?; Ok(()) @@ -484,7 +502,7 @@ fn install_pointerdown(runner_ref: &WebRunner, target: &EventTarget) -> Result<( |event: web_sys::PointerEvent, runner: &mut AppRunner| { let modifiers = modifiers_from_mouse_event(&event); runner.input.raw.modifiers = modifiers; - let mut should_propagate = false; + let mut should_stop_propagation = true; if let Some(button) = button_from_mouse_event(&event) { let pos = pos_from_mouse_event(runner.canvas(), &event, runner.egui_ctx()); let modifiers = runner.input.raw.modifiers; @@ -494,7 +512,7 @@ fn install_pointerdown(runner_ref: &WebRunner, target: &EventTarget) -> Result<( pressed: true, modifiers, }; - should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); runner.input.raw.events.push(egui_event); // In Safari we are only allowed to write to the clipboard during the @@ -506,7 +524,7 @@ fn install_pointerdown(runner_ref: &WebRunner, target: &EventTarget) -> Result<( } // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } // Note: prevent_default breaks VSCode tab focusing, hence why we don't call it here. @@ -536,7 +554,10 @@ fn install_pointerup(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), pressed: false, modifiers, }; - let should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + let should_stop_propagation = + (runner.web_options.should_stop_propagation)(&egui_event); + let should_prevent_default = + (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); // Previously on iOS, the canvas would not receive focus on @@ -555,10 +576,12 @@ fn install_pointerup(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), // Make sure we paint the output of the above logic call asap: runner.needs_repaint.repaint_asap(); - event.prevent_default(); + if should_prevent_default { + event.prevent_default(); + } // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } } @@ -600,15 +623,19 @@ fn install_mousemove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), egui::pos2(event.client_x() as f32, event.client_y() as f32), ) { let egui_event = egui::Event::PointerMoved(pos); - let should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + let should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); + let should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } - event.prevent_default(); + + if should_prevent_default { + event.prevent_default(); + } } }) } @@ -622,10 +649,13 @@ fn install_mouseleave(runner_ref: &WebRunner, target: &EventTarget) -> Result<() runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !(runner.web_options.should_propagate_event)(&egui::Event::PointerGone) { + if (runner.web_options.should_stop_propagation)(&egui::Event::PointerGone) { event.stop_propagation(); } - event.prevent_default(); + + if (runner.web_options.should_prevent_default)(&egui::Event::PointerGone) { + event.prevent_default(); + } }, ) } @@ -635,7 +665,8 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() target, "touchstart", |event: web_sys::TouchEvent, runner| { - let mut should_propagate = false; + let mut should_stop_propagation = true; + let mut should_prevent_default = true; if let Some((pos, _)) = primary_touch_pos(runner, &event) { let egui_event = egui::Event::PointerButton { pos, @@ -643,7 +674,8 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() pressed: true, modifiers: runner.input.raw.modifiers, }; - should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); + should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); } @@ -651,10 +683,13 @@ fn install_touchstart(runner_ref: &WebRunner, target: &EventTarget) -> Result<() runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } - event.prevent_default(); + + if should_prevent_default { + event.prevent_default(); + } }, ) } @@ -667,17 +702,23 @@ fn install_touchmove(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), egui::pos2(touch.client_x() as f32, touch.client_y() as f32), ) { let egui_event = egui::Event::PointerMoved(pos); - let should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + let should_stop_propagation = + (runner.web_options.should_stop_propagation)(&egui_event); + let should_prevent_default = + (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); push_touches(runner, egui::TouchPhase::Move, &event); runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } - event.prevent_default(); + + if should_prevent_default { + event.prevent_default(); + } } } }) @@ -691,18 +732,23 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), egui::pos2(touch.client_x() as f32, touch.client_y() as f32), ) { // First release mouse to click: - let mut should_propagate = false; + let mut should_stop_propagation = true; + let mut should_prevent_default = true; let egui_event = egui::Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed: false, modifiers: runner.input.raw.modifiers, }; - should_propagate |= (runner.web_options.should_propagate_event)(&egui_event); + should_stop_propagation &= + (runner.web_options.should_stop_propagation)(&egui_event); + should_prevent_default &= (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); // Then remove hover effect: - should_propagate |= - (runner.web_options.should_propagate_event)(&egui::Event::PointerGone); + should_stop_propagation &= + (runner.web_options.should_stop_propagation)(&egui::Event::PointerGone); + should_prevent_default &= + (runner.web_options.should_prevent_default)(&egui::Event::PointerGone); runner.input.raw.events.push(egui::Event::PointerGone); push_touches(runner, egui::TouchPhase::End, &event); @@ -710,10 +756,13 @@ fn install_touchend(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } - event.prevent_default(); + + if should_prevent_default { + event.prevent_default(); + } // Fix virtual keyboard IOS // Need call focus at the same time of event @@ -769,16 +818,20 @@ fn install_wheel(runner_ref: &WebRunner, target: &EventTarget) -> Result<(), JsV modifiers, } }; - let should_propagate = (runner.web_options.should_propagate_event)(&egui_event); + let should_stop_propagation = (runner.web_options.should_stop_propagation)(&egui_event); + let should_prevent_default = (runner.web_options.should_prevent_default)(&egui_event); runner.input.raw.events.push(egui_event); runner.needs_repaint.repaint_asap(); // Use web options to tell if the web event should be propagated to parent elements based on the egui event. - if !should_propagate { + if should_stop_propagation { event.stop_propagation(); } - event.prevent_default(); + + if should_prevent_default { + event.prevent_default(); + } }) } From 943e3618fcdf7f96d3f5f163ad741d96dbe7dbbf Mon Sep 17 00:00:00 2001 From: Hank Jordan Date: Sun, 30 Mar 2025 08:03:19 -0400 Subject: [PATCH 3/5] Improve drag-to-select text (add margins) (#5797) Might want to draw from `interaction.interact_radius` style instead of hard-coding the margin, but I didn't want to create a breaking change. If desired, I can follow up with a separate PR to address that concern. * Closes * [x] I have followed the instructions in the PR template --- crates/epaint/src/text/text_layout_types.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index 6d69045ab..b6d7ccf49 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -796,13 +796,16 @@ impl Galley { /// same as a cursor at the end. /// This allows implementing text-selection by dragging above/below the galley. pub fn cursor_from_pos(&self, pos: Vec2) -> CCursor { + // Vertical margin around galley improves text selection UX + const VMARGIN: f32 = 5.0; + if let Some(first_row) = self.rows.first() { - if pos.y < first_row.min_y() { + if pos.y < first_row.min_y() - VMARGIN { return self.begin(); } } if let Some(last_row) = self.rows.last() { - if last_row.max_y() < pos.y { + if last_row.max_y() + VMARGIN < pos.y { return self.end(); } } From 995058bbd10d8c877d49d18b2f78fc65066cb960 Mon Sep 17 00:00:00 2001 From: Alexander Nadeau Date: Sun, 30 Mar 2025 08:04:07 -0400 Subject: [PATCH 4/5] Update web-sys min version to 0.3.73 (#5862) This should prevent compilation errors (which I ran into) where eframe tries to use HtmlElement::set_autofocus(), which doesn't exist until 0.3.73. ``` error[E0599]: no method named `set_autofocus` found for struct `HtmlElement` in the current scope --> C:\Users\wareya\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\eframe-0.31.1\src\web\text_agent.rs:24:15 | 24 | input.set_autofocus(true)?; | ^^^^^^^^^^^^^ | help: there is a method `set_onfocus` with a similar name | 24 | input.set_onfocus(true)?; | ~~~~~~~~~~~ ``` * [x] I have followed the instructions in the PR template --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 92f1ce3c5..cb750bfda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,7 @@ thiserror = "1.0.37" type-map = "0.5.0" wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" -web-sys = "0.3.70" +web-sys = "0.3.73" web-time = "1.1.0" # Timekeeping for native and web wgpu = { version = "24.0.0", default-features = false } windows-sys = "0.59" From e3acd710904ecd957f9d88e3593fd7efee5768c8 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 30 Mar 2025 16:21:00 +0200 Subject: [PATCH 5/5] Make text background rects pixel-sharp (#5864) Small visual teak: make sure the background text color is pixel-aligned. --- .../tests/snapshots/rendering_test/dpi_1.50.png | 2 +- crates/egui_extras/src/syntax_highlighting.rs | 1 + crates/epaint/src/text/text_layout.rs | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) 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 132864c85..9e1b69fee 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:e6f394c2beb51d95edaf8c7ddc9ff62d3f95913ea88a3840245b6bacf8b850cc +oid sha256:334f52bfee27f9c467de739696fd7ce7c48ec9013e315dc4b2e61eee58f11287 size 907997 diff --git a/crates/egui_extras/src/syntax_highlighting.rs b/crates/egui_extras/src/syntax_highlighting.rs index 77ad0cc2d..ac51c673c 100644 --- a/crates/egui_extras/src/syntax_highlighting.rs +++ b/crates/egui_extras/src/syntax_highlighting.rs @@ -33,6 +33,7 @@ pub fn highlight( // performing it at a separate thread (ctx, ctx.style()) can be used and when ui is available // (ui.ctx(), ui.style()) can be used + #[allow(non_local_definitions)] impl egui::cache::ComputerMut<(&egui::FontId, &CodeTheme, &str, &str), LayoutJob> for Highlighter { fn compute( &mut self, diff --git a/crates/epaint/src/text/text_layout.rs b/crates/epaint/src/text/text_layout.rs index 7ce726f79..d1b2d5038 100644 --- a/crates/epaint/src/text/text_layout.rs +++ b/crates/epaint/src/text/text_layout.rs @@ -715,7 +715,7 @@ fn tessellate_row( mesh.reserve_vertices(row.glyphs.len() * 4); if format_summary.any_background { - add_row_backgrounds(job, row, &mut mesh); + add_row_backgrounds(point_scale, job, row, &mut mesh); } let glyph_index_start = mesh.indices.len(); @@ -753,7 +753,7 @@ fn tessellate_row( /// Create background for glyphs that have them. /// Creates as few rectangular regions as possible. -fn add_row_backgrounds(job: &LayoutJob, row: &Row, mesh: &mut Mesh) { +fn add_row_backgrounds(point_scale: PointScale, job: &LayoutJob, row: &Row, mesh: &mut Mesh) { if row.glyphs.is_empty() { return; } @@ -762,6 +762,7 @@ fn add_row_backgrounds(job: &LayoutJob, row: &Row, mesh: &mut Mesh) { if let Some((color, start_rect, expand)) = start { let rect = Rect::from_min_max(start_rect.left_top(), pos2(stop_x, start_rect.bottom())); let rect = rect.expand(expand); + let rect = rect.round_to_pixels(point_scale.pixels_per_point()); mesh.add_colored_rect(rect, color); } };