From 4b5c680a2644cc70ced48953cda0b94ed8bd29f6 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Fri, 18 Aug 2023 16:22:27 +0200 Subject: [PATCH] Introduce RenderOptions.RequiresFullOpacityHandling --- src/Avalonia.Base/Media/RenderOptions.cs | 45 ++++++++++++++++---- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 28 +++++++----- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/Avalonia.Base/Media/RenderOptions.cs b/src/Avalonia.Base/Media/RenderOptions.cs index 639498543b..1ac2520919 100644 --- a/src/Avalonia.Base/Media/RenderOptions.cs +++ b/src/Avalonia.Base/Media/RenderOptions.cs @@ -8,12 +8,13 @@ namespace Avalonia.Media public EdgeMode EdgeMode { get; init; } public TextRenderingMode TextRenderingMode { get; init; } public BitmapBlendingMode BitmapBlendingMode { get; init; } + public bool? RequiresFullOpacityHandling { get; init; } /// /// Gets the value of the BitmapInterpolationMode attached property for a visual. /// /// The control. - /// The control's left coordinate. + /// The value. public static BitmapInterpolationMode GetBitmapInterpolationMode(Visual visual) { return visual.RenderOptions.BitmapInterpolationMode; @@ -23,7 +24,7 @@ namespace Avalonia.Media /// Sets the value of the BitmapInterpolationMode attached property for a visual. /// /// The control. - /// The left value. + /// The value. public static void SetBitmapInterpolationMode(Visual visual, BitmapInterpolationMode value) { visual.RenderOptions = visual.RenderOptions with { BitmapInterpolationMode = value }; @@ -33,7 +34,7 @@ namespace Avalonia.Media /// Gets the value of the BitmapBlendingMode attached property for a visual. /// /// The control. - /// The control's left coordinate. + /// The value. public static BitmapBlendingMode GetBitmapBlendingMode(Visual visual) { return visual.RenderOptions.BitmapBlendingMode; @@ -53,7 +54,7 @@ namespace Avalonia.Media /// Gets the value of the EdgeMode attached property for a visual. /// /// The control. - /// The control's left coordinate. + /// The value. public static EdgeMode GetEdgeMode(Visual visual) { return visual.RenderOptions.EdgeMode; @@ -63,7 +64,7 @@ namespace Avalonia.Media /// Sets the value of the EdgeMode attached property for a visual. /// /// The control. - /// The left value. + /// The value. public static void SetEdgeMode(Visual visual, EdgeMode value) { visual.RenderOptions = visual.RenderOptions with { EdgeMode = value }; @@ -73,7 +74,7 @@ namespace Avalonia.Media /// Gets the value of the TextRenderingMode attached property for a visual. /// /// The control. - /// The control's left coordinate. + /// The value. public static TextRenderingMode GetTextRenderingMode(Visual visual) { return visual.RenderOptions.TextRenderingMode; @@ -83,12 +84,32 @@ namespace Avalonia.Media /// Sets the value of the TextRenderingMode attached property for a visual. /// /// The control. - /// The left value. + /// The value. public static void SetTextRenderingMode(Visual visual, TextRenderingMode value) { visual.RenderOptions = visual.RenderOptions with { TextRenderingMode = value }; } + /// + /// Gets the value of the RequiresFullOpacityHandling attached property for a visual. + /// + /// The control. + /// The value. + public static bool? GetRequiresFullOpacityHandling(Visual visual) + { + return visual.RenderOptions.RequiresFullOpacityHandling; + } + + /// + /// Sets the value of the RequiresFullOpacityHandling attached property for a visual. + /// + /// The control. + /// The value. + public static void SetRequiresFullOpacityHandling(Visual visual, bool? value) + { + visual.RenderOptions = visual.RenderOptions with { RequiresFullOpacityHandling = value }; + } + public RenderOptions MergeWith(RenderOptions other) { var bitmapInterpolationMode = BitmapInterpolationMode; @@ -119,12 +140,20 @@ namespace Avalonia.Media bitmapBlendingMode = other.BitmapBlendingMode; } + var requiresFullOpacityHandling = RequiresFullOpacityHandling; + + if (requiresFullOpacityHandling == null) + { + requiresFullOpacityHandling = other.RequiresFullOpacityHandling; + } + return new RenderOptions { BitmapInterpolationMode = bitmapInterpolationMode, EdgeMode = edgeMode, TextRenderingMode = textRenderingMode, - BitmapBlendingMode = bitmapBlendingMode + BitmapBlendingMode = bitmapBlendingMode, + RequiresFullOpacityHandling = requiresFullOpacityHandling }; } } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index fbff4ab4e7..7b5cca0fde 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -189,7 +189,8 @@ namespace Avalonia.Skia var d = destRect.ToSKRect(); var paint = SKPaintCache.Shared.Get(); - paint.Color = new SKColor(255, 255, 255, (byte)(255 * opacity * (_useOpacitySaveLayer ? 1 : _currentOpacity))); + + paint.Color = new SKColor(255, 255, 255, (byte)(255 * opacity * currentOpacity)); paint.FilterQuality = RenderOptions.BitmapInterpolationMode.ToSKFilterQuality(); paint.BlendMode = RenderOptions.BitmapBlendingMode.ToSKBlendMode(); @@ -375,7 +376,7 @@ namespace Avalonia.Skia { if (boxShadow != default && !boxShadow.IsInset) { - using (var shadow = BoxShadowFilter.Create(_boxShadowPaint, boxShadow, _useOpacitySaveLayer ? 1 : _currentOpacity)) + using (var shadow = BoxShadowFilter.Create(_boxShadowPaint, boxShadow, _currentOpacity)) { var spread = (float)boxShadow.Spread; if (boxShadow.IsInset) @@ -432,7 +433,7 @@ namespace Avalonia.Skia { if (boxShadow != default && boxShadow.IsInset) { - using (var shadow = BoxShadowFilter.Create(_boxShadowPaint, boxShadow, _useOpacitySaveLayer ? 1 : _currentOpacity)) + using (var shadow = BoxShadowFilter.Create(_boxShadowPaint, boxShadow, currentOpacity)) { var spread = (float)boxShadow.Spread; var offsetX = (float)boxShadow.OffsetX; @@ -592,8 +593,16 @@ namespace Avalonia.Skia { CheckLease(); - if(_useOpacitySaveLayer) + _opacityStack.Push(_currentOpacity); + + var useOpacitySaveLayer = _useOpacitySaveLayer || RenderOptions.RequiresFullOpacityHandling == true; + + if (useOpacitySaveLayer) { + opacity = _currentOpacity * opacity; //Take current multiplied opacity + + _currentOpacity = 1; //Opacity is applied via layering + if (bounds.HasValue) { var rect = bounds.Value.ToSKRect(); @@ -606,7 +615,6 @@ namespace Avalonia.Skia } else { - _opacityStack.Push(_currentOpacity); _currentOpacity *= opacity; } } @@ -616,14 +624,14 @@ namespace Avalonia.Skia { CheckLease(); - if(_useOpacitySaveLayer) + var useOpacitySaveLayer = _useOpacitySaveLayer || RenderOptions.RequiresFullOpacityHandling == true; + + if (useOpacitySaveLayer) { Canvas.Restore(); } - else - { - _currentOpacity = _opacityStack.Pop(); - } + + _currentOpacity = _opacityStack.Pop(); } ///