diff --git a/samples/ControlCatalog/Pages/CompositionPage.axaml b/samples/ControlCatalog/Pages/CompositionPage.axaml
index 403f45b8eb..602b9b768d 100644
--- a/samples/ControlCatalog/Pages/CompositionPage.axaml
+++ b/samples/ControlCatalog/Pages/CompositionPage.axaml
@@ -2,44 +2,57 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pages="using:ControlCatalog.Pages"
x:Class="ControlCatalog.Pages.CompositionPage">
-
- Implicit animations
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Resize me
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Resize me
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
index c70675b606..8b12a2d663 100644
--- a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
+++ b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
@@ -1,28 +1,39 @@
using System;
using System.Collections.Generic;
+using System.Numerics;
+using System.Threading;
using Avalonia;
+using Avalonia.Animation;
using Avalonia.Controls;
+using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
+using Avalonia.Media.Immutable;
using Avalonia.Rendering.Composition;
using Avalonia.Rendering.Composition.Animations;
using Avalonia.VisualTree;
+using Math = System.Math;
namespace ControlCatalog.Pages;
public partial class CompositionPage : UserControl
{
private ImplicitAnimationCollection? _implicitAnimations;
+ private CompositionCustomVisual? _customVisual;
+ private CompositionSolidColorVisual? _solidVisual;
public CompositionPage()
{
AvaloniaXamlLoader.Load(this);
+ AttachAnimatedSolidVisual(this.FindControl("SolidVisualHost")!);
+ AttachCustomVisual(this.FindControl("CustomVisualHost")!);
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
this.Get("Items").Items = CreateColorItems();
+
}
private static List CreateColorItems()
@@ -126,6 +137,167 @@ public partial class CompositionPage : UserControl
compositionVisual.ImplicitAnimations = page._implicitAnimations;
}
}
+
+ void AttachAnimatedSolidVisual(Visual v)
+ {
+ void Update()
+ {
+ if(_solidVisual == null)
+ return;
+ _solidVisual.Size = new Vector2((float)v.Bounds.Width / 3, (float)v.Bounds.Height / 3);
+ _solidVisual.Offset = new Vector3((float)v.Bounds.Width / 3, (float)v.Bounds.Height / 3, 0);
+ }
+ v.AttachedToVisualTree += delegate
+ {
+ var compositor = ElementComposition.GetElementVisual(v)?.Compositor;
+ if(compositor == null || _solidVisual?.Compositor == compositor)
+ return;
+ _solidVisual = compositor.CreateSolidColorVisual();
+ ElementComposition.SetElementChildVisual(v, _solidVisual);
+ _solidVisual.Color = Colors.Red;
+ var animation = _solidVisual.Compositor.CreateColorKeyFrameAnimation();
+ animation.InsertKeyFrame(0, Colors.Red);
+ animation.InsertKeyFrame(0.5f, Colors.Blue);
+ animation.InsertKeyFrame(1, Colors.Green);
+ animation.Duration = TimeSpan.FromSeconds(5);
+ animation.IterationBehavior = AnimationIterationBehavior.Forever;
+ animation.Direction = PlaybackDirection.Alternate;
+ _solidVisual.StartAnimation("Color", animation);
+
+ _solidVisual.AnchorPoint = new Vector2(0, 0);
+
+ var scale = _solidVisual.Compositor.CreateVector3KeyFrameAnimation();
+ scale.Duration = TimeSpan.FromSeconds(5);
+ scale.IterationBehavior = AnimationIterationBehavior.Forever;
+ scale.InsertKeyFrame(0, new Vector3(1, 1, 0));
+ scale.InsertKeyFrame(0.5f, new Vector3(1.5f, 1.5f, 0));
+ scale.InsertKeyFrame(1, new Vector3(1, 1, 0));
+
+ _solidVisual.StartAnimation("Scale", scale);
+
+ var center =
+ _solidVisual.Compositor.CreateExpressionAnimation(
+ "Vector3(this.Target.Size.X * 0.5, this.Target.Size.Y * 0.5, 1)");
+ _solidVisual.StartAnimation("CenterPoint", center);
+ Update();
+ };
+ v.PropertyChanged += (_, a) =>
+ {
+ if (a.Property == BoundsProperty)
+ Update();
+ };
+ }
+
+ void AttachCustomVisual(Visual v)
+ {
+ void Update()
+ {
+ if (_customVisual == null)
+ return;
+ var h = (float)Math.Min(v.Bounds.Height, v.Bounds.Width / 3);
+ _customVisual.Size = new Vector2((float)v.Bounds.Width, h);
+ _customVisual.Offset = new Vector3(0, (float)(v.Bounds.Height - h) / 2, 0);
+ }
+ v.AttachedToVisualTree += delegate
+ {
+ var compositor = ElementComposition.GetElementVisual(v)?.Compositor;
+ if(compositor == null || _customVisual?.Compositor == compositor)
+ return;
+ _customVisual = compositor.CreateCustomVisual(new CustomVisualHandler());
+ ElementComposition.SetElementChildVisual(v, _customVisual);
+ _customVisual.SendHandlerMessage(CustomVisualHandler.StartMessage);
+ Update();
+ };
+
+ v.PropertyChanged += (_, a) =>
+ {
+ if (a.Property == BoundsProperty)
+ Update();
+ };
+ }
+
+ class CustomVisualHandler : CompositionCustomVisualHandler
+ {
+ private TimeSpan _animationElapsed;
+ private TimeSpan? _lastServerTime;
+ private bool _running;
+
+ public static readonly object StopMessage = new(), StartMessage = new();
+
+ public override void OnRender(ImmediateDrawingContext drawingContext)
+ {
+ if (_running)
+ {
+ if (_lastServerTime.HasValue) _animationElapsed += (CompositionNow - _lastServerTime.Value);
+ _lastServerTime = CompositionNow;
+ }
+
+ const int cnt = 20;
+ var maxPointSizeX = EffectiveSize.X / (cnt * 1.6);
+ var maxPointSizeY = EffectiveSize.Y / 4;
+ var pointSize = Math.Min(maxPointSizeX, maxPointSizeY);
+ var animationLength = TimeSpan.FromSeconds(4);
+ var animationStage = _animationElapsed.TotalSeconds / animationLength.TotalSeconds;
+
+ var sinOffset = Math.Cos(_animationElapsed.TotalSeconds) * 1.5;
+
+ for (var c = 0; c < cnt; c++)
+ {
+ var stage = (animationStage + (double)c / cnt) % 1;
+ var colorStage =
+ (animationStage + (Math.Sin(_animationElapsed.TotalSeconds * 2) + 1) / 2 + (double)c / cnt) % 1;
+ var posX = (EffectiveSize.X + pointSize * 3) * stage - pointSize;
+ var posY = (EffectiveSize.Y - pointSize) * (1 + Math.Sin(stage * 3.14 * 3 + sinOffset)) / 2 + pointSize / 2;
+ var opacity = Math.Sin(stage * 3.14);
+
+
+ drawingContext.DrawEllipse(new ImmutableSolidColorBrush(Color.FromArgb(
+ 255,
+ (byte)(255 - 255 * colorStage),
+ (byte)(255 * Math.Abs(0.5 - colorStage) * 2),
+ (byte)(255 * colorStage)
+ ), opacity), null,
+ new Point(posX, posY), pointSize / 2, pointSize / 2);
+ }
+
+ }
+
+ public override void OnMessage(object message)
+ {
+ if (message == StartMessage)
+ {
+ _running = true;
+ _lastServerTime = null;
+ RegisterForNextAnimationFrameUpdate();
+ }
+ else if (message == StopMessage)
+ _running = false;
+ }
+
+ public override void OnAnimationFrameUpdate()
+ {
+ if (_running)
+ {
+ Invalidate();
+ RegisterForNextAnimationFrameUpdate();
+ }
+ }
+ }
+
+ private void ButtonThreadSleep(object? sender, RoutedEventArgs e)
+ {
+ Thread.Sleep(10000);
+ }
+
+ private void ButtonStartCustomVisual(object? sender, RoutedEventArgs e)
+ {
+ _customVisual?.SendHandlerMessage(CustomVisualHandler.StartMessage);
+ }
+
+ private void ButtonStopCustomVisual(object? sender, RoutedEventArgs e)
+ {
+ _customVisual?.SendHandlerMessage(CustomVisualHandler.StopMessage);
+ }
}
public class CompositionPageColorItem
diff --git a/src/Avalonia.Base/Media/Brush.cs b/src/Avalonia.Base/Media/Brush.cs
index 8d531e9394..4138f1c891 100644
--- a/src/Avalonia.Base/Media/Brush.cs
+++ b/src/Avalonia.Base/Media/Brush.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Media
/// Describes how an area is painted.
///
[TypeConverter(typeof(BrushConverter))]
- public abstract class Brush : Animatable, IMutableBrush
+ public abstract class Brush : Animatable
{
///
/// Defines the property.
@@ -92,9 +92,6 @@ namespace Avalonia.Media
throw new FormatException($"Invalid brush string: '{s}'.");
}
- ///
- public abstract IBrush ToImmutable();
-
///
/// Marks a property as affecting the brush's visual representation.
///
diff --git a/src/Avalonia.Base/Media/BrushExtensions.cs b/src/Avalonia.Base/Media/BrushExtensions.cs
index 2fc8778a5e..d0208c187a 100644
--- a/src/Avalonia.Base/Media/BrushExtensions.cs
+++ b/src/Avalonia.Base/Media/BrushExtensions.cs
@@ -16,11 +16,11 @@ namespace Avalonia.Media
/// The result of calling if the brush is mutable,
/// otherwise .
///
- public static IBrush ToImmutable(this IBrush brush)
+ public static IImmutableBrush ToImmutable(this IBrush brush)
{
_ = brush ?? throw new ArgumentNullException(nameof(brush));
- return (brush as IMutableBrush)?.ToImmutable() ?? brush;
+ return (brush as IMutableBrush)?.ToImmutable() ?? (IImmutableBrush)brush;
}
///
diff --git a/src/Avalonia.Base/Media/Brushes.cs b/src/Avalonia.Base/Media/Brushes.cs
index 5957775f39..7ecba6df3e 100644
--- a/src/Avalonia.Base/Media/Brushes.cs
+++ b/src/Avalonia.Base/Media/Brushes.cs
@@ -8,706 +8,706 @@ namespace Avalonia.Media
///
/// Gets an colored brush.
///
- public static ISolidColorBrush AliceBlue => KnownColor.AliceBlue.ToBrush();
+ public static IImmutableSolidColorBrush AliceBlue => KnownColor.AliceBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush AntiqueWhite => KnownColor.AntiqueWhite.ToBrush();
+ public static IImmutableSolidColorBrush AntiqueWhite => KnownColor.AntiqueWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Aqua => KnownColor.Aqua.ToBrush();
+ public static IImmutableSolidColorBrush Aqua => KnownColor.Aqua.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Aquamarine => KnownColor.Aquamarine.ToBrush();
+ public static IImmutableSolidColorBrush Aquamarine => KnownColor.Aquamarine.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Azure => KnownColor.Azure.ToBrush();
+ public static IImmutableSolidColorBrush Azure => KnownColor.Azure.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Beige => KnownColor.Beige.ToBrush();
+ public static IImmutableSolidColorBrush Beige => KnownColor.Beige.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Bisque => KnownColor.Bisque.ToBrush();
+ public static IImmutableSolidColorBrush Bisque => KnownColor.Bisque.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Black => KnownColor.Black.ToBrush();
+ public static IImmutableSolidColorBrush Black => KnownColor.Black.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush BlanchedAlmond => KnownColor.BlanchedAlmond.ToBrush();
+ public static IImmutableSolidColorBrush BlanchedAlmond => KnownColor.BlanchedAlmond.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Blue => KnownColor.Blue.ToBrush();
+ public static IImmutableSolidColorBrush Blue => KnownColor.Blue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush BlueViolet => KnownColor.BlueViolet.ToBrush();
+ public static IImmutableSolidColorBrush BlueViolet => KnownColor.BlueViolet.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Brown => KnownColor.Brown.ToBrush();
+ public static IImmutableSolidColorBrush Brown => KnownColor.Brown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush BurlyWood => KnownColor.BurlyWood.ToBrush();
+ public static IImmutableSolidColorBrush BurlyWood => KnownColor.BurlyWood.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush CadetBlue => KnownColor.CadetBlue.ToBrush();
+ public static IImmutableSolidColorBrush CadetBlue => KnownColor.CadetBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Chartreuse => KnownColor.Chartreuse.ToBrush();
+ public static IImmutableSolidColorBrush Chartreuse => KnownColor.Chartreuse.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Chocolate => KnownColor.Chocolate.ToBrush();
+ public static IImmutableSolidColorBrush Chocolate => KnownColor.Chocolate.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Coral => KnownColor.Coral.ToBrush();
+ public static IImmutableSolidColorBrush Coral => KnownColor.Coral.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush CornflowerBlue => KnownColor.CornflowerBlue.ToBrush();
+ public static IImmutableSolidColorBrush CornflowerBlue => KnownColor.CornflowerBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Cornsilk => KnownColor.Cornsilk.ToBrush();
+ public static IImmutableSolidColorBrush Cornsilk => KnownColor.Cornsilk.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Crimson => KnownColor.Crimson.ToBrush();
+ public static IImmutableSolidColorBrush Crimson => KnownColor.Crimson.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Cyan => KnownColor.Cyan.ToBrush();
+ public static IImmutableSolidColorBrush Cyan => KnownColor.Cyan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkBlue => KnownColor.DarkBlue.ToBrush();
+ public static IImmutableSolidColorBrush DarkBlue => KnownColor.DarkBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkCyan => KnownColor.DarkCyan.ToBrush();
+ public static IImmutableSolidColorBrush DarkCyan => KnownColor.DarkCyan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkGoldenrod => KnownColor.DarkGoldenrod.ToBrush();
+ public static IImmutableSolidColorBrush DarkGoldenrod => KnownColor.DarkGoldenrod.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkGray => KnownColor.DarkGray.ToBrush();
+ public static IImmutableSolidColorBrush DarkGray => KnownColor.DarkGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkGreen => KnownColor.DarkGreen.ToBrush();
+ public static IImmutableSolidColorBrush DarkGreen => KnownColor.DarkGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkKhaki => KnownColor.DarkKhaki.ToBrush();
+ public static IImmutableSolidColorBrush DarkKhaki => KnownColor.DarkKhaki.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkMagenta => KnownColor.DarkMagenta.ToBrush();
+ public static IImmutableSolidColorBrush DarkMagenta => KnownColor.DarkMagenta.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkOliveGreen => KnownColor.DarkOliveGreen.ToBrush();
+ public static IImmutableSolidColorBrush DarkOliveGreen => KnownColor.DarkOliveGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkOrange => KnownColor.DarkOrange.ToBrush();
+ public static IImmutableSolidColorBrush DarkOrange => KnownColor.DarkOrange.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkOrchid => KnownColor.DarkOrchid.ToBrush();
+ public static IImmutableSolidColorBrush DarkOrchid => KnownColor.DarkOrchid.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkRed => KnownColor.DarkRed.ToBrush();
+ public static IImmutableSolidColorBrush DarkRed => KnownColor.DarkRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSalmon => KnownColor.DarkSalmon.ToBrush();
+ public static IImmutableSolidColorBrush DarkSalmon => KnownColor.DarkSalmon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSeaGreen => KnownColor.DarkSeaGreen.ToBrush();
+ public static IImmutableSolidColorBrush DarkSeaGreen => KnownColor.DarkSeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSlateBlue => KnownColor.DarkSlateBlue.ToBrush();
+ public static IImmutableSolidColorBrush DarkSlateBlue => KnownColor.DarkSlateBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkSlateGray => KnownColor.DarkSlateGray.ToBrush();
+ public static IImmutableSolidColorBrush DarkSlateGray => KnownColor.DarkSlateGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkTurquoise => KnownColor.DarkTurquoise.ToBrush();
+ public static IImmutableSolidColorBrush DarkTurquoise => KnownColor.DarkTurquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DarkViolet => KnownColor.DarkViolet.ToBrush();
+ public static IImmutableSolidColorBrush DarkViolet => KnownColor.DarkViolet.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DeepPink => KnownColor.DeepPink.ToBrush();
+ public static IImmutableSolidColorBrush DeepPink => KnownColor.DeepPink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DeepSkyBlue => KnownColor.DeepSkyBlue.ToBrush();
+ public static IImmutableSolidColorBrush DeepSkyBlue => KnownColor.DeepSkyBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DimGray => KnownColor.DimGray.ToBrush();
+ public static IImmutableSolidColorBrush DimGray => KnownColor.DimGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush DodgerBlue => KnownColor.DodgerBlue.ToBrush();
+ public static IImmutableSolidColorBrush DodgerBlue => KnownColor.DodgerBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Firebrick => KnownColor.Firebrick.ToBrush();
+ public static IImmutableSolidColorBrush Firebrick => KnownColor.Firebrick.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush FloralWhite => KnownColor.FloralWhite.ToBrush();
+ public static IImmutableSolidColorBrush FloralWhite => KnownColor.FloralWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush ForestGreen => KnownColor.ForestGreen.ToBrush();
+ public static IImmutableSolidColorBrush ForestGreen => KnownColor.ForestGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Fuchsia => KnownColor.Fuchsia.ToBrush();
+ public static IImmutableSolidColorBrush Fuchsia => KnownColor.Fuchsia.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Gainsboro => KnownColor.Gainsboro.ToBrush();
+ public static IImmutableSolidColorBrush Gainsboro => KnownColor.Gainsboro.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush GhostWhite => KnownColor.GhostWhite.ToBrush();
+ public static IImmutableSolidColorBrush GhostWhite => KnownColor.GhostWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Gold => KnownColor.Gold.ToBrush();
+ public static IImmutableSolidColorBrush Gold => KnownColor.Gold.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Goldenrod => KnownColor.Goldenrod.ToBrush();
+ public static IImmutableSolidColorBrush Goldenrod => KnownColor.Goldenrod.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Gray => KnownColor.Gray.ToBrush();
+ public static IImmutableSolidColorBrush Gray => KnownColor.Gray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Green => KnownColor.Green.ToBrush();
+ public static IImmutableSolidColorBrush Green => KnownColor.Green.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush GreenYellow => KnownColor.GreenYellow.ToBrush();
+ public static IImmutableSolidColorBrush GreenYellow => KnownColor.GreenYellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Honeydew => KnownColor.Honeydew.ToBrush();
+ public static IImmutableSolidColorBrush Honeydew => KnownColor.Honeydew.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush HotPink => KnownColor.HotPink.ToBrush();
+ public static IImmutableSolidColorBrush HotPink => KnownColor.HotPink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush IndianRed => KnownColor.IndianRed.ToBrush();
+ public static IImmutableSolidColorBrush IndianRed => KnownColor.IndianRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Indigo => KnownColor.Indigo.ToBrush();
+ public static IImmutableSolidColorBrush Indigo => KnownColor.Indigo.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Ivory => KnownColor.Ivory.ToBrush();
+ public static IImmutableSolidColorBrush Ivory => KnownColor.Ivory.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Khaki => KnownColor.Khaki.ToBrush();
+ public static IImmutableSolidColorBrush Khaki => KnownColor.Khaki.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Lavender => KnownColor.Lavender.ToBrush();
+ public static IImmutableSolidColorBrush Lavender => KnownColor.Lavender.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LavenderBlush => KnownColor.LavenderBlush.ToBrush();
+ public static IImmutableSolidColorBrush LavenderBlush => KnownColor.LavenderBlush.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LawnGreen => KnownColor.LawnGreen.ToBrush();
+ public static IImmutableSolidColorBrush LawnGreen => KnownColor.LawnGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LemonChiffon => KnownColor.LemonChiffon.ToBrush();
+ public static IImmutableSolidColorBrush LemonChiffon => KnownColor.LemonChiffon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightBlue => KnownColor.LightBlue.ToBrush();
+ public static IImmutableSolidColorBrush LightBlue => KnownColor.LightBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightCoral => KnownColor.LightCoral.ToBrush();
+ public static IImmutableSolidColorBrush LightCoral => KnownColor.LightCoral.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightCyan => KnownColor.LightCyan.ToBrush();
+ public static IImmutableSolidColorBrush LightCyan => KnownColor.LightCyan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightGoldenrodYellow => KnownColor.LightGoldenrodYellow.ToBrush();
+ public static IImmutableSolidColorBrush LightGoldenrodYellow => KnownColor.LightGoldenrodYellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightGray => KnownColor.LightGray.ToBrush();
+ public static IImmutableSolidColorBrush LightGray => KnownColor.LightGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightGreen => KnownColor.LightGreen.ToBrush();
+ public static IImmutableSolidColorBrush LightGreen => KnownColor.LightGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightPink => KnownColor.LightPink.ToBrush();
+ public static IImmutableSolidColorBrush LightPink => KnownColor.LightPink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSalmon => KnownColor.LightSalmon.ToBrush();
+ public static IImmutableSolidColorBrush LightSalmon => KnownColor.LightSalmon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSeaGreen => KnownColor.LightSeaGreen.ToBrush();
+ public static IImmutableSolidColorBrush LightSeaGreen => KnownColor.LightSeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSkyBlue => KnownColor.LightSkyBlue.ToBrush();
+ public static IImmutableSolidColorBrush LightSkyBlue => KnownColor.LightSkyBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSlateGray => KnownColor.LightSlateGray.ToBrush();
+ public static IImmutableSolidColorBrush LightSlateGray => KnownColor.LightSlateGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightSteelBlue => KnownColor.LightSteelBlue.ToBrush();
+ public static IImmutableSolidColorBrush LightSteelBlue => KnownColor.LightSteelBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LightYellow => KnownColor.LightYellow.ToBrush();
+ public static IImmutableSolidColorBrush LightYellow => KnownColor.LightYellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Lime => KnownColor.Lime.ToBrush();
+ public static IImmutableSolidColorBrush Lime => KnownColor.Lime.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush LimeGreen => KnownColor.LimeGreen.ToBrush();
+ public static IImmutableSolidColorBrush LimeGreen => KnownColor.LimeGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Linen => KnownColor.Linen.ToBrush();
+ public static IImmutableSolidColorBrush Linen => KnownColor.Linen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Magenta => KnownColor.Magenta.ToBrush();
+ public static IImmutableSolidColorBrush Magenta => KnownColor.Magenta.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Maroon => KnownColor.Maroon.ToBrush();
+ public static IImmutableSolidColorBrush Maroon => KnownColor.Maroon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumAquamarine => KnownColor.MediumAquamarine.ToBrush();
+ public static IImmutableSolidColorBrush MediumAquamarine => KnownColor.MediumAquamarine.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumBlue => KnownColor.MediumBlue.ToBrush();
+ public static IImmutableSolidColorBrush MediumBlue => KnownColor.MediumBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumOrchid => KnownColor.MediumOrchid.ToBrush();
+ public static IImmutableSolidColorBrush MediumOrchid => KnownColor.MediumOrchid.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumPurple => KnownColor.MediumPurple.ToBrush();
+ public static IImmutableSolidColorBrush MediumPurple => KnownColor.MediumPurple.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumSeaGreen => KnownColor.MediumSeaGreen.ToBrush();
+ public static IImmutableSolidColorBrush MediumSeaGreen => KnownColor.MediumSeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumSlateBlue => KnownColor.MediumSlateBlue.ToBrush();
+ public static IImmutableSolidColorBrush MediumSlateBlue => KnownColor.MediumSlateBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumSpringGreen => KnownColor.MediumSpringGreen.ToBrush();
+ public static IImmutableSolidColorBrush MediumSpringGreen => KnownColor.MediumSpringGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumTurquoise => KnownColor.MediumTurquoise.ToBrush();
+ public static IImmutableSolidColorBrush MediumTurquoise => KnownColor.MediumTurquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MediumVioletRed => KnownColor.MediumVioletRed.ToBrush();
+ public static IImmutableSolidColorBrush MediumVioletRed => KnownColor.MediumVioletRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MidnightBlue => KnownColor.MidnightBlue.ToBrush();
+ public static IImmutableSolidColorBrush MidnightBlue => KnownColor.MidnightBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MintCream => KnownColor.MintCream.ToBrush();
+ public static IImmutableSolidColorBrush MintCream => KnownColor.MintCream.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush MistyRose => KnownColor.MistyRose.ToBrush();
+ public static IImmutableSolidColorBrush MistyRose => KnownColor.MistyRose.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Moccasin => KnownColor.Moccasin.ToBrush();
+ public static IImmutableSolidColorBrush Moccasin => KnownColor.Moccasin.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush NavajoWhite => KnownColor.NavajoWhite.ToBrush();
+ public static IImmutableSolidColorBrush NavajoWhite => KnownColor.NavajoWhite.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Navy => KnownColor.Navy.ToBrush();
+ public static IImmutableSolidColorBrush Navy => KnownColor.Navy.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush OldLace => KnownColor.OldLace.ToBrush();
+ public static IImmutableSolidColorBrush OldLace => KnownColor.OldLace.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Olive => KnownColor.Olive.ToBrush();
+ public static IImmutableSolidColorBrush Olive => KnownColor.Olive.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush OliveDrab => KnownColor.OliveDrab.ToBrush();
+ public static IImmutableSolidColorBrush OliveDrab => KnownColor.OliveDrab.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Orange => KnownColor.Orange.ToBrush();
+ public static IImmutableSolidColorBrush Orange => KnownColor.Orange.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush OrangeRed => KnownColor.OrangeRed.ToBrush();
+ public static IImmutableSolidColorBrush OrangeRed => KnownColor.OrangeRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Orchid => KnownColor.Orchid.ToBrush();
+ public static IImmutableSolidColorBrush Orchid => KnownColor.Orchid.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleGoldenrod => KnownColor.PaleGoldenrod.ToBrush();
+ public static IImmutableSolidColorBrush PaleGoldenrod => KnownColor.PaleGoldenrod.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleGreen => KnownColor.PaleGreen.ToBrush();
+ public static IImmutableSolidColorBrush PaleGreen => KnownColor.PaleGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleTurquoise => KnownColor.PaleTurquoise.ToBrush();
+ public static IImmutableSolidColorBrush PaleTurquoise => KnownColor.PaleTurquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PaleVioletRed => KnownColor.PaleVioletRed.ToBrush();
+ public static IImmutableSolidColorBrush PaleVioletRed => KnownColor.PaleVioletRed.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PapayaWhip => KnownColor.PapayaWhip.ToBrush();
+ public static IImmutableSolidColorBrush PapayaWhip => KnownColor.PapayaWhip.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PeachPuff => KnownColor.PeachPuff.ToBrush();
+ public static IImmutableSolidColorBrush PeachPuff => KnownColor.PeachPuff.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Peru => KnownColor.Peru.ToBrush();
+ public static IImmutableSolidColorBrush Peru => KnownColor.Peru.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Pink => KnownColor.Pink.ToBrush();
+ public static IImmutableSolidColorBrush Pink => KnownColor.Pink.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Plum => KnownColor.Plum.ToBrush();
+ public static IImmutableSolidColorBrush Plum => KnownColor.Plum.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush PowderBlue => KnownColor.PowderBlue.ToBrush();
+ public static IImmutableSolidColorBrush PowderBlue => KnownColor.PowderBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Purple => KnownColor.Purple.ToBrush();
+ public static IImmutableSolidColorBrush Purple => KnownColor.Purple.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Red => KnownColor.Red.ToBrush();
+ public static IImmutableSolidColorBrush Red => KnownColor.Red.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush RosyBrown => KnownColor.RosyBrown.ToBrush();
+ public static IImmutableSolidColorBrush RosyBrown => KnownColor.RosyBrown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush RoyalBlue => KnownColor.RoyalBlue.ToBrush();
+ public static IImmutableSolidColorBrush RoyalBlue => KnownColor.RoyalBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SaddleBrown => KnownColor.SaddleBrown.ToBrush();
+ public static IImmutableSolidColorBrush SaddleBrown => KnownColor.SaddleBrown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Salmon => KnownColor.Salmon.ToBrush();
+ public static IImmutableSolidColorBrush Salmon => KnownColor.Salmon.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SandyBrown => KnownColor.SandyBrown.ToBrush();
+ public static IImmutableSolidColorBrush SandyBrown => KnownColor.SandyBrown.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SeaGreen => KnownColor.SeaGreen.ToBrush();
+ public static IImmutableSolidColorBrush SeaGreen => KnownColor.SeaGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SeaShell => KnownColor.SeaShell.ToBrush();
+ public static IImmutableSolidColorBrush SeaShell => KnownColor.SeaShell.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Sienna => KnownColor.Sienna.ToBrush();
+ public static IImmutableSolidColorBrush Sienna => KnownColor.Sienna.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Silver => KnownColor.Silver.ToBrush();
+ public static IImmutableSolidColorBrush Silver => KnownColor.Silver.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SkyBlue => KnownColor.SkyBlue.ToBrush();
+ public static IImmutableSolidColorBrush SkyBlue => KnownColor.SkyBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SlateBlue => KnownColor.SlateBlue.ToBrush();
+ public static IImmutableSolidColorBrush SlateBlue => KnownColor.SlateBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SlateGray => KnownColor.SlateGray.ToBrush();
+ public static IImmutableSolidColorBrush SlateGray => KnownColor.SlateGray.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Snow => KnownColor.Snow.ToBrush();
+ public static IImmutableSolidColorBrush Snow => KnownColor.Snow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SpringGreen => KnownColor.SpringGreen.ToBrush();
+ public static IImmutableSolidColorBrush SpringGreen => KnownColor.SpringGreen.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush SteelBlue => KnownColor.SteelBlue.ToBrush();
+ public static IImmutableSolidColorBrush SteelBlue => KnownColor.SteelBlue.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Tan => KnownColor.Tan.ToBrush();
+ public static IImmutableSolidColorBrush Tan => KnownColor.Tan.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Teal => KnownColor.Teal.ToBrush();
+ public static IImmutableSolidColorBrush Teal => KnownColor.Teal.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Thistle => KnownColor.Thistle.ToBrush();
+ public static IImmutableSolidColorBrush Thistle => KnownColor.Thistle.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Tomato => KnownColor.Tomato.ToBrush();
+ public static IImmutableSolidColorBrush Tomato => KnownColor.Tomato.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Transparent => KnownColor.Transparent.ToBrush();
+ public static IImmutableSolidColorBrush Transparent => KnownColor.Transparent.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Turquoise => KnownColor.Turquoise.ToBrush();
+ public static IImmutableSolidColorBrush Turquoise => KnownColor.Turquoise.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Violet => KnownColor.Violet.ToBrush();
+ public static IImmutableSolidColorBrush Violet => KnownColor.Violet.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Wheat => KnownColor.Wheat.ToBrush();
+ public static IImmutableSolidColorBrush Wheat => KnownColor.Wheat.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush White => KnownColor.White.ToBrush();
+ public static IImmutableSolidColorBrush White => KnownColor.White.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush WhiteSmoke => KnownColor.WhiteSmoke.ToBrush();
+ public static IImmutableSolidColorBrush WhiteSmoke => KnownColor.WhiteSmoke.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush Yellow => KnownColor.Yellow.ToBrush();
+ public static IImmutableSolidColorBrush Yellow => KnownColor.Yellow.ToBrush();
///
/// Gets an colored brush.
///
- public static ISolidColorBrush YellowGreen => KnownColor.YellowGreen.ToBrush();
+ public static IImmutableSolidColorBrush YellowGreen => KnownColor.YellowGreen.ToBrush();
}
}
diff --git a/src/Avalonia.Base/Media/ConicGradientBrush.cs b/src/Avalonia.Base/Media/ConicGradientBrush.cs
index 4b50019ddc..bce7a5af19 100644
--- a/src/Avalonia.Base/Media/ConicGradientBrush.cs
+++ b/src/Avalonia.Base/Media/ConicGradientBrush.cs
@@ -47,7 +47,7 @@ namespace Avalonia.Media
}
///
- public override IBrush ToImmutable()
+ public override IImmutableBrush ToImmutable()
{
return new ImmutableConicGradientBrush(this);
}
diff --git a/src/Avalonia.Base/Media/GradientBrush.cs b/src/Avalonia.Base/Media/GradientBrush.cs
index c84413ecbb..83cdaa1694 100644
--- a/src/Avalonia.Base/Media/GradientBrush.cs
+++ b/src/Avalonia.Base/Media/GradientBrush.cs
@@ -12,7 +12,7 @@ namespace Avalonia.Media
///
/// Base class for brushes that draw with a gradient.
///
- public abstract class GradientBrush : Brush, IGradientBrush
+ public abstract class GradientBrush : Brush, IGradientBrush, IMutableBrush
{
///
/// Defines the property.
@@ -92,5 +92,7 @@ namespace Avalonia.Media
{
RaiseInvalidated(EventArgs.Empty);
}
+
+ public abstract IImmutableBrush ToImmutable();
}
}
diff --git a/src/Avalonia.Base/Media/IImmutableBrush.cs b/src/Avalonia.Base/Media/IImmutableBrush.cs
new file mode 100644
index 0000000000..5781b0117a
--- /dev/null
+++ b/src/Avalonia.Base/Media/IImmutableBrush.cs
@@ -0,0 +1,9 @@
+namespace Avalonia.Media;
+
+///
+/// Represents an immutable brush which can be safely used with various threading contexts
+///
+public interface IImmutableBrush : IBrush
+{
+
+}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Media/IMutableBrush.cs b/src/Avalonia.Base/Media/IMutableBrush.cs
index fef124ba36..f128aba4df 100644
--- a/src/Avalonia.Base/Media/IMutableBrush.cs
+++ b/src/Avalonia.Base/Media/IMutableBrush.cs
@@ -7,12 +7,12 @@ namespace Avalonia.Media
/// Represents a mutable brush which can return an immutable clone of itself.
///
[NotClientImplementable]
- public interface IMutableBrush : IBrush, IAffectsRender
+ internal interface IMutableBrush : IBrush, IAffectsRender
{
///
/// Creates an immutable clone of the brush.
///
/// The immutable clone.
- IBrush ToImmutable();
+ internal IImmutableBrush ToImmutable();
}
}
diff --git a/src/Avalonia.Base/Media/ISolidColorBrush.cs b/src/Avalonia.Base/Media/ISolidColorBrush.cs
index 29e11210f1..f58768ef09 100644
--- a/src/Avalonia.Base/Media/ISolidColorBrush.cs
+++ b/src/Avalonia.Base/Media/ISolidColorBrush.cs
@@ -13,4 +13,13 @@ namespace Avalonia.Media
///
Color Color { get; }
}
+
+ ///
+ /// Fills an area with a solid color.
+ ///
+ [NotClientImplementable]
+ public interface IImmutableSolidColorBrush : ISolidColorBrush, IImmutableBrush
+ {
+
+ }
}
diff --git a/src/Avalonia.Base/Media/ImageBrush.cs b/src/Avalonia.Base/Media/ImageBrush.cs
index 19dcf00901..2f2a0fb627 100644
--- a/src/Avalonia.Base/Media/ImageBrush.cs
+++ b/src/Avalonia.Base/Media/ImageBrush.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Media
///
/// Paints an area with an .
///
- public class ImageBrush : TileBrush, IImageBrush
+ public class ImageBrush : TileBrush, IImageBrush, IMutableBrush
{
///
/// Defines the property.
@@ -45,7 +45,7 @@ namespace Avalonia.Media
}
///
- public override IBrush ToImmutable()
+ public IImmutableBrush ToImmutable()
{
return new ImmutableImageBrush(this);
}
diff --git a/src/Avalonia.Base/Media/ImmediateDrawingContext.cs b/src/Avalonia.Base/Media/ImmediateDrawingContext.cs
new file mode 100644
index 0000000000..1e1a73437d
--- /dev/null
+++ b/src/Avalonia.Base/Media/ImmediateDrawingContext.cs
@@ -0,0 +1,373 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Platform;
+using Avalonia.Rendering.SceneGraph;
+using Avalonia.Threading;
+using Avalonia.Utilities;
+using Avalonia.Media.Imaging;
+using Avalonia.Media.Immutable;
+
+namespace Avalonia.Media
+{
+ public sealed class ImmediateDrawingContext : IDisposable, IOptionalFeatureProvider
+ {
+ private readonly bool _ownsImpl;
+ private int _currentLevel;
+
+ private static ThreadSafeObjectPool> StateStackPool { get; } =
+ ThreadSafeObjectPool>.Default;
+
+ private static ThreadSafeObjectPool> TransformStackPool { get; } =
+ ThreadSafeObjectPool>.Default;
+
+ private Stack? _states = StateStackPool.Get();
+
+ private Stack? _transformContainers = TransformStackPool.Get();
+
+ readonly struct TransformContainer
+ {
+ public readonly Matrix LocalTransform;
+ public readonly Matrix ContainerTransform;
+
+ public TransformContainer(Matrix localTransform, Matrix containerTransform)
+ {
+ LocalTransform = localTransform;
+ ContainerTransform = containerTransform;
+ }
+ }
+
+ internal ImmediateDrawingContext(IDrawingContextImpl impl, bool ownsImpl)
+ {
+ _ownsImpl = ownsImpl;
+ PlatformImpl = impl;
+ _currentContainerTransform = impl.Transform;
+ }
+
+ public IDrawingContextImpl PlatformImpl { get; }
+
+ private Matrix _currentTransform = Matrix.Identity;
+
+ private Matrix _currentContainerTransform;
+
+ ///
+ /// Gets the current transform of the drawing context.
+ ///
+ public Matrix CurrentTransform
+ {
+ get { return _currentTransform; }
+ private set
+ {
+ _currentTransform = value;
+ var transform = _currentTransform * _currentContainerTransform;
+ PlatformImpl.Transform = transform;
+ }
+ }
+
+ ///
+ /// Draws an bitmap.
+ ///
+ /// The bitmap.
+ /// The rect in the output to draw to.
+ public void DrawBitmap(IBitmap source, Rect rect)
+ {
+ _ = source ?? throw new ArgumentNullException(nameof(source));
+ DrawBitmap(source, new Rect(source.Size), rect);
+ }
+
+ ///
+ /// Draws an image.
+ ///
+ /// The bitmap.
+ /// The rect in the image to draw.
+ /// The rect in the output to draw to.
+ /// The bitmap interpolation mode.
+ public void DrawBitmap(IBitmap source, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default)
+ {
+ _ = source ?? throw new ArgumentNullException(nameof(source));
+ PlatformImpl.DrawBitmap(source.PlatformImpl, 1, sourceRect, destRect, bitmapInterpolationMode);
+ }
+
+ ///
+ /// Draws a line.
+ ///
+ /// The stroke pen.
+ /// The first point of the line.
+ /// The second point of the line.
+ public void DrawLine(ImmutablePen pen, Point p1, Point p2)
+ {
+ if (PenIsVisible(pen))
+ {
+ PlatformImpl.DrawLine(pen, p1, p2);
+ }
+ }
+
+ ///
+ /// Draws a rectangle with the specified Brush and Pen.
+ ///
+ /// The brush used to fill the rectangle, or null for no fill.
+ /// The pen used to stroke the rectangle, or null for no stroke.
+ /// The rectangle bounds.
+ /// The radius in the X dimension of the rounded corners.
+ /// This value will be clamped to the range of 0 to Width/2
+ ///
+ /// The radius in the Y dimension of the rounded corners.
+ /// This value will be clamped to the range of 0 to Height/2
+ ///
+ /// Box shadow effect parameters
+ ///
+ /// The brush and the pen can both be null. If the brush is null, then no fill is performed.
+ /// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible.
+ ///
+ public void DrawRectangle(IImmutableBrush? brush, ImmutablePen? pen, Rect rect, double radiusX = 0, double radiusY = 0,
+ BoxShadows boxShadows = default)
+ {
+ if (brush == null && !PenIsVisible(pen))
+ {
+ return;
+ }
+
+ if (!MathUtilities.IsZero(radiusX))
+ {
+ radiusX = Math.Min(radiusX, rect.Width / 2);
+ }
+
+ if (!MathUtilities.IsZero(radiusY))
+ {
+ radiusY = Math.Min(radiusY, rect.Height / 2);
+ }
+
+ PlatformImpl.DrawRectangle(brush, pen, new RoundedRect(rect, radiusX, radiusY), boxShadows);
+ }
+
+ ///
+ /// Draws the outline of a rectangle.
+ ///
+ /// The pen.
+ /// The rectangle bounds.
+ /// The corner radius.
+ public void DrawRectangle(ImmutablePen pen, Rect rect, float cornerRadius = 0.0f)
+ {
+ DrawRectangle(null, pen, rect, cornerRadius, cornerRadius);
+ }
+
+ ///
+ /// Draws an ellipse with the specified Brush and Pen.
+ ///
+ /// The brush used to fill the ellipse, or null for no fill.
+ /// The pen used to stroke the ellipse, or null for no stroke.
+ /// The location of the center of the ellipse.
+ /// The horizontal radius of the ellipse.
+ /// The vertical radius of the ellipse.
+ ///
+ /// The brush and the pen can both be null. If the brush is null, then no fill is performed.
+ /// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible.
+ ///
+ public void DrawEllipse(IImmutableBrush? brush, ImmutablePen? pen, Point center, double radiusX, double radiusY)
+ {
+ if (brush == null && !PenIsVisible(pen))
+ {
+ return;
+ }
+
+ var originX = center.X - radiusX;
+ var originY = center.Y - radiusY;
+ var width = radiusX * 2;
+ var height = radiusY * 2;
+
+ PlatformImpl.DrawEllipse(brush, pen, new Rect(originX, originY, width, height));
+ }
+
+ ///
+ /// Draws a glyph run.
+ ///
+ /// The foreground brush.
+ /// The glyph run.
+ public void DrawGlyphRun(IImmutableBrush foreground, GlyphRun glyphRun)
+ {
+ _ = glyphRun ?? throw new ArgumentNullException(nameof(glyphRun));
+
+ PlatformImpl.DrawGlyphRun(foreground, glyphRun);
+ }
+
+ ///
+ /// Draws a filled rectangle.
+ ///
+ /// The brush.
+ /// The rectangle bounds.
+ /// The corner radius.
+ public void FillRectangle(IImmutableBrush brush, Rect rect, float cornerRadius = 0.0f)
+ {
+ DrawRectangle(brush, null, rect, cornerRadius, cornerRadius);
+ }
+
+ public readonly record struct PushedState : IDisposable
+ {
+ private readonly int _level;
+ private readonly ImmediateDrawingContext _context;
+ private readonly Matrix _matrix;
+ private readonly PushedStateType _type;
+
+ public enum PushedStateType
+ {
+ None,
+ Matrix,
+ Opacity,
+ Clip,
+ MatrixContainer,
+ GeometryClip,
+ OpacityMask,
+ }
+
+ internal PushedState(ImmediateDrawingContext context, PushedStateType type, Matrix matrix = default(Matrix))
+ {
+ if (context._states is null)
+ throw new ObjectDisposedException(nameof(ImmediateDrawingContext));
+
+ _context = context;
+ _type = type;
+ _matrix = matrix;
+ _level = context._currentLevel += 1;
+ context._states.Push(this);
+ }
+
+ public void Dispose()
+ {
+ if (_type == PushedStateType.None)
+ return;
+ if (_context._states is null || _context._transformContainers is null)
+ throw new ObjectDisposedException(nameof(DrawingContext));
+ if (_context._currentLevel != _level)
+ throw new InvalidOperationException("Wrong Push/Pop state order");
+ _context._currentLevel--;
+ _context._states.Pop();
+ if (_type == PushedStateType.Matrix)
+ _context.CurrentTransform = _matrix;
+ else if (_type == PushedStateType.Clip)
+ _context.PlatformImpl.PopClip();
+ else if (_type == PushedStateType.Opacity)
+ _context.PlatformImpl.PopOpacity();
+ else if (_type == PushedStateType.GeometryClip)
+ _context.PlatformImpl.PopGeometryClip();
+ else if (_type == PushedStateType.OpacityMask)
+ _context.PlatformImpl.PopOpacityMask();
+ else if (_type == PushedStateType.MatrixContainer)
+ {
+ var cont = _context._transformContainers.Pop();
+ _context._currentContainerTransform = cont.ContainerTransform;
+ _context.CurrentTransform = cont.LocalTransform;
+ }
+ }
+ }
+
+
+ public PushedState PushClip(RoundedRect clip)
+ {
+ PlatformImpl.PushClip(clip);
+ return new PushedState(this, PushedState.PushedStateType.Clip);
+ }
+
+ ///
+ /// Pushes a clip rectangle.
+ ///
+ /// The clip rectangle.
+ /// A disposable used to undo the clip rectangle.
+ public PushedState PushClip(Rect clip)
+ {
+ PlatformImpl.PushClip(clip);
+ return new PushedState(this, PushedState.PushedStateType.Clip);
+ }
+
+ ///
+ /// Pushes an opacity value.
+ ///
+ /// The opacity.
+ /// A disposable used to undo the opacity.
+ public PushedState PushOpacity(double opacity)
+ //TODO: Eliminate platform-specific push opacity call
+ {
+ PlatformImpl.PushOpacity(opacity);
+ return new PushedState(this, PushedState.PushedStateType.Opacity);
+ }
+
+ ///
+ /// Pushes an opacity mask.
+ ///
+ /// The opacity mask.
+ ///
+ /// The size of the brush's target area. TODO: Are we sure this is needed?
+ ///
+ /// A disposable to undo the opacity mask.
+ public PushedState PushOpacityMask(IImmutableBrush mask, Rect bounds)
+ {
+ PlatformImpl.PushOpacityMask(mask, bounds);
+ return new PushedState(this, PushedState.PushedStateType.OpacityMask);
+ }
+
+ ///
+ /// Pushes a matrix post-transformation.
+ ///
+ /// The matrix
+ /// A disposable used to undo the transformation.
+ public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform * matrix);
+
+ ///
+ /// Pushes a matrix pre-transformation.
+ ///
+ /// The matrix
+ /// A disposable used to undo the transformation.
+ public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix * CurrentTransform);
+
+ ///
+ /// Sets the current matrix transformation.
+ ///
+ /// The matrix
+ /// A disposable used to undo the transformation.
+ public PushedState PushSetTransform(Matrix matrix)
+ {
+ var oldMatrix = CurrentTransform;
+ CurrentTransform = matrix;
+
+ return new PushedState(this, PushedState.PushedStateType.Matrix, oldMatrix);
+ }
+
+ ///
+ /// Pushes a new transform context.
+ ///
+ /// A disposable used to undo the transformation.
+ public PushedState PushTransformContainer()
+ {
+ if (_transformContainers is null)
+ throw new ObjectDisposedException(nameof(DrawingContext));
+ _transformContainers.Push(new TransformContainer(CurrentTransform, _currentContainerTransform));
+ _currentContainerTransform = CurrentTransform * _currentContainerTransform;
+ _currentTransform = Matrix.Identity;
+ return new PushedState(this, PushedState.PushedStateType.MatrixContainer);
+ }
+
+ ///
+ /// Disposes of any resources held by the .
+ ///
+ public void Dispose()
+ {
+ if (_states is null || _transformContainers is null)
+ throw new ObjectDisposedException(nameof(DrawingContext));
+ while (_states.Count != 0)
+ _states.Peek().Dispose();
+ StateStackPool.Return(_states);
+ _states = null;
+ if (_transformContainers.Count != 0)
+ throw new InvalidOperationException("Transform container stack is non-empty");
+ TransformStackPool.Return(_transformContainers);
+ _transformContainers = null;
+ if (_ownsImpl)
+ PlatformImpl.Dispose();
+ }
+
+ private static bool PenIsVisible(IPen? pen)
+ {
+ return pen?.Brush != null && pen.Thickness > 0;
+ }
+
+ public object? TryGetFeature(Type type) => PlatformImpl.GetFeature(type);
+ }
+}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
index 1e95acbf22..c86d86d20a 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
@@ -5,7 +5,7 @@ namespace Avalonia.Media.Immutable
///
/// A brush that draws with a gradient.
///
- public abstract class ImmutableGradientBrush : IGradientBrush
+ public abstract class ImmutableGradientBrush : IGradientBrush, IImmutableBrush
{
///
/// Initializes a new instance of the class.
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutablePen.cs b/src/Avalonia.Base/Media/Immutable/ImmutablePen.cs
index 8a53eaf7b8..ef4468fccf 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutablePen.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutablePen.cs
@@ -38,15 +38,13 @@ namespace Avalonia.Media.Immutable
/// The line join.
/// The miter limit.
public ImmutablePen(
- IBrush? brush,
+ IImmutableBrush? brush,
double thickness = 1.0,
ImmutableDashStyle? dashStyle = null,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0)
{
- Debug.Assert(!(brush is IMutableBrush));
-
Brush = brush;
Thickness = thickness;
LineCap = lineCap;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
index 6755dfd236..4e623f02c5 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
@@ -5,7 +5,7 @@ namespace Avalonia.Media.Immutable
///
/// Fills an area with a solid color.
///
- public class ImmutableSolidColorBrush : ISolidColorBrush, IEquatable
+ public class ImmutableSolidColorBrush : IImmutableSolidColorBrush, IEquatable
{
///
/// Initializes a new instance of the class.
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
index 6df27872fc..1ee52365e0 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
@@ -5,7 +5,7 @@ namespace Avalonia.Media.Immutable
///
/// A brush which displays a repeating image.
///
- public abstract class ImmutableTileBrush : ITileBrush
+ public abstract class ImmutableTileBrush : ITileBrush, IImmutableBrush
{
///
/// Initializes a new instance of the class.
diff --git a/src/Avalonia.Base/Media/KnownColors.cs b/src/Avalonia.Base/Media/KnownColors.cs
index ae2fca5a60..64cf1ef2f1 100644
--- a/src/Avalonia.Base/Media/KnownColors.cs
+++ b/src/Avalonia.Base/Media/KnownColors.cs
@@ -10,7 +10,7 @@ namespace Avalonia.Media
private static readonly IReadOnlyDictionary _knownColorNames;
private static readonly IReadOnlyDictionary _knownColors;
#if !BUILDTASK
- private static readonly Dictionary _knownBrushes;
+ private static readonly Dictionary _knownBrushes;
#endif
[GenerateEnumValueDictionary()]
@@ -39,7 +39,7 @@ namespace Avalonia.Media
_knownColors = knownColors;
#if !BUILDTASK
- _knownBrushes = new Dictionary();
+ _knownBrushes = new ();
#endif
}
@@ -72,7 +72,7 @@ namespace Avalonia.Media
}
#if !BUILDTASK
- public static ISolidColorBrush ToBrush(this KnownColor color)
+ public static IImmutableSolidColorBrush ToBrush(this KnownColor color)
{
lock (_knownBrushes)
{
diff --git a/src/Avalonia.Base/Media/LinearGradientBrush.cs b/src/Avalonia.Base/Media/LinearGradientBrush.cs
index a51adf0949..9b9ce5e4b7 100644
--- a/src/Avalonia.Base/Media/LinearGradientBrush.cs
+++ b/src/Avalonia.Base/Media/LinearGradientBrush.cs
@@ -47,7 +47,7 @@ namespace Avalonia.Media
}
///
- public override IBrush ToImmutable()
+ public override IImmutableBrush ToImmutable()
{
return new ImmutableLinearGradientBrush(this);
}
diff --git a/src/Avalonia.Base/Media/RadialGradientBrush.cs b/src/Avalonia.Base/Media/RadialGradientBrush.cs
index 16c367c0d0..f803051676 100644
--- a/src/Avalonia.Base/Media/RadialGradientBrush.cs
+++ b/src/Avalonia.Base/Media/RadialGradientBrush.cs
@@ -67,7 +67,7 @@ namespace Avalonia.Media
}
///
- public override IBrush ToImmutable()
+ public override IImmutableBrush ToImmutable()
{
return new ImmutableRadialGradientBrush(this);
}
diff --git a/src/Avalonia.Base/Media/SolidColorBrush.cs b/src/Avalonia.Base/Media/SolidColorBrush.cs
index 962819a1a1..d8e25fe748 100644
--- a/src/Avalonia.Base/Media/SolidColorBrush.cs
+++ b/src/Avalonia.Base/Media/SolidColorBrush.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Media
///
/// Fills an area with a solid color.
///
- public class SolidColorBrush : Brush, ISolidColorBrush
+ public class SolidColorBrush : Brush, ISolidColorBrush, IMutableBrush
{
///
/// Defines the property.
@@ -80,7 +80,7 @@ namespace Avalonia.Media
}
///
- public override IBrush ToImmutable()
+ public IImmutableBrush ToImmutable()
{
return new ImmutableSolidColorBrush(this);
}
diff --git a/src/Avalonia.Base/Media/VisualBrush.cs b/src/Avalonia.Base/Media/VisualBrush.cs
index 8dce79cf11..1261d233ac 100644
--- a/src/Avalonia.Base/Media/VisualBrush.cs
+++ b/src/Avalonia.Base/Media/VisualBrush.cs
@@ -6,7 +6,7 @@ namespace Avalonia.Media
///
/// Paints an area with an .
///
- public class VisualBrush : TileBrush, IVisualBrush
+ public class VisualBrush : TileBrush, IVisualBrush, IMutableBrush
{
///
/// Defines the property.
@@ -45,7 +45,7 @@ namespace Avalonia.Media
}
///
- public override IBrush ToImmutable()
+ IImmutableBrush IMutableBrush.ToImmutable()
{
return new ImmutableVisualBrush(this);
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs b/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
index 889c1d34c8..80b6bb9d2a 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
@@ -80,4 +80,6 @@ internal abstract class AnimationInstanceBase : IAnimationInstance
_invalidated = true;
TargetObject.NotifyAnimatedValueChanged(Property);
}
+
+ public void OnTick() => Invalidate();
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs
index 8ec4ec19bc..b14d2c0b19 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/IAnimationInstance.cs
@@ -6,7 +6,7 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations
{
- internal interface IAnimationInstance
+ internal interface IAnimationInstance : IServerClockItem
{
ServerObject TargetObject { get; }
ExpressionVariant Evaluate(TimeSpan now, ExpressionVariant currentValue);
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs
new file mode 100644
index 0000000000..f816231781
--- /dev/null
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using System.Numerics;
+using Avalonia.Rendering.Composition.Server;
+using Avalonia.Rendering.Composition.Transport;
+
+namespace Avalonia.Rendering.Composition;
+
+public class CompositionCustomVisual : CompositionContainerVisual
+{
+ private List