Browse Source

Fix PushOpacity when ClipToBounds is false

Benedikt Stebner 2 years ago
parent
commit
101cdc5257

+ 3 - 4
src/Avalonia.Base/Media/DrawingContext.cs

@@ -360,16 +360,15 @@ namespace Avalonia.Media
         /// Pushes an opacity value.
         /// </summary>
         /// <param name="opacity">The opacity.</param>
-        /// <param name="bounds">The bounds.</param>
         /// <returns>A disposable used to undo the opacity.</returns>
-        public PushedState PushOpacity(double opacity, Rect bounds)
+        public PushedState PushOpacity(double opacity)
         {
-            PushOpacityCore(opacity, bounds);
+            PushOpacityCore(opacity);
             _states ??= StateStackPool.Get();
             _states.Push(new RestoreState(this, RestoreState.PushedStateType.Opacity));
             return new PushedState(this);
         }
-        protected abstract void PushOpacityCore(double opacity, Rect bounds);
+        protected abstract void PushOpacityCore(double opacity);
 
         /// <summary>
         /// Pushes an opacity mask.

+ 14 - 8
src/Avalonia.Base/Media/DrawingGroup.cs

@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using Avalonia.Media.Imaging;
 using Avalonia.Metadata;
 using Avalonia.Platform;
 using Avalonia.Rendering.SceneGraph;
@@ -72,9 +71,8 @@ namespace Avalonia.Media
         internal override void DrawCore(DrawingContext context)
         {
             var bounds = GetBounds();
-
             using (context.PushTransform(Transform?.Value ?? Matrix.Identity))
-            using (context.PushOpacity(Opacity, bounds))
+            using (context.PushOpacity(Opacity))
             using (ClipGeometry != null ? context.PushGeometryClip(ClipGeometry) : default)
             using (OpacityMask != null ? context.PushOpacityMask(OpacityMask, bounds) : default)
             {
@@ -178,22 +176,30 @@ namespace Avalonia.Media
 
             protected override void PushClipCore(Rect rect)
             {
-                throw new NotImplementedException();
+                var drawingGroup = PushNewDrawingGroup();
+
+                drawingGroup.ClipGeometry = new RectangleGeometry(rect);
             }
 
             protected override void PushGeometryClipCore(Geometry clip)
             {
-                throw new NotImplementedException();
+                var drawingGroup = PushNewDrawingGroup();
+
+                drawingGroup.ClipGeometry = clip;
             }
 
-            protected override void PushOpacityCore(double opacity, Rect bounds)
+            protected override void PushOpacityCore(double opacity)
             {
-                throw new NotImplementedException();
+                var drawingGroup = PushNewDrawingGroup();
+
+                drawingGroup.Opacity = opacity;
             }
 
             protected override void PushOpacityMaskCore(IBrush mask, Rect bounds)
             {
-                throw new NotImplementedException();
+                var drawingGroup = PushNewDrawingGroup();
+
+                drawingGroup.OpacityMask = mask;
             }
 
             internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)

+ 2 - 2
src/Avalonia.Base/Media/PlatformDrawingContext.cs

@@ -76,8 +76,8 @@ internal sealed class PlatformDrawingContext : DrawingContext
     protected override void PushGeometryClipCore(Geometry clip) =>
         _impl.PushGeometryClip(clip.PlatformImpl ?? throw new ArgumentException());
 
-    protected override void PushOpacityCore(double opacity, Rect bounds) => 
-        _impl.PushOpacity(opacity, bounds);
+    protected override void PushOpacityCore(double opacity) => 
+        _impl.PushOpacity(opacity, null);
 
     protected override void PushOpacityMaskCore(IBrush mask, Rect bounds) =>
         _impl.PushOpacityMask(mask, bounds);

+ 1 - 1
src/Avalonia.Base/Platform/IDrawingContextImpl.cs

@@ -132,7 +132,7 @@ namespace Avalonia.Platform
         /// </summary>
         /// <param name="opacity">The opacity.</param>
         /// <param name="bounds">where to apply the opacity.</param>
-        void PushOpacity(double opacity, Rect bounds);
+        void PushOpacity(double opacity, Rect? bounds);
 
         /// <summary>
         /// Pops the latest pushed opacity value.

+ 2 - 3
src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs

@@ -182,11 +182,10 @@ class RenderDataGeometryClipNode : RenderDataPushNode
 class RenderDataOpacityNode : RenderDataPushNode
 {
     public double Opacity { get; set; }
-    public Rect BoundsRect { get; set; }
     public override void Push(ref RenderDataNodeRenderContext context)
     {
         if (Opacity != 1)
-            context.Context.PushOpacity(Opacity, BoundsRect);
+            context.Context.PushOpacity(Opacity, null);
     }
 
     public override void Pop(ref RenderDataNodeRenderContext context)
@@ -211,4 +210,4 @@ abstract class RenderDataBrushAndPenNode : IRenderDataItemWithServerResources
     public abstract void Invoke(ref RenderDataNodeRenderContext context);
     public abstract Rect? Bounds { get; }
     public abstract bool HitTest(Point p);
-}
+}

+ 3 - 4
src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs

@@ -212,15 +212,14 @@ internal class RenderDataDrawingContext : DrawingContext
             });
     }
 
-    protected override void PushOpacityCore(double opacity, Rect bounds)
+    protected override void PushOpacityCore(double opacity)
     {
         if (opacity == 1)
             Push();
         else
             Push(new RenderDataOpacityNode
             {
-                Opacity = opacity,
-                BoundsRect = bounds
+                Opacity = opacity
             });
     }
 
@@ -346,4 +345,4 @@ internal class RenderDataDrawingContext : DrawingContext
         if (_resourcesHashSet != null) 
             s_hashSetPool.ReturnAndSetNull(ref _resourcesHashSet);
     }
-}
+}

+ 1 - 1
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@@ -109,7 +109,7 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
         _impl.PopClip();
     }
 
-    public void PushOpacity(double opacity, Rect bounds)
+    public void PushOpacity(double opacity, Rect? bounds)
     {
         _impl.PushOpacity(opacity, bounds);
     }

+ 1 - 1
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs

@@ -58,7 +58,7 @@ namespace Avalonia.Rendering.Composition.Server
                 canvas.PushEffect(Effect);
             
             if (Opacity != 1)
-                canvas.PushOpacity(Opacity, boundsRect);
+                canvas.PushOpacity(Opacity, ClipToBounds ? boundsRect : null);
             if (ClipToBounds && !HandlesClipToBounds)
                 canvas.PushClip(Root!.SnapToDevicePixels(boundsRect));
             if (Clip != null) 

+ 1 - 1
src/Avalonia.Base/Rendering/ImmediateRenderer.cs

@@ -96,7 +96,7 @@ namespace Avalonia.Rendering
                     }
 
                     using (context.PushTransform(m))
-                    using (context.PushOpacity(opacity, bounds))
+                    using (context.PushOpacity(opacity))
                     using (clipToBounds
 #pragma warning disable CS0618 // Type or member is obsolete
                         ? visual is IVisualWithRoundRectClip roundClipVisual

+ 1 - 1
src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@@ -457,7 +457,7 @@ namespace Avalonia.Headless
 
             }
 
-            public void PushOpacity(double opacity, Rect rect)
+            public void PushOpacity(double opacity, Rect? rect)
             {
 
             }

+ 10 - 4
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@@ -7,7 +7,6 @@ using Avalonia.Media;
 using Avalonia.Platform;
 using Avalonia.Rendering.Utilities;
 using Avalonia.Utilities;
-using Avalonia.Media.Imaging;
 using SkiaSharp;
 using ISceneBrush = Avalonia.Media.ISceneBrush;
 
@@ -573,14 +572,21 @@ namespace Avalonia.Skia
         }
 
         /// <inheritdoc />
-        public void PushOpacity(double opacity, Rect bounds)
+        public void PushOpacity(double opacity, Rect? bounds)
         {
             CheckLease();
 
             if(_useOpacitySaveLayer)
             {
-                var rect = bounds.ToSKRect();
-                Canvas.SaveLayer(rect, new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity)});
+                if (bounds.HasValue)
+                {
+                    var rect = bounds.Value.ToSKRect();
+                    Canvas.SaveLayer(rect, new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity) });
+                }
+                else
+                {
+                    Canvas.SaveLayer(new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity) });
+                }
             }
             else
             {

+ 12 - 3
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@@ -454,17 +454,26 @@ namespace Avalonia.Direct2D1.Media
         /// <param name="opacity">The opacity.</param>
         /// <param name="bounds">The bounds.</param>
         /// <returns>A disposable used to undo the opacity.</returns>
-        public void PushOpacity(double opacity, Rect bounds)
+        public void PushOpacity(double opacity, Rect? bounds)
         {
             if (opacity < 1)
             {
+                if(bounds == null || bounds == default(Rect))
+                {
+                    bounds = new Rect(0, 0, _renderTarget.PixelSize.Width, _renderTarget.PixelSize.Height);
+                }
+
                 var parameters = new LayerParameters
                 {
-                    ContentBounds = bounds.ToDirect2D(),
                     MaskTransform = PrimitiveExtensions.Matrix3x2Identity,
-                    Opacity = (float)opacity,
+                    Opacity = (float)opacity
                 };
 
+                if(bounds.HasValue)
+                {
+                    parameters.ContentBounds = bounds.Value.ToDirect2D();
+                }
+
                 var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext);
                 _deviceContext.PushLayer(ref parameters, layer);
 

+ 1 - 1
tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs

@@ -141,7 +141,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                         new Rect(control.Bounds.Size),
                         4);
 
-                    using (context.PushOpacity(0.5, control.Bounds))
+                    using (context.PushOpacity(0.5))
                     {
                         context.FillRectangle(
                             Brushes.Blue,