Skip to content

[Desktop] Layout snapping for crisp fractional scaling #90926

@ishitatsuyuki

Description

@ishitatsuyuki

Use case

Unlike mobile where high density is ubiquitous, only a portion of devices on desktop can afford to have 2x or more device pixel ratio. Meanwhile, the density baseline is slowly going up so many users end up with a fractional scaling factor like 1.25x.

Fractional scaling creates rounding problems: UIs designed for a integer pixel grid now no longer snaps to it. Flutter chooses the approach to happily draw at fractional coordinates, which allows the layout to be more scale independent. However, this comes with blurring/antialiasing artifacts, and this can be especially noticeable to some people at lower DPI.

A screenshot of Chicago's gallery below (at 125% scale) demonstrates the blurred borders.

image

You can compare this with the UI at 100% scale, where the borders snap to the pixel grid. The borders are much more crisp this way.

image

Pro tip: view at 100% scale: that is, if your system scale is 125%, then you need to set the browser zoom to 80%.

Proposal

The web platform already have a sensible answer to this question. I use Firefox as my daily driver, and its behavior is described as below:

We’re trying to meet a bunch of constraints that can’t all be satisfied at the same time (the proof is left as an exercise to the reader, though I may have actually written it out once in a Bugzilla comment):

  1. 4 adjacent objects of width/height 25% (for example) starting at one edge of a container should end exactly at the other edge; there should never be an extra pixel in the container and they should never be wrapped due to being a pixel to wide
  2. objects that are logically adjacent should always touch visually; there should never be a pixel gap or a pixel of overlap due to rounding error
  3. objects given the same width should occupy the same number of pixels
  4. object boundaries should always (visually) be aliased to a specific pixel boundary in the display (they should never be blurred)

The one [Mozilla] sacrifices is typically (3), except for borders where we sacrifice (1) by rounding the widths to pixel boundaries much earlier.
Source

So boxes are snapped to the grid after layout, as the <0.5px distortion would likely be unnoticeable. Borders on the other hand needs to have their width rounded before layout, that is, a 1dp border at 125% scale becomes 0.8dp, in addition to being snapped to the grid after layout.

As a final note, this behavior probably should be opt-in, just like how people have been fighting for hinted fonts vs unhinted fonts for ages.

A related issue is #31707, but it proposes to not support the feature described in this issue. The floating point hack, also mentioned #31707, happens in logical pixels, and therefore it does not contributes to crispness in any way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: desktopRunning on desktopc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterframeworkflutter/packages/flutter repository. See also f: labels.team-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions