AvaloniaUI/Avalonia

Incorrect borders drawn for non-uniform border thickness

tomlm opened this issue · 3 comments

tomlm commented

Describe the bug

When applying a non-uniform border thickness the layout of the content vs the layout of the strokes is off by 1 or 2 pixels
This is applying a 1 thickness border to a 8x8 rectangle. You will see that the vertical layout of the rectangle moves up and down more than the thickness of the stroke, and that the stroke has gaps between it and the rectangle.
image
image

Sometimes the stroke aligns with the rectangle, sometimes not
When the layout is horizontal then the mistakes on the strokes happen on the vertical borders
When the layout is vertical then the mistakes happen on the horizontal borders.

To Reproduce

  <StackPanel VerticalAlignment="Top" HorizontalAlignment="Left" Orientation="Horizontal">
      <Border BorderThickness="0 0 0 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="0 0 1 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="0 0 1 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="0 1 0 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="0 1 0 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="0 1 1 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="0 1 1 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 0 0 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 0 0 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 0 1 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 0 1 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 1 0 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 1 0 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 1 1 0" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
      <Border BorderThickness="1 1 1 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>

  </StackPanel>

Expected behavior

The border to be aligned with the content
The border to not have gaps between it and the content

NOTES

I discovered by trial and error that this bug only occurs when being the controls are in a stackpanel together.

If I wrap each border in its own stack panel like this:

<StackPanel>
      <Border BorderThickness="1 1 1 1" Margin="2" BorderBrush="Blue">
        <Rectangle Fill="AntiqueWhite" Width="8" Height="8"/>
      </Border>
</StackPanel>
<StackPanel>
    <Border>
        ...

Then it correctly renders all of the strokes with no errors.
image

Avalonia version

11.2.1

OS

Windows

Additional context

Related Issue

Consolonia jinek/Consolonia#200 is blocked on the resolution of this bug.

I imagine this is by design as I get similar results with WPF with the gaps. BorderThickness is a property that participates in layout, therefore you will have borders that are 8, 9, and 10px in height/width (with the 8x8 child rectangle inside). Any edge with a 0px or 1px thickness will necessarily shift the layout differently. There's some more complications with the StackPanel adjusting all of the DesiredSize height's to 10px (the tallest on the line in horizontal alignment). I removed the fixed 2px Margin which I assumed was for item separation and not for making the layout size of each item consistent.

Instead, I suggest you cover up the deficits with Padding (or Margin). See the example below:

<Window.Styles>
    <Style Selector="Rectangle">
        <Setter Property="Width" Value="8" />
        <Setter Property="Height" Value="8" />
        <Setter Property="Fill" Value="AntiqueWhite" />
    </Style>
    <Style Selector="StackPanel > Border">
        <Setter Property="BorderBrush" Value="Blue" />
    </Style>
</Window.Styles>
<Viewbox RenderOptions.EdgeMode="Aliased">
    <StackPanel
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        Orientation="Horizontal">
        <Border Padding="1,1,1,0" BorderThickness="0,0,0,1">
            <Rectangle />
        </Border>
        <Border Padding="1,1,0,1" BorderThickness="0,0,1,0">
            <Rectangle />
        </Border>
        <Border Padding="1,1,0,0" BorderThickness="0,0,1,1">
            <Rectangle />
        </Border>
        <Border Padding="1,0,1,1" BorderThickness="0,1,0,0">
            <Rectangle />
        </Border>
        <Border Padding="1,0,1,0" BorderThickness="0,1,0,1">
            <Rectangle />
        </Border>
        <Border Padding="1,0,0,1" BorderThickness="0,1,1,0">
            <Rectangle />
        </Border>
        <Border Padding="1,0,0,0" BorderThickness="0,1,1,1">
            <Rectangle />
        </Border>
        <Border Padding="0,1,1,1" BorderThickness="1,0,0,0">
            <Rectangle />
        </Border>
        <Border Padding="0,1,1,0" BorderThickness="1,0,0,1">
            <Rectangle />
        </Border>
        <Border Padding="0,1,0,1" BorderThickness="1,0,1,0">
            <Rectangle />
        </Border>
        <Border Padding="0,1,0,0" BorderThickness="1,0,1,1">
            <Rectangle />
        </Border>
        <Border Padding="0,0,1,1" BorderThickness="1,1,0,0">
            <Rectangle />
        </Border>
        <Border Padding="0,0,1,0" BorderThickness="1,1,0,1">
            <Rectangle />
        </Border>
        <Border Padding="0,0,0,1" BorderThickness="1,1,1,0">
            <Rectangle />
        </Border>
        <Border Padding="0,0,0,0" BorderThickness="1,1,1,1">
            <Rectangle />
        </Border>
    </StackPanel>
</Viewbox>

image

Please leave the issue open for a maintainer to decide.

tomlm commented

Thanks, that indeed helps immensely. It feels wrong to have the gaps between the edge of the rectangle and the strokes, but at with padding I do indeed have a workaround which makes relative sense.

Are you using LayoutRounding probably or SnapToDevicePixels?