Browse Source

Fix opacity mask rendering.

We're potentially creating a new immutable version of the opacity mask each time the `VisualNode` is updated. Need to implement comparison between mutable and immutable brushes.
Steven Kirk 8 years ago
parent
commit
2a87dbd6ca

+ 3 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@@ -178,7 +178,9 @@ namespace Avalonia.Rendering.SceneGraph
                     node.ClipToBounds = clipToBounds;
                     node.GeometryClip = visual.Clip?.PlatformImpl;
                     node.Opacity = opacity;
-                    node.OpacityMask = visual.OpacityMask;
+
+                    // TODO: Check equality between node.OpacityMask and visual.OpacityMask before assigning.
+                    node.OpacityMask = visual.OpacityMask?.ToImmutable();
 
                     if (ShouldStartLayer(visual))
                     {

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

@@ -231,6 +231,11 @@ namespace Avalonia.Rendering.SceneGraph
                 context.PushOpacity(Opacity);
             }
 
+            if (OpacityMask != null)
+            {
+                context.PushOpacityMask(OpacityMask, ClipBounds);
+            }
+
             context.Transform = Transform;
 
             if (GeometryClip != null)
@@ -247,6 +252,11 @@ namespace Avalonia.Rendering.SceneGraph
                 context.PopGeometryClip();
             }
 
+            if (OpacityMask != null)
+            {
+                context.PopOpacityMask();
+            }
+
             if (Opacity != 1 && !skipOpacity)
             {
                 context.PopOpacity();

+ 26 - 0
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

@@ -165,6 +165,32 @@ namespace Avalonia.Visuals.UnitTests.Rendering
             context.Verify(x => x.PopOpacity(), Times.Never);
         }
 
+        [Fact]
+        public void Should_Push_Opacity_Mask()
+        {
+            var root = new TestRoot
+            {
+                Width = 100,
+                Height = 100,
+                Child = new Border
+                {
+                    Background = Brushes.Red,
+                    OpacityMask = Brushes.Green,
+                }
+            };
+
+            root.Measure(Size.Infinity);
+            root.Arrange(new Rect(root.DesiredSize));
+
+            var target = CreateTargetAndRunFrame(root);
+            var context = GetLayerContext(target, root);
+            var animation = new BehaviorSubject<double>(0.5);
+
+            context.Verify(x => x.PushOpacityMask(Brushes.Green, new Rect(0, 0, 100, 100)), Times.Once);
+            context.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once);
+            context.Verify(x => x.PopOpacityMask(), Times.Once);
+        }
+
         [Fact]
         public void Should_Create_Layer_For_Root()
         {