浏览代码

Make geometry clips work.

Still problems with hit-testing and geometry clips aren't propogated to
new layers.
Steven Kirk 8 年之前
父节点
当前提交
bfd8c04149

+ 5 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/IVisualNode.cs

@@ -42,6 +42,11 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         /// </summary>
         bool ClipToBounds { get; }
         bool ClipToBounds { get; }
 
 
+        /// <summary>
+        /// Gets the node's clip geometry, if any.
+        /// </summary>
+        Geometry GeometryClip { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets the child scene graph nodes.
         /// Gets the child scene graph nodes.
         /// </summary>
         /// </summary>

+ 11 - 2
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

@@ -3,6 +3,7 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using Avalonia;
 using Avalonia.VisualTree;
 using Avalonia.VisualTree;
 
 
 namespace Avalonia.Rendering.SceneGraph
 namespace Avalonia.Rendering.SceneGraph
@@ -98,13 +99,21 @@ namespace Avalonia.Rendering.SceneGraph
         {
         {
             if (filter?.Invoke(node.Visual) != false)
             if (filter?.Invoke(node.Visual) != false)
             {
             {
+                var clipped = false;
+
                 if (node.ClipToBounds)
                 if (node.ClipToBounds)
                 {
                 {
-                    // TODO: Handle geometry clip.
                     clip = clip == null ? node.ClipBounds : clip.Value.Intersect(node.ClipBounds);
                     clip = clip == null ? node.ClipBounds : clip.Value.Intersect(node.ClipBounds);
+                    clipped = !clip.Value.Contains(p);
+                }
+
+                if (node.GeometryClip != null)
+                {
+                    var controlPoint = Root.Visual.TranslatePoint(p, node.Visual);
+                    clipped = !node.GeometryClip.FillContains(p);
                 }
                 }
 
 
-                if (!clip.HasValue || clip.Value.Contains(p))
+                if (!clipped)
                 {
                 {
                     for (var i = node.Children.Count - 1; i >= 0; --i)
                     for (var i = node.Children.Count - 1; i >= 0; --i)
                     {
                     {

+ 10 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@@ -221,11 +221,21 @@ namespace Avalonia.Rendering.SceneGraph
             }
             }
 
 
             context.Transform = Transform;
             context.Transform = Transform;
+
+            if (GeometryClip != null)
+            {
+                context.PushGeometryClip(GeometryClip);
+            }
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         public void EndRender(IDrawingContextImpl context)
         public void EndRender(IDrawingContextImpl context)
         {
         {
+            if (GeometryClip != null)
+            {
+                context.PopGeometryClip();
+            }
+
             if (ClipToBounds)
             if (ClipToBounds)
             {
             {
                 context.PopClip();
                 context.PopClip();

+ 24 - 0
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs

@@ -598,6 +598,30 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
             }
             }
         }
         }
 
 
+        [Fact]
+        public void Should_Set_GeometryClip()
+        {
+            using (TestApplication())
+            {
+                var clip = StreamGeometry.Parse("M100,0 L0,100 100,100");
+                Decorator decorator;
+                var tree = new TestRoot
+                {
+                    Child = decorator = new Decorator
+                    {
+                        Clip = clip,
+                    }
+                };
+
+                var scene = new Scene(tree);
+                var sceneBuilder = new SceneBuilder();
+                sceneBuilder.UpdateAll(scene);
+
+                var decoratorNode = scene.FindNode(decorator);
+                Assert.Same(clip, decoratorNode.GeometryClip);
+            }
+        }
+
         private IDisposable TestApplication()
         private IDisposable TestApplication()
         {
         {
             return UnitTestApplication.Start(
             return UnitTestApplication.Start(

+ 7 - 1
tests/Avalonia.Visuals.UnitTests/VisualTree/VisualExtensionsTests_GetVisualsAt.cs

@@ -455,6 +455,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
             using (TestApplication())
             using (TestApplication())
             {
             {
                 Border border;
                 Border border;
+                Canvas canvas;
                 var container = new TestRoot
                 var container = new TestRoot
                 {
                 {
                     Width = 200,
                     Width = 200,
@@ -463,6 +464,11 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
                     {
                     {
                         Background = Brushes.Red,
                         Background = Brushes.Red,
                         Clip = StreamGeometry.Parse("M100,0 L0,100 100,100"),
                         Clip = StreamGeometry.Parse("M100,0 L0,100 100,100"),
+                        Child = canvas = new Canvas
+                        {
+                            Background = Brushes.Yellow,
+                            Margin = new Thickness(10),
+                        }
                     }
                     }
                 };
                 };
 
 
@@ -472,7 +478,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
                 var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
                 var context = new DrawingContext(Mock.Of<IDrawingContextImpl>());
 
 
                 var result = container.GetVisualsAt(new Point(100, 100));
                 var result = container.GetVisualsAt(new Point(100, 100));
-                Assert.Equal(new[] { border }, result);
+                Assert.Equal(new IVisual[] { canvas, border }, result);
 
 
                 result = container.GetVisualsAt(new Point(10, 10));
                 result = container.GetVisualsAt(new Point(10, 10));
                 Assert.Empty(result);
                 Assert.Empty(result);