Skip to content

Grid children overlap by 1px deterministically based on floating-point error #11166

@abdullahas2883

Description

@abdullahas2883

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.
    <Grid Padding="2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid Background="#80808080"/>
        <Grid Grid.Column="1"
              Background="#80808080"/>
    </Grid>
  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

Image

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageIssue needs to be triaged by the area owners

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions