microsoft / microsoft/microsoft-ui-xaml
Grid children overlap by 1px deterministically based on floating-point error
- Dominant language
- C++
- Stars
- 8.4k
- Forks
- 942
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 105
Description
### Describe the bug
When creating a Grid with two child Grids, the two Grids overlap slightly. This happens for specific combinations of the parent's padding and the first child's width.
### Why is this important?
I came across this bug because of a SplitButton in SplitButtonCommandBarStyle. The bug created a nice divider between the two sides on PointerOver. The divider was very noticeable, even if just 1px.
### Steps to reproduce the bug
1. Create a WinUI Blank App (Packaged).
2. Replace the Grid in MainWindow.xaml with the following code.
```xml
```
3. Set DPI scaling to 125%. This *will not* work on 100%.
4. Run. There will be a thin line where the two Grids overlap.
### Actual behavior
A 1px/0.8epx line appears where the two Grids overlap.
### Expected behavior
The Grids should not overlap.
### Screenshots
### NuGet package version
2.2.0
### Windows version
_No response_
### Additional context
To explain exactly which combinations of padding and width...
When scaling is 125%, 1px = 0.8epx. The padding can be any number congruent to 2 mod 4, which will be a midpoint between two multiples of 0.8. The padding and the first child will get rounded up, e.g. 2.4, 10.4 in the repro. However, the second child's positioning will first calculate 10.4 + 2.0, round the value to the nearest multiple of 0.8, and use that rounded value. (I'm just describing the observed behavior, not the implementation)
So, the bug depends on floating point accuracy. Let k satisfy 2^k < v < 2^(k + 1) where v = the previously mentioned value. The following table provides the remainders of v mod 4 where the issue occurs.
| congruency class of k mod 4 | 0.4 | 1.2 | 2.0 | 2.8 |
| --------------------------- | --- | --- | --- | --- |
| 0 | x | | | x |
| 1 | | | | x |
| 2 | | x | | |
| 3 | x | x | | |
Because the binary expansions of 0.4, 1.2, 2.8 have a period of 4, this will repeat forever.
When this happens, the second child is positioned 0.8epx to the left of where it should be. That's the bug.
Contributor guide
Research direction
Reproduce the issue in MainWindow.xaml using the provided nested Grid, with 125% DPI scaling and the stated padding and column widths. Trace the Grid layout and child positioning behavior, then verify that the two children no longer overlap and that the reproduction does not regress at other scaling combinations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- desktop, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100