Browse Source

Pass correct node bounds to PushOpacityMask. (#1870)

* Pass correct node bounds.

Use node bounds not clip bounds for opacity mask rect.

Fixes #1118.

* Use layout bounds for opacity mask.

And added a new render test to make sure that the render transform is applied to it.

* Fix bad XAML formatting.
Steven Kirk 7 years ago
parent
commit
d15e86c2a7

+ 2 - 1
samples/ControlCatalog/Pages/CanvasPage.xaml

@@ -11,7 +11,8 @@
               <GradientStop Offset="1" Color="Transparent"/>
             </LinearGradientBrush.GradientStops>
           </LinearGradientBrush>
-        </Rectangle.OpacityMask>      </Rectangle>
+        </Rectangle.OpacityMask>     
+      </Rectangle>
       <Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="88" Canvas.Top="100"/>
       <Path Fill="Orange" Data="M 0,0 c 0,0 50,0 50,-50 c 0,0 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
       <Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">

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

@@ -30,19 +30,20 @@ namespace Avalonia.Rendering.SceneGraph
         Matrix Transform { get; }
 
         /// <summary>
-        /// Gets the bounds for the node's geometry in global coordinates.
+        /// Gets the bounds of the node's geometry in global coordinates.
         /// </summary>
         Rect Bounds { get; }
 
         /// <summary>
         /// Gets the clip bounds for the node in global coordinates.
         /// </summary>
-        /// <remarks>
-        /// This clip does not take into account parent clips, to find the absolute clip bounds
-        /// it is necessary to traverse the tree.
-        /// </remarks>
         Rect ClipBounds { get; }
 
+        /// <summary>
+        /// Gets the layout bounds for the node in global coordinates.
+        /// </summary>
+        Rect LayoutBounds { get; }
+
         /// <summary>
         /// Whether the node is clipped to <see cref="ClipBounds"/>.
         /// </summary>

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

@@ -167,8 +167,9 @@ namespace Avalonia.Rendering.SceneGraph
                 using (context.PushPostTransform(m))
                 using (context.PushTransformContainer())
                 {
+                    var globalBounds = bounds.TransformToAABB(contextImpl.Transform);
                     var clipBounds = clipToBounds ?
-                        bounds.TransformToAABB(contextImpl.Transform).Intersect(clip) :
+                        globalBounds.Intersect(clip) :
                         clip;
 
                     forceRecurse = forceRecurse ||
@@ -179,6 +180,7 @@ namespace Avalonia.Rendering.SceneGraph
                     node.Transform = contextImpl.Transform;
                     node.ClipBounds = clipBounds;
                     node.ClipToBounds = clipToBounds;
+                    node.LayoutBounds = globalBounds;
                     node.GeometryClip = visual.Clip?.PlatformImpl;
                     node.Opacity = opacity;
 

+ 4 - 1
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@@ -58,6 +58,9 @@ namespace Avalonia.Rendering.SceneGraph
         /// <inheritdoc/>
         public Rect ClipBounds { get; set; }
 
+        /// <inheritdoc/>
+        public Rect LayoutBounds { get; set; }
+
         /// <inheritdoc/>
         public bool ClipToBounds { get; set; }
 
@@ -266,7 +269,7 @@ namespace Avalonia.Rendering.SceneGraph
 
             if (OpacityMask != null)
             {
-                context.PushOpacityMask(OpacityMask, ClipBounds);
+                context.PushOpacityMask(OpacityMask, LayoutBounds);
             }
         }
 

+ 37 - 0
tests/Avalonia.RenderTests/OpacityMaskTests.cs

@@ -55,5 +55,42 @@ namespace Avalonia.Direct2D1.RenderTests
             await RenderToFile(target);
             CompareImages();
         }
+
+        [Fact]
+        public async Task RenderTansform_Applies_To_Opacity_Mask()
+        {
+            var target = new Canvas
+            {
+                OpacityMask = new LinearGradientBrush
+                {
+                    StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
+                    EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative),
+                    GradientStops = new List<GradientStop>
+                    {
+                        new GradientStop(Color.FromUInt32(0xffffffff), 0),
+                        new GradientStop(Color.FromUInt32(0x00ffffff), 1)
+                    }
+                },
+                RenderTransform = new RotateTransform(90),
+                Width = 76,
+                Height = 76,
+                Children =
+                {
+                    new Path
+                    {
+                        Width = 32,
+                        Height = 40,
+                        [Canvas.LeftProperty] = 23,
+                        [Canvas.TopProperty] = 18,
+                        Stretch = Stretch.Fill,
+                        Fill = Brushes.Red,
+                        Data = StreamGeometry.Parse("F1 M 27,18L 23,26L 33,30L 24,38L 33,46L 23,50L 27,58L 45,58L 55,38L 45,18L 27,18 Z")
+                    }
+                }
+            };
+
+            await RenderToFile(target);
+            CompareImages();
+        }
     }
 }

BIN
tests/TestFiles/Direct2D1/OpacityMask/RenderTansform_Applies_To_Opacity_Mask.expected.png


BIN
tests/TestFiles/Skia/OpacityMask/RenderTansform_Applies_To_Opacity_Mask.expected.png