Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: Adjust RadialGradientBrush base type #12142

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@
using Windows.UI.Xaml.Media;
using Point = Windows.Foundation.Point;
using Size = Windows.Foundation.Size;
using Rect = Windows.Foundation.Rect;

namespace Microsoft.UI.Xaml.Media
{
partial class RadialGradientBrush
{
protected internal override Shader GetShader(Size size)
protected override Paint GetPaintInner(Rect destinationRect)
{
var paint = new Paint();
paint.SetShader(GetShader(destinationRect.Size));
MartinZikmund marked this conversation as resolved.
Show resolved Hide resolved
paint.SetStyle(Paint.Style.Stroke);
return paint;
}

internal Shader GetShader(Size size)
{
var center = Center;
var radiusX = RadiusX;
Expand Down
35 changes: 34 additions & 1 deletion src/Uno.UI/Microsoft/UI/Xaml/Media/RadialGradientBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,45 @@
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Uno;
using Windows.Foundation.Collections;

namespace Microsoft.UI.Xaml.Media
{
[ContentProperty(Name = nameof(GradientStops))]
public sealed partial class RadialGradientBrush : GradientBrush
public sealed partial class RadialGradientBrush : XamlCompositionBrushBase
{
public static DependencyProperty SpreadMethodProperty { get; } =
DependencyProperty.Register(
nameof(SpreadMethod),
typeof(GradientSpreadMethod),
typeof(RadialGradientBrush),
new FrameworkPropertyMetadata(
defaultValue: GradientSpreadMethod.Pad,
options: FrameworkPropertyMetadataOptions.AffectsRender));

public GradientSpreadMethod SpreadMethod
{
get => (GradientSpreadMethod)GetValue(SpreadMethodProperty);
set => SetValue(SpreadMethodProperty, value);
}

public static DependencyProperty MappingModeProperty { get; } =
DependencyProperty.Register(
"MappingMode",
typeof(BrushMappingMode),
typeof(RadialGradientBrush),
new FrameworkPropertyMetadata(
defaultValue: BrushMappingMode.RelativeToBoundingBox,
options: FrameworkPropertyMetadataOptions.AffectsRender));

public BrushMappingMode MappingMode
{
get => (BrushMappingMode)GetValue(MappingModeProperty);
set => SetValue(MappingModeProperty, value);
}

public IObservableVector<GradientStop> GradientStops { get; } = new ObservableVector<GradientStop>();

public static DependencyProperty CenterProperty { get; } = DependencyProperty.Register(
nameof(Center), typeof(Point), typeof(RadialGradientBrush), new FrameworkPropertyMetadata(new Point(0.5d, 0.5d)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.UI.Xaml.Media
{
partial class RadialGradientBrush
{
internal override CALayer GetLayer(CGSize size)
internal CALayer GetLayer(CGSize size)
{
var center = Center;
var radiusX = RadiusX;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.UI.Xaml.Media
{
partial class RadialGradientBrush
{
internal override string ToCssString(Size size)
internal string ToCssString(Size size)
{
var center = Center;
var radiusX = RadiusX;
Expand All @@ -31,7 +31,7 @@ internal override string ToCssString(Size size)
return $"radial-gradient(ellipse farthest-side at {radiusX * 100d}% {radiusY * 100d}%, {stops})";
}

internal override UIElement ToSvgElement()
internal UIElement ToSvgElement()
{
var center = Center;

Expand Down
13 changes: 13 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Border/Border.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#endif
using _Debug = System.Diagnostics.Debug;

using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;

namespace Windows.UI.Xaml.Controls
{
[ContentProperty(Name = nameof(Child))]
Expand Down Expand Up @@ -274,6 +276,17 @@ protected virtual void OnBorderBrushChanged(Brush oldValue, Brush newValue)
(s, _) => OnBorderBrushChangedPartial()
);
}
else if (newValue is RadialGradientBrush rgb)
{
_borderBrushColorChanged.Disposable = rgb.RegisterDisposablePropertyChangedCallback(
RadialGradientBrush.FallbackColorProperty,
(s, colorArg) => OnBorderBrushChangedPartial()
);
_borderBrushOpacityChanged.Disposable = rgb.RegisterDisposablePropertyChangedCallback(
RadialGradientBrush.OpacityProperty,
(s, _) => OnBorderBrushChangedPartial()
);
}
else if (newValue is AcrylicBrush ab)
{
_borderBrushColorChanged.Disposable = ab.RegisterDisposablePropertyChangedCallback(
Expand Down
81 changes: 54 additions & 27 deletions src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.iOSmacOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
using _Image = AppKit.NSImage;
#endif

using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;

namespace Windows.UI.Xaml.Shapes
{
partial class BorderLayerRenderer
Expand Down Expand Up @@ -170,7 +172,14 @@ private static IDisposable InnerCreateLayer(UIElement owner, CALayer parent, Lay

var insertionIndex = 0;

if (background is GradientBrush gradientBackground)
var caLayer = background switch
{
GradientBrush gradientBackground => gradientBackground.GetLayer(backgroundArea.Size),
RadialGradientBrush radialBackground => radialBackground.GetLayer(backgroundArea.Size),
_ => null,
};

if (caLayer is not null)
{
var fillMask = new CAShapeLayer()
{
Expand All @@ -180,7 +189,7 @@ private static IDisposable InnerCreateLayer(UIElement owner, CALayer parent, Lay
FillColor = _Color.White.CGColor,
};

CreateGradientBrushLayers(area, backgroundArea, parent, sublayers, ref insertionIndex, gradientBackground, fillMask);
CreateGradientBrushLayers(area, backgroundArea, parent, sublayers, ref insertionIndex, caLayer, fillMask);
}
else if (background is SolidColorBrush scbBackground)
{
Expand Down Expand Up @@ -237,20 +246,14 @@ private static IDisposable InnerCreateLayer(UIElement owner, CALayer parent, Lay
parent.AddSublayer(outerLayer);
parent.InsertSublayer(backgroundLayer, insertionIndex);

if (borderBrush is SolidColorBrush scbBorder || borderBrush == null)
var borderCALayer = borderBrush switch
{
Brush.AssignAndObserveBrush(borderBrush, color =>
{
outerLayer.StrokeColor = color;
outerLayer.FillColor = color;
GradientBrush gradientBorder => gradientBorder.GetLayer(area.Size),
RadialGradientBrush radialBorder => radialBorder.GetLayer(area.Size),
_ => null,
};

// Make sure to hold native object ref until it has been retained by native itself
// https://github.com/unoplatform/uno/issues/10283
GC.KeepAlive(color);
})
.DisposeWith(disposables);
}
else if (borderBrush is GradientBrush gradientBorder)
if (borderCALayer is not null)
{
var fillMask = new CAShapeLayer()
{
Expand All @@ -261,7 +264,20 @@ private static IDisposable InnerCreateLayer(UIElement owner, CALayer parent, Lay
};

var borderLayerIndex = parent.Sublayers.Length;
CreateGradientBrushLayers(area, area, parent, sublayers, ref borderLayerIndex, gradientBorder, fillMask);
CreateGradientBrushLayers(area, area, parent, sublayers, ref borderLayerIndex, borderCALayer, fillMask);
}
else if (borderBrush is SolidColorBrush scbBorder || borderBrush == null)
{
Brush.AssignAndObserveBrush(borderBrush, color =>
{
outerLayer.StrokeColor = color;
outerLayer.FillColor = color;

// Make sure to hold native object ref until it has been retained by native itself
// https://github.com/unoplatform/uno/issues/10283
GC.KeepAlive(color);
})
.DisposeWith(disposables);
}

parent.Mask = new CAShapeLayer()
Expand Down Expand Up @@ -293,9 +309,16 @@ private static IDisposable InnerCreateLayer(UIElement owner, CALayer parent, Lay

var insertionIndex = 0;

if (background is GradientBrush gradientBackground)
var caLayer = background switch
{
GradientBrush gradientBackground => gradientBackground.GetLayer(backgroundArea.Size),
RadialGradientBrush radialBackground => radialBackground.GetLayer(backgroundArea.Size),
_ => null,
};

if (caLayer is not null)
{
CreateGradientBrushLayers(area, backgroundArea, parent, sublayers, ref insertionIndex, gradientBackground, fillMask: null);
CreateGradientBrushLayers(area, backgroundArea, parent, sublayers, ref insertionIndex, caLayer, fillMask: null);
}
else if (background is SolidColorBrush scbBackground)
{
Expand Down Expand Up @@ -353,13 +376,14 @@ imageData.NativeImage is _Image uiImage &&
sublayers.Add(layer);
parent.AddSublayer(layer);

if (borderBrush is SolidColorBrush scbBorder)
var borderCALayer = borderBrush switch
{
Brush.AssignAndObserveBrush(borderBrush, c => layer.FillColor = c)
.DisposeWith(disposables);
GradientBrush gradientBorder => gradientBorder.GetLayer(area.Size),
RadialGradientBrush radialBorder => radialBorder.GetLayer(area.Size),
_ => null,
};

}
else if (borderBrush is GradientBrush gradientBorder)
if (borderCALayer is not null)
{
var fillMask = new CAShapeLayer()
{
Expand All @@ -370,9 +394,13 @@ imageData.NativeImage is _Image uiImage &&
};

var borderLayerIndex = parent.Sublayers.Length;
CreateGradientBrushLayers(area, area, parent, sublayers, ref borderLayerIndex, gradientBorder, fillMask);
CreateGradientBrushLayers(area, area, parent, sublayers, ref borderLayerIndex, borderCALayer, fillMask);
}
else if (borderBrush is SolidColorBrush scbBorder)
{
Brush.AssignAndObserveBrush(borderBrush, c => layer.FillColor = c)
.DisposeWith(disposables);
}

}

backgroundLayer.Path = backgroundPath;
Expand Down Expand Up @@ -591,9 +619,9 @@ private static void CreateImageBrushLayers(CGRect fullArea, CGRect insideArea, C
/// <param name="layer">The layer in which the gradient layers will be added</param>
/// <param name="sublayers">List of layers to keep all references</param>
/// <param name="insertionIndex">Where in the layer the new layers will be added</param>
/// <param name="gradientBrush">The xxGradientBrush</param>
/// <param name="gradientLayer">The CALayer retrieved by brush.GetLayer(insideArea.Size)</param>
/// <param name="fillMask">Optional mask layer (for when we use rounded corners)</param>
private static void CreateGradientBrushLayers(CGRect fullArea, CGRect insideArea, CALayer layer, List<CALayer> sublayers, ref int insertionIndex, GradientBrush gradientBrush, CAShapeLayer fillMask)
private static void CreateGradientBrushLayers(CGRect fullArea, CGRect insideArea, CALayer layer, List<CALayer> sublayers, ref int insertionIndex, CALayer gradientLayer, CAShapeLayer fillMask)
{
// This layer is the one we apply the mask on. It's the full size of the shape because the mask is as well.
var gradientContainerLayer = new CALayer
Expand All @@ -607,7 +635,6 @@ private static void CreateGradientBrushLayers(CGRect fullArea, CGRect insideArea
var gradientFrame = new CGRect(new CGPoint(insideArea.X, insideArea.Y), insideArea.Size);

// This is the layer with the actual gradient in it. Its frame is the inside of the border.
var gradientLayer = gradientBrush.GetLayer(insideArea.Size);
gradientLayer.Frame = gradientFrame;
gradientLayer.MasksToBounds = true;

Expand Down
15 changes: 15 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Uno.UI.Xaml;
using Uno.UI.Xaml.Media;

using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;

namespace Windows.UI.Xaml.Shapes
{
partial class BorderLayerRenderer
Expand Down Expand Up @@ -94,6 +96,15 @@ public static void SetBorder(UIElement element, Thickness thickness, Brush brush
("border-width", borderWidth),
("border-image-slice", "1"));
break;
case RadialGradientBrush radialGradientBrush:
var radialBorder = radialGradientBrush.ToCssString(element.RenderSize); // TODO: Reevaluate when size is changing
element.SetStyle(
("border-style", "solid"),
("border-color", ""),
("border-image", radialBorder),
("border-width", borderWidth),
("border-image-slice", "1"));
break;
case AcrylicBrush acrylicBrush:
var acrylicFallbackColor = acrylicBrush.FallbackColorWithOpacity;
element.SetStyle(
Expand Down Expand Up @@ -163,6 +174,10 @@ public static void SetBackgroundBrush(FrameworkElement element, Brush brush)
WindowManagerInterop.SetElementBackgroundGradient(element.HtmlId, gradientBrush.ToCssString(element.RenderSize));
RecalculateBrushOnSizeChanged(element, true);
break;
case RadialGradientBrush radialGradientBrush:
WindowManagerInterop.SetElementBackgroundGradient(element.HtmlId, radialGradientBrush.ToCssString(element.RenderSize));
RecalculateBrushOnSizeChanged(element, true);
break;
case XamlCompositionBrushBase unsupportedCompositionBrush:
var fallbackColor = unsupportedCompositionBrush.FallbackColorWithOpacity;
WindowManagerInterop.SetElementBackgroundColor(element.HtmlId, fallbackColor);
Expand Down
15 changes: 12 additions & 3 deletions src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
using Windows.UI.Xaml.Input;
using Uno.Collections;

using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;

namespace Windows.UI.Xaml.Controls
{
public partial class TextBlock : FrameworkElement
Expand Down Expand Up @@ -234,9 +236,12 @@ private void UpdatePaint()
.Value;

// The size is incorrect at this point, we update it later in `UpdateLayout`.
var shader = Foreground is GradientBrush gb
? gb.GetShader(LayoutSlot.Size.LogicalToPhysicalPixels())
: null;
var shader = Foreground switch
{
GradientBrush gb => gb.GetShader(LayoutSlot.Size.LogicalToPhysicalPixels()),
RadialGradientBrush rgb => rgb.GetShader(LayoutSlot.Size.LogicalToPhysicalPixels()),
_ => null,
};

_paint = TextPaintPool.GetPaint(
FontWeight,
Expand Down Expand Up @@ -441,6 +446,10 @@ private Size UpdateLayout(ref LayoutBuilder layout, Size availableSize, bool exa
{
layout.Layout.Paint.SetShader(gb.GetShader(_measureLayout.MeasuredSize.LogicalToPhysicalPixels()));
}
else if (Foreground is RadialGradientBrush rgb)
{
layout.Layout.Paint.SetShader(rgb.GetShader(_measureLayout.MeasuredSize.LogicalToPhysicalPixels()));
}

if (_textFormatted is UnoSpannableString textFormatted)
{
Expand Down
3 changes: 2 additions & 1 deletion src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using Uno;
using Uno.Foundation.Logging;

using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;

#if XAMARIN_IOS
using UIKit;
Expand Down Expand Up @@ -384,7 +385,7 @@ Brush Foreground
set
{
#if !__WASM__
if (value is SolidColorBrush || value is GradientBrush || value is null)
if (value is SolidColorBrush || value is GradientBrush || value is RadialGradientBrush || value is null)
{
SetValue(ForegroundProperty, value);
}
Expand Down
12 changes: 7 additions & 5 deletions src/Uno.UI/UI/Xaml/Documents/InlineExtensions.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using Uno.UI.Extensions;
using Windows.Foundation;

using RadialGradientBrush = Microsoft.UI.Xaml.Media.RadialGradientBrush;

namespace Windows.UI.Xaml.Documents
{
internal static partial class InlineExtensions
Expand All @@ -22,12 +24,12 @@ internal static TextPaint GetPaint(this Inline inline, Size size)
.GetColorWithOpacity(inline.Foreground, Colors.Transparent)
.Value;

Shader shader = null;

if (inline.Foreground is GradientBrush gb)
Shader shader = inline.Foreground switch
{
shader = gb.GetShader(size.LogicalToPhysicalPixels());
}
GradientBrush gb => gb.GetShader(size.LogicalToPhysicalPixels()),
RadialGradientBrush rgb => rgb.GetShader(size.LogicalToPhysicalPixels()),
_ => null,
};

return Uno.UI.Controls.TextPaintPool.GetPaint(
inline.FontWeight,
Expand Down
Loading