iced-rs / iced

A cross-platform GUI library for Rust, inspired by Elm
https://iced.rs
MIT License
24.15k stars 1.12k forks source link

Different widget types do not agree on how to align to pixel grid #2546

Open peterkrull opened 1 month ago

peterkrull commented 1 month ago

Is your issue REALLY a bug?

Is there an existing issue for this?

Is this issue related to iced?

What happened?

I am currently using Cosmic, but I have also tested this on the latest iced master. I have noticed that various parts of the UI (in Cosmic) seem to "shimmer" or "wiggle", due to how different elements/widgets get rasterized. For example, text will always "jump" up or down one entire pixel at a time, but the quad of a button, will "smoothly" glide across pixels. Even a 1-pixel wide border on the quad will be able to sit between pixels, causing it to become become slightly blurred.

This is a video from Cosmic settings.

https://github.com/user-attachments/assets/4b87e56b-7b2a-4a78-b0e8-462747c63aef

And on the current Iced master, I am able to produce this:

https://github.com/user-attachments/assets/645b6e49-161d-4b2a-a05f-38b7d320a867

The border is supposed to have a 1px white border, but the sides are obviously 2px wide, and muted in color. Also the number of pixels between lines of text keep changing, instead of staying the same.

What is the expected behavior?

I would expect (or at least have the option to enforce) that everything is rendered aligned to the pixel grid. Such that a 1px border is only and always 1px on my monitor. Or that the distance between two lines of text are always x pixels when scrolling, instead of constantly swapping between x and 1+x pixel distance.

Essentially when scrolling a static page, I would like to have the contents be pixel-perfect identical, just shifted up or down by some number of pixels.

Version

master

Operating System

Linux

Do you have any log output?

No response

hecrj commented 1 month ago

Let's say you have a container that is 4px wide and you want to draw a vertical line of 1px in its center. What would you expect?

When we pixel snap the line and it appears off-center, wouldn't then the bug be that the line isn't centered? Which poison do we pick?

hecrj commented 1 month ago

I believe the gist of what you are noticing here is simply vertical text hinting performed by cosmic-text (which I coincidentally introduced here: https://github.com/pop-os/cosmic-text/pull/143) together with our rudimentary anti-aliasing strategy in our quad pipeline.

Pixel snapping is precisely what causes the uneven distances between primitives. We want the opposite.

hecrj commented 1 month ago

For more context, everything is measured in logical pixels in iced. The UI primitives exist in an ideal world where pixels are infinite in a continuous space.

The pixel grid is seen as a hardware limitation that must be dealt with to project the UI primitives into the physical world; and therefore what you see through your screen is an approximation of the actual UI. The lower your resolution is, the more apparent the approximation errors become. It's this approximation that needs work.

There is no way to say in iced that a border should be 1 physical pixel. There are good reasons for this, but mainly it's because of fractional scaling support (HiDPI) and subpixel offsetting (i.e. the problem I posed earlier).

peterkrull commented 1 month ago

Thanks for the response. Though it is unclear to me whether you believe this is all intended behavior, or whether it is something we should have a way to remedy. Even any approximation will become significantly less noticeable on HiDPI displays, most people are presumably still using displays where pixel-width inconsistencies are visible.

Perhaps my issue is two-fold

First point

As you mentioned, text hinting causes those elements to align vertically to the pixel grid. An issue is then that different text elements are not guaranteed to shift up and down at the same time, causing inconsistent pixel-spacing between text elements over time, as both videos in the issue show. The distance between text and containers will also be inconsistent.

Second point

Then, consider this switch in cosmic, sitting inside of a larger container in the settings app. Both the switch outline, the switch handle, and the container all have a row/column of "transition" pixels, making them slightly blurry. Now, if it was consistently this blurry, that would be one thing. But because it is sitting inside of a container which is centered within a window that may be an even or odd number of pixels, it is sort of random whether it is slightly blurry or sharp.

screenshot-2024-08-12-09-42-55

All together

I would personally prefer that such elements alternate between being 1 pixel off center, than all elements alternating between being blurry and crisp. I would also expect when scrolling on a page with a bunch of elements, that if some elements (like text) snap to the grid, then nothing should move even one pixel, until everything is ready to move 1 pixel. It is just inconsistent to have different elements move at different times, with some jumping an entire pixel, and others smoothly gliding between the pixels.

I hope I am getting my point across and not just rambling. This problem is obviously not unique to Iced, and I do not believe I have noticed similar behavior in applications using other toolkits.

hecrj commented 1 month ago

The issue is not the subpixel offsetting, but the blurriness and snapping being noticeable. As I said, this is caused by vertical text hinting and a rudimentary anti-aliasing strategy; mostly noticeable in displays with low pixel density.

If I didn't think it was an issue that needed to be solved, I would have closed it. That said, I don't think it will be a priority in quite some time.

peterkrull commented 1 month ago

Fair enough. I just didn't gather whether you had understood my issue.