Просмотр исходного кода

Fix TileBrush Source/DestinationRect handling (#15289)

* Fix TileBrush Source/DestinationRect handling

* Add unit test

* Add cross render tests

* Add missing test image
Benedikt Stebner 1 год назад
Родитель
Сommit
544d5372e3

+ 15 - 24
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@@ -1160,35 +1160,21 @@ namespace Avalonia.Skia
                 return;
             }
 
-            var brushTransform = Matrix.CreateTranslation(-contentBounds.Position);
-
-            contentBounds = contentBounds.TransformToAABB(brushTransform);
+            var brushTransform = Matrix.Identity;
 
             var destinationRect = content.Brush.DestinationRect.ToPixels(targetRect.Size);
 
-            if (tileBrush.Stretch != Stretch.None)
-            {
-                //scale content to destination size
-                var scale = tileBrush.Stretch.CalculateScaling(destinationRect.Size, contentBounds.Size);
-
-                var scaleTransform = Matrix.CreateScale(scale);
-
-                contentBounds = contentBounds.TransformToAABB(scaleTransform);
-
-                brushTransform *= scaleTransform;
-            }
-
             var sourceRect = tileBrush.SourceRect.ToPixels(contentBounds);
 
-            //scale content to source size
-            if (contentBounds.Size != sourceRect.Size)
+            brushTransform *= Matrix.CreateTranslation(-sourceRect.Position);
+
+            if (sourceRect.Size != destinationRect.Size)
             {
-                var scale = tileBrush.Stretch.CalculateScaling(sourceRect.Size, contentBounds.Size);
+                //scale source to destination size
+                var scale = tileBrush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size);
 
                 var scaleTransform = Matrix.CreateScale(scale);
 
-                contentBounds = contentBounds.TransformToAABB(scaleTransform);
-
                 brushTransform *= scaleTransform;
             }
 
@@ -1199,11 +1185,16 @@ namespace Avalonia.Skia
                 var transformOrigin = content.TransformOrigin.ToPixels(targetRect);
                 var offset = Matrix.CreateTranslation(transformOrigin);
                 transform = -offset * content.Transform.Value * offset;
-            }
 
-            if (content.Brush.TileMode == TileMode.None)
-            {
-                brushTransform *= transform;
+                if (tileBrush.TileMode == TileMode.None)
+                {
+                    brushTransform *= transform;
+
+                    destinationRect = destinationRect.TransformToAABB(transform);
+
+                    destinationRect = new Rect(0, 0, destinationRect.Left + destinationRect.Width,
+                        destinationRect.Top + destinationRect.Height);
+                }
             }
 
             if (tileBrush.Stretch == Stretch.None && transform == Matrix.Identity)

+ 61 - 0
tests/Avalonia.RenderTests/CrossTests/Brushes/CrossTileBrushTests.cs

@@ -1,3 +1,4 @@
+using System.Collections.Generic;
 using Avalonia.Media;
 using CrossUI;
 using Xunit;
@@ -51,4 +52,64 @@ public class CrossTileBrushTests : CrossTestBase
         });
 
     }
+
+    [CrossFact]
+    public void Should_Render_Scaled_TileBrush()
+    {
+        var brush = new CrossDrawingBrush
+        {
+            TileMode = TileMode.Tile,
+            Viewbox = new Rect(0, 0, 20, 20),
+            ViewboxUnits = BrushMappingMode.Absolute,
+            Viewport = new Rect(0, 0, 20, 20),
+            ViewportUnits = BrushMappingMode.Absolute,
+            Drawing = new CrossGeometryDrawing(new CrossSvgGeometry("M 0 0 l 50 50"))
+            {
+                Pen = new CrossPen { Brush = new CrossSolidColorBrush(Colors.Red), Thickness = 5 }
+            }
+        };
+
+        RenderAndCompare(new CrossControl()
+        {
+            Width = 100,
+            Height = 100,
+            Background = brush
+        });
+
+    }
+
+    [CrossFact]
+    public void Should_Render_With_Transform()
+    {
+        var brush = new CrossDrawingBrush()
+        {
+            TileMode = TileMode.None,
+            Viewbox = new Rect(0, 0, 1, 1),
+            ViewboxUnits = BrushMappingMode.RelativeToBoundingBox,
+            Viewport = new Rect(0, 0, 50, 50),
+            ViewportUnits = BrushMappingMode.Absolute,
+            Transform = Matrix.CreateTranslation(150, 150),
+            Drawing = new CrossDrawingGroup()
+            {
+                Children = new List<CrossDrawing>()
+                {
+                    new CrossGeometryDrawing(new CrossRectangleGeometry(new(0, 0, 100, 100)))
+                    {
+                        Brush = new CrossSolidColorBrush(Colors.Crimson)
+                    },
+                    new CrossGeometryDrawing(new CrossRectangleGeometry(new(20, 20, 60, 60)))
+                    {
+                        Brush = new CrossSolidColorBrush(Colors.Blue)
+                    }
+                }
+            }
+        };
+
+        RenderAndCompare(new CrossControl()
+        {
+            Width = 200,
+            Height = 200,
+            Background = brush
+        });
+    }
 }

+ 2 - 2
tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs

@@ -107,8 +107,8 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 _brush = new DrawingBrush()
                 {
                     TileMode = TileMode.None,
-                    SourceRect = new RelativeRect(0, 0, 50, 50, RelativeUnit.Absolute),
-                    DestinationRect = new RelativeRect(0, 0, 1, 1, RelativeUnit.Relative),
+                    SourceRect = new RelativeRect(0, 0, 1, 1, RelativeUnit.Relative),
+                    DestinationRect = new RelativeRect(0, 0, 50, 50, RelativeUnit.Absolute),
                     Transform = new TranslateTransform(150, 150),
                     Drawing = new DrawingGroup()
                     {

+ 29 - 1
tests/Avalonia.RenderTests/Media/TileBrushTests.cs

@@ -40,7 +40,35 @@ public class DrawingBrushTests: TestBase
         await RenderToFile(target);
         CompareImages();
     }
-    
+
+
+    [Fact]
+    public async Task DrawingBrushIsProperlyScaled()
+    {
+        Decorator target = new Decorator
+        {
+            Padding = new Thickness(10),
+            Width = 220,
+            Height = 220,
+            Child = new Rectangle
+            {
+                Fill = new DrawingBrush
+                {
+                    TileMode = TileMode.Tile,
+                    SourceRect = new RelativeRect(0, 0, 20, 20, RelativeUnit.Absolute),
+                    DestinationRect = new RelativeRect(0, 0, 20, 20, RelativeUnit.Absolute),
+                    Drawing = new GeometryDrawing()
+                    {
+                        Pen = new Pen(Brushes.Red, 5),
+                        Geometry = Geometry.Parse("M 0 0 l 50 50")
+                    }
+                }
+            }
+        };
+
+        await RenderToFile(target);
+        CompareImages();
+    }
 
 #if AVALONIA_SKIA
     [Fact]

BIN
tests/TestFiles/CrossTests/Media/TileBrushes/Should_Render_Scaled_TileBrush.wpf.png


BIN
tests/TestFiles/CrossTests/Media/TileBrushes/Should_Render_With_Transform.wpf.png


BIN
tests/TestFiles/Direct2D1/Media/DrawingBrush/DrawingBrushIsProperlyScaled.expected.png


BIN
tests/TestFiles/Skia/Media/DrawingBrush/DrawingBrushIsProperlyScaled.expected.png