Browse Source

Fix blurry rendering in some browsers (#4299)

* Closes https://github.com/emilk/egui/issues/4241

I would love some more testers of this.

I'm not sure if we really need the round-to-even code, but I'm hesitant
to out-right revert https://github.com/emilk/egui/pull/151 when I cannot
reproduce its problem. Keeping it seems quite safe though.

---
# Testing
Checkout the branch and run:

* `./scripts/start_server.sh`
* `./scripts/build_demo_web.sh` and then open
`http://localhost:8888/index.html#Rendering`
* `./scripts/build_demo_web.sh --wgpu` and then open
`http://localhost:8888/index.html#Rendering`

Check the "Rendering test" that the squares in the pixel alignment test
are perfectly sharp, like this:

<img width="576" alt="Screenshot 2024-04-01 at 13 27 20"
src="https://github.com/emilk/egui/assets/1148717/fb6c4824-9e25-4304-bc0c-3c50fbd44a52">

If it looks something like this, something is WRONG:
<img width="488" alt="Screenshot 2024-04-01 at 13 29 07"
src="https://github.com/emilk/egui/assets/1148717/04bd93ff-2108-40c5-95f6-76e3bcb9cd7f">


Please try it on different zoom levels in different browsers, and if
possible on different monitors with different native dpi scaling. Report
back the results!


### Mac
I have tested on a high-DPI Mac:
* Chromium (Brave):  Can reproduce problem on `master`, and it's now
fixed
* Firefox:   Can reproduce problem on `master`, and it's now fixed
* Safari:  Can't get it to work; giving up for now
pull/4301/head
Emil Ernerfeldt 7 months ago
committed by GitHub
parent
commit
0a40b16bd4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 51
      crates/eframe/src/web/mod.rs
  2. 7
      web_demo/index.html

51
crates/eframe/src/web/mod.rs

@ -130,51 +130,46 @@ fn resize_canvas_to_screen_size(
) -> Option<()> { ) -> Option<()> {
let parent = canvas.parent_element()?; let parent = canvas.parent_element()?;
// In this function we use "pixel" to mean physical pixel,
// and "point" to mean "logical CSS pixel".
let pixels_per_point = native_pixels_per_point();
// Prefer the client width and height so that if the parent // Prefer the client width and height so that if the parent
// element is resized that the egui canvas resizes appropriately. // element is resized that the egui canvas resizes appropriately.
let width = parent.client_width(); let parent_size_points = Vec2 {
let height = parent.client_height(); x: parent.client_width() as f32,
y: parent.client_height() as f32,
let canvas_real_size = Vec2 {
x: width as f32,
y: height as f32,
}; };
if width <= 0 || height <= 0 { if parent_size_points.x <= 0.0 || parent_size_points.y <= 0.0 {
log::error!("egui canvas parent size is {}x{}. Try adding `html, body {{ height: 100%; width: 100% }}` to your CSS!", width, height); log::error!("The parent element of the egui canvas is {}x{}. Try adding `html, body {{ height: 100%; width: 100% }}` to your CSS!", parent_size_points.x, parent_size_points.y);
} }
let pixels_per_point = native_pixels_per_point(); // We take great care here to ensure the rendered canvas aligns
// perfectly to the physical pixel grid, lest we get blurry text.
// At the time of writing, we get pixel perfection on Chromium and Firefox on Mac,
// but Desktop Safari will be blurry on most zoom levels.
// See https://github.com/emilk/egui/issues/4241 for more.
let max_size_pixels = pixels_per_point * max_size_points; let canvas_size_pixels = pixels_per_point * parent_size_points.min(max_size_points);
let canvas_size_pixels = pixels_per_point * canvas_real_size; // Make sure that the size is always an even number of pixels,
let canvas_size_pixels = canvas_size_pixels.min(max_size_pixels);
let canvas_size_points = canvas_size_pixels / pixels_per_point;
// Make sure that the height and width are always even numbers.
// otherwise, the page renders blurry on some platforms. // otherwise, the page renders blurry on some platforms.
// See https://github.com/emilk/egui/issues/103 // See https://github.com/emilk/egui/issues/103
fn round_to_even(v: f32) -> f32 { let canvas_size_pixels = (canvas_size_pixels / 2.0).round() * 2.0;
(v / 2.0).round() * 2.0
} let canvas_size_points = canvas_size_pixels / pixels_per_point;
canvas canvas
.style() .style()
.set_property( .set_property("width", &format!("{}px", canvas_size_points.x))
"width",
&format!("{}px", round_to_even(canvas_size_points.x)),
)
.ok()?; .ok()?;
canvas canvas
.style() .style()
.set_property( .set_property("height", &format!("{}px", canvas_size_points.y))
"height",
&format!("{}px", round_to_even(canvas_size_points.y)),
)
.ok()?; .ok()?;
canvas.set_width(round_to_even(canvas_size_pixels.x) as u32); canvas.set_width(canvas_size_pixels.x as u32);
canvas.set_height(round_to_even(canvas_size_pixels.y) as u32); canvas.set_height(canvas_size_pixels.y as u32);
Some(()) Some(())
} }

7
web_demo/index.html

@ -37,7 +37,12 @@
width: 100%; width: 100%;
} }
/* Position canvas in center-top: */ /* Position canvas in center-top.
This is rather arbitrarily chosen.
In particular, it seems like both Chromium and Firefox will still align
the canvas on the physical pixel grid, which is required to get
pixel-perfect (non-blurry) rendering in egui.
See https://github.com/emilk/egui/issues/4241 for more */
canvas { canvas {
margin-right: auto; margin-right: auto;
margin-left: auto; margin-left: auto;

Loading…
Cancel
Save