AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
25.96k stars 2.25k forks source link

Zero-length subpaths are drawn in Geometry #4913

Open joneuhauser opened 4 years ago

joneuhauser commented 4 years ago

Avalonia 0.10.0-preview5, Windows 10, Visual Studio

Consider the following XAML, converted with https://github.com/BerndK/SvgToXaml (and slightly modified to match Avalonia syntax):

<Window.Resources>
    <Geometry x:Key="redoGeometry1">F1 M50.799999,50.799999z M0,0z M 37.14073,21.33593 49.741711,33.91947 37.140724,46.50301</Geometry>
    <Geometry x:Key="redoGeometry2">F1 M50.799999,50.799999z M0,0z M 29.121941,58.32464 H 14.149799 c -7.2526715,0 -13.0914653,-5.44356 -13.0914653,-12.20531 0,-6.76172 5.8387938,-12.2053 13.0914653,-12.2053 h 34.89083</Geometry>
    <DrawingGroup x:Key="redoDrawingGroup" >
      <DrawingGroup Opacity="1" Transform="1,0,0,1,0,-246.2">
        <GeometryDrawing Geometry="{StaticResource redoGeometry1}">
          <GeometryDrawing.Pen>
            <Pen Brush="#FF000000" Thickness="2.11666656" LineCap="Round" LineJoin="Round" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
        <GeometryDrawing Geometry="{StaticResource redoGeometry2}">
          <GeometryDrawing.Pen>
            <Pen Brush="#FF000000" Thickness="2.11666656" LineCap="Round" LineJoin="Round" />
          </GeometryDrawing.Pen>
        </GeometryDrawing>
      </DrawingGroup>
    </DrawingGroup>
    <DrawingImage x:Key="redoDrawingImage" Drawing="{StaticResource redoDrawingGroup}" />
  </Window.Resources>
  <Grid>
    <Image Source="{StaticResource redoDrawingImage}"/> 
  </Grid>

This gets rendered as follows: grafik

The two specks at the top and the right are zero-length subpaths at the beginning of the path, and probably come from an attempt of XamlToSVG to set the bounding box of the drawing (which is futile for multiple reasons, but not relevant here).

In WPF, these dots are not rendered, and also not taken into account for bounding box computation.

Looking at the SVG specification, it seems correct to render them: https://www.w3.org/TR/SVG/paths.html#ZeroLengthSegments (I guess that's where the path syntax comes from).

The WPF documentation doesn't mention this case: https://docs.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/path-markup-syntax?view=netframeworkdesktop-4.8

If this difference between Avalonia and WPF is intentional, I'll gladly close this issue.

(Another difference is that WPF takes the stroke width into account for computing the bounding box, so the bottom line doesn't get clipped)

mgnslndh commented 1 year ago

I've been looking into this issue but I need some guidance to be able to proceed.

The core issue is regarding if empty figures should be drawn or not. According to the SVG spec they should, at least under some conditions, be drawn. But WPF does not draw them. I guess that we are aiming for WPF compatibility over SVG compatibility or maybe both?

Where do we fix this? Should the parser skip empty figures? Or do we remove empty figures after they've been parsed? Do we keep them all the way until we're drawing? What would be the best solution?

I made a quick test as a proof of concet where PathGeometry:Parse would remove any empty figures and that solves the problem described in this issue.

However, StreamGeometry (the parent of PathGeometry) has its own parse method and is mostly a shim over the platform API and there is no abstraction for figures. At this level I guess you are left to two options; 1) remove empty figures while parsing, or, 2) introduce a method that will return a copy of the geometry where the empty figures (sub paths) are removed. This method would need to be supported by the platform as well.

Gillibald commented 1 year ago

When I worked on the parser the goal was to follow the SVG specification as close as possible. So if the spec explicitly mentions this case it should be handled accordingly.

mgnslndh commented 1 year ago

In that case it seems like the current implementation is correct. I guess then that we either close this issue as "by design" or make it possible to clean the path from empty figures so that it will render as in WPF. It would be easy to add such a method to PathGeometry. For XAML perhaps a converter. However, not sure how important this is.

kekekeks commented 1 year ago

We should be following what WPF does for geometries, so it's a bug.

Gillibald commented 1 year ago

The issue here is that for zero-length paths a line cap is drawn