From 2180e23e36554743c041163db27566fa9a2f706c Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Tue, 15 Mar 2022 12:59:16 +0100 Subject: [PATCH] feat: ElevatedView on Skia --- .../Composition/Compositor.skia.cs | 9 ++++- .../Composition/ShadowState.skia.cs | 39 +++++++++++++++++++ .../Composition/Visual.skia.cs | 6 +-- src/Uno.UI.Toolkit/ElevatedView.cs | 2 + src/Uno.UI.Toolkit/UIElementExtensions.cs | 20 +++++++++- src/Uno.UWP/UI/Color.skia.cs | 11 ++++++ 6 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 src/Uno.UI.Composition/Composition/ShadowState.skia.cs create mode 100644 src/Uno.UWP/UI/Color.skia.cs diff --git a/src/Uno.UI.Composition/Composition/Compositor.skia.cs b/src/Uno.UI.Composition/Composition/Compositor.skia.cs index 3c1c9a941868..44ac3f0ea2a8 100644 --- a/src/Uno.UI.Composition/Composition/Compositor.skia.cs +++ b/src/Uno.UI.Composition/Composition/Compositor.skia.cs @@ -59,7 +59,14 @@ private void RenderVisual(SKSurface surface, SKImageInfo info, Visual visual) { if (visual.Opacity != 0 && visual.IsVisible) { - surface.Canvas.Save(); + if (visual.ShadowState is { } shadow) + { + surface.Canvas.SaveLayer(shadow.Paint); + } + else + { + surface.Canvas.Save(); + } var visualMatrix = surface.Canvas.TotalMatrix; diff --git a/src/Uno.UI.Composition/Composition/ShadowState.skia.cs b/src/Uno.UI.Composition/Composition/ShadowState.skia.cs new file mode 100644 index 000000000000..4f732cb0fdcf --- /dev/null +++ b/src/Uno.UI.Composition/Composition/ShadowState.skia.cs @@ -0,0 +1,39 @@ +#nullable enable + +using SkiaSharp; +using Windows.UI; + +namespace Uno.UI.Composition.Composition; + +/// +/// Captures the state of drop shadow for a visual. +/// +internal class ShadowState +{ + private SKPaint? _paint; + + public ShadowState(float dx, float dy, float sigmaX, float sigmaY, Color color) + { + Dx = dx; + Dy = dy; + SigmaX = sigmaX; + SigmaY = sigmaY; + Color = color; + } + + public float Dx { get; } + + public float Dy { get; } + + public float SigmaX { get; } + + public float SigmaY { get; } + + public Color Color { get; } + + public SKPaint Paint => + _paint ??= new SKPaint() + { + ImageFilter = SKImageFilter.CreateDropShadow(Dx, Dy, SigmaX, SigmaY, Color) + }; +} diff --git a/src/Uno.UI.Composition/Composition/Visual.skia.cs b/src/Uno.UI.Composition/Composition/Visual.skia.cs index 6ffb8f7070d3..c09b8f92ef36 100644 --- a/src/Uno.UI.Composition/Composition/Visual.skia.cs +++ b/src/Uno.UI.Composition/Composition/Visual.skia.cs @@ -1,9 +1,8 @@ #nullable enable -#if !__IOS__ using System.Numerics; -using System; using SkiaSharp; +using Uno.UI.Composition.Composition; namespace Windows.UI.Composition { @@ -49,6 +48,7 @@ internal int ZIndex } } } + + internal ShadowState? ShadowState { get; set; } } } -#endif diff --git a/src/Uno.UI.Toolkit/ElevatedView.cs b/src/Uno.UI.Toolkit/ElevatedView.cs index 7ea92c0d39c2..ff90a83f2f0e 100644 --- a/src/Uno.UI.Toolkit/ElevatedView.cs +++ b/src/Uno.UI.Toolkit/ElevatedView.cs @@ -197,6 +197,8 @@ private void UpdateElevation() // The elevation must be applied on the border, since // it will get the right shape (with rounded corners) _border.SetElevationInternal(Elevation, ShadowColor); +#elif __SKIA__ + this.SetElevationInternal(Elevation, ShadowColor); #elif NETFX_CORE || NETCOREAPP _border.SetElevationInternal(Elevation, ShadowColor, _shadowHost as DependencyObject, CornerRadius); #endif diff --git a/src/Uno.UI.Toolkit/UIElementExtensions.cs b/src/Uno.UI.Toolkit/UIElementExtensions.cs index 4d95725b4f95..d4805d27cc44 100644 --- a/src/Uno.UI.Toolkit/UIElementExtensions.cs +++ b/src/Uno.UI.Toolkit/UIElementExtensions.cs @@ -9,6 +9,7 @@ using Windows.UI.Xaml.Hosting; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Shapes; +using Uno.UI.Composition.Composition; #if HAS_UNO using Uno.Extensions; @@ -142,6 +143,23 @@ internal static void SetElevationInternal(this DependencyObject element, double uiElement.UnsetCssClasses("noclip"); } } +#elif __SKIA__ + if (element is UIElement uiElement) + { + var visual = uiElement.Visual; + + const float SHADOW_SIGMA_X_MODIFIER = 1f / 3.5f; + const float SHADOW_SIGMA_Y_MODIFIER = 1f / 3.5f; + float x = 0.3f; + float y = 0.92f * 0.5f; + + var dx = (float)elevation * x; + var dy = (float)elevation * y; + var sigmaX = (float)elevation * SHADOW_SIGMA_X_MODIFIER; + var sigmaY = (float)elevation * SHADOW_SIGMA_Y_MODIFIER; + var shadow = new ShadowState(dx, dy, sigmaX, sigmaY, shadowColor); + visual.ShadowState = shadow; + } #elif NETFX_CORE || NETCOREAPP if (element is UIElement uiElement) { @@ -213,7 +231,7 @@ internal static void SetElevationInternal(this DependencyObject element, double ElementCompositionPreview.SetElementChildVisual(uiHost, spriteVisual); } #endif - } + } #endregion diff --git a/src/Uno.UWP/UI/Color.skia.cs b/src/Uno.UWP/UI/Color.skia.cs new file mode 100644 index 000000000000..9eef0aed4975 --- /dev/null +++ b/src/Uno.UWP/UI/Color.skia.cs @@ -0,0 +1,11 @@ +using System; +using SkiaSharp; + +namespace Windows.UI; + +public partial struct Color : IFormattable +{ + public static implicit operator SKColor(Color color) => new SKColor(color.R, color.G, color.B, color.A); + + public static implicit operator Color(SKColor color) => FromArgb(color.Alpha, color.Red, color.Green, color.Blue); +}