diff --git a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
index b37231243d..74ee43ed92 100644
--- a/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
+++ b/samples/ControlCatalog/Pages/CompositionPage.axaml.cs
@@ -111,7 +111,7 @@ public partial class CompositionPage : UserControl
{
if (_implicitAnimations == null)
{
- var compositor = ElementCompositionPreview.GetElementVisual(this)!.Compositor;
+ var compositor = ElementComposition.GetElementVisual(this)!.Compositor;
var offsetAnimation = compositor.CreateVector3KeyFrameAnimation();
offsetAnimation.Target = "Offset";
@@ -143,11 +143,11 @@ public partial class CompositionPage : UserControl
return;
}
- if (ElementCompositionPreview.GetElementVisual(page) == null)
+ if (ElementComposition.GetElementVisual(page) == null)
return;
page.EnsureImplicitAnimations();
- ElementCompositionPreview.GetElementVisual((Visual)border.GetVisualParent()).ImplicitAnimations =
+ ElementComposition.GetElementVisual((Visual)border.GetVisualParent()).ImplicitAnimations =
page._implicitAnimations;
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Utils/CubicBezier.cs b/src/Avalonia.Base/Animation/Easings/CubicBezier.cs
similarity index 97%
rename from src/Avalonia.Base/Rendering/Composition/Utils/CubicBezier.cs
rename to src/Avalonia.Base/Animation/Easings/CubicBezier.cs
index 8c85d7978b..5c2487a516 100644
--- a/src/Avalonia.Base/Rendering/Composition/Utils/CubicBezier.cs
+++ b/src/Avalonia.Base/Animation/Easings/CubicBezier.cs
@@ -2,6 +2,7 @@
// Ported from Chromium project https://github.com/chromium/chromium/blob/374d31b7704475fa59f7b2cb836b3b68afdc3d79/ui/gfx/geometry/cubic_bezier.cc
using System;
+using Avalonia.Utilities;
// ReSharper disable CompareOfFloatsByEqualityOperator
// ReSharper disable CommentTypo
@@ -10,8 +11,11 @@ using System;
// ReSharper disable UnusedMember.Global
#pragma warning disable 649
-namespace Avalonia.Rendering.Composition.Utils
+namespace Avalonia.Animation.Easings
{
+ ///
+ /// Represents a cubic bezier curve and can compute Y coordinate for a given X
+ ///
internal unsafe struct CubicBezier
{
const int CUBIC_BEZIER_SPLINE_SAMPLES = 11;
@@ -284,7 +288,7 @@ namespace Avalonia.Rendering.Composition.Utils
public readonly double SlopeWithEpsilon(double x, double epsilon)
{
- x = MathExt.Clamp(x, 0.0, 1.0);
+ x = MathUtilities.Clamp(x, 0.0, 1.0);
double t = SolveCurveX(x, epsilon);
double dx = SampleCurveDerivativeX(t);
double dy = SampleCurveDerivativeY(t);
diff --git a/src/Avalonia.Base/Animation/Easings/CubicBezierEasing.cs b/src/Avalonia.Base/Animation/Easings/CubicBezierEasing.cs
new file mode 100644
index 0000000000..e51c35c4e6
--- /dev/null
+++ b/src/Avalonia.Base/Animation/Easings/CubicBezierEasing.cs
@@ -0,0 +1,29 @@
+using System;
+using Avalonia.Rendering.Composition;
+using Avalonia.Rendering.Composition.Utils;
+
+namespace Avalonia.Animation.Easings;
+
+public class CubicBezierEasing : IEasing
+{
+ private CubicBezier _bezier;
+ //cubic-bezier(0.25, 0.1, 0.25, 1.0)
+ internal CubicBezierEasing(Point controlPoint1, Point controlPoint2)
+ {
+ ControlPoint1 = controlPoint1;
+ ControlPoint2 = controlPoint2;
+ if (controlPoint1.X < 0 || controlPoint1.X > 1 || controlPoint2.X < 0 || controlPoint2.X > 1)
+ throw new ArgumentException();
+ _bezier = new CubicBezier(controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y);
+ }
+
+ public Point ControlPoint2 { get; set; }
+ public Point ControlPoint1 { get; set; }
+
+ internal static IEasing Ease { get; } = new CubicBezierEasing(new Point(0.25, 0.1), new Point(0.25, 1));
+
+ double IEasing.Ease(double progress)
+ {
+ return _bezier.Solve(progress);
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj
index 38d114eca2..4c988c8ae1 100644
--- a/src/Avalonia.Base/Avalonia.Base.csproj
+++ b/src/Avalonia.Base/Avalonia.Base.csproj
@@ -35,6 +35,10 @@
-
+
+
+
+
+
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/AnimatedValueStore.cs b/src/Avalonia.Base/Rendering/Composition/Animations/AnimatedValueStore.cs
index 95bc384743..f4735040d5 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/AnimatedValueStore.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/AnimatedValueStore.cs
@@ -7,10 +7,15 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// This is the first element of both animated and non-animated value stores.
+ /// It's used to propagate property invalidation to subscribers
+ ///
+
internal struct ServerObjectSubscriptionStore
{
public bool IsValid;
- public RefTrackingDictionary Subscribers;
+ public RefTrackingDictionary? Subscribers;
public void Invalidate()
{
@@ -23,6 +28,10 @@ namespace Avalonia.Rendering.Composition.Animations
}
}
+ ///
+ /// The value store for non-animated values that can still be referenced by animations.
+ /// Simply stores the value and notifies subscribers
+ ///
[StructLayout(LayoutKind.Sequential)]
internal struct ServerValueStore
{
@@ -43,7 +52,12 @@ namespace Avalonia.Rendering.Composition.Animations
}
}
}
-
+
+ ///
+ /// Value store for potentially animated values. Can hold both direct value and animation instance.
+ /// Is also responsible for activating/deactivating the animation when container object is activated/deactivated
+ ///
+ ///
[StructLayout(LayoutKind.Sequential)]
internal struct ServerAnimatedValueStore where T : struct
{
@@ -53,8 +67,6 @@ namespace Avalonia.Rendering.Composition.Animations
private T _direct;
private T? _lastAnimated;
- public T Direct => _direct;
-
public T GetAnimated(ServerCompositor compositor)
{
Subscriptions.IsValid = true;
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs b/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
index 212237049f..35aa8de1bc 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
@@ -5,6 +5,11 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations;
+
+///
+/// The base class for both key-frame and expression animation instances
+/// Is responsible for activation tracking and for subscribing to properties used in dependencies
+///
internal abstract class AnimationInstanceBase : IAnimationInstance
{
private List<(ServerObject obj, int member)>? _trackedObjects;
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
index cf81c6e656..c5102a2d7d 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
@@ -10,51 +10,66 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition.Animations
{
- public abstract class CompositionAnimation : CompositionObject, ICompositionAnimationBase
- {
- private readonly CompositionPropertySet _propertySet;
- internal CompositionAnimation(Compositor compositor) : base(compositor, null!)
- {
- _propertySet = new CompositionPropertySet(compositor);
- }
-
- public void ClearAllParameters() => _propertySet.ClearAll();
-
- public void ClearParameter(string key) => _propertySet.Clear(key);
-
- void SetVariant(string key, ExpressionVariant value) => _propertySet.Set(key, value);
-
- public void SetColorParameter(string key, Avalonia.Media.Color value) => SetVariant(key, value);
-
- public void SetMatrix3x2Parameter(string key, Matrix3x2 value) => SetVariant(key, value);
-
- public void SetMatrix4x4Parameter(string key, Matrix4x4 value) => SetVariant(key, value);
-
- public void SetQuaternionParameter(string key, Quaternion value) => SetVariant(key, value);
-
- public void SetReferenceParameter(string key, CompositionObject compositionObject) =>
- _propertySet.Set(key, compositionObject);
-
- public void SetScalarParameter(string key, float value) => SetVariant(key, value);
-
- public void SetVector2Parameter(string key, Vector2 value) => SetVariant(key, value);
-
- public void SetVector3Parameter(string key, Vector3 value) => SetVariant(key, value);
-
- public void SetVector4Parameter(string key, Vector4 value) => SetVariant(key, value);
-
- // TODO: void SetExpressionReferenceParameter(string parameterName, IAnimationObject source)
-
- public string? Target { get; set; }
-
- internal abstract IAnimationInstance CreateInstance(ServerObject targetObject,
- ExpressionVariant? finalValue);
-
- internal PropertySetSnapshot CreateSnapshot() => _propertySet.Snapshot();
-
- void ICompositionAnimationBase.InternalOnly()
- {
-
- }
- }
+ ///
+ /// This is the base class for ExpressionAnimation and KeyFrameAnimation.
+ ///
+ ///
+ /// Use the method to start the animation.
+ /// Value parameters (as opposed to reference parameters which are set using )
+ /// are copied and "embedded" into an expression at the time CompositionObject.StartAnimation is called.
+ /// Changing the value of the variable after is called will not affect
+ /// the value of the ExpressionAnimation.
+ /// See the remarks section of ExpressionAnimation for additional information.
+ ///
+ public abstract class CompositionAnimation : CompositionObject, ICompositionAnimationBase
+ {
+ private readonly CompositionPropertySet _propertySet;
+ internal CompositionAnimation(Compositor compositor) : base(compositor, null!)
+ {
+ _propertySet = new CompositionPropertySet(compositor);
+ }
+
+ ///
+ /// Clears all of the parameters of the animation.
+ ///
+ public void ClearAllParameters() => _propertySet.ClearAll();
+
+ ///
+ /// Clears a parameter from the animation.
+ ///
+ public void ClearParameter(string key) => _propertySet.Clear(key);
+
+ void SetVariant(string key, ExpressionVariant value) => _propertySet.Set(key, value);
+
+ public void SetColorParameter(string key, Media.Color value) => SetVariant(key, value);
+
+ public void SetMatrix3x2Parameter(string key, Matrix3x2 value) => SetVariant(key, value);
+
+ public void SetMatrix4x4Parameter(string key, Matrix4x4 value) => SetVariant(key, value);
+
+ public void SetQuaternionParameter(string key, Quaternion value) => SetVariant(key, value);
+
+ public void SetReferenceParameter(string key, CompositionObject compositionObject) =>
+ _propertySet.Set(key, compositionObject);
+
+ public void SetScalarParameter(string key, float value) => SetVariant(key, value);
+
+ public void SetVector2Parameter(string key, Vector2 value) => SetVariant(key, value);
+
+ public void SetVector3Parameter(string key, Vector3 value) => SetVariant(key, value);
+
+ public void SetVector4Parameter(string key, Vector4 value) => SetVariant(key, value);
+
+ public string? Target { get; set; }
+
+ internal abstract IAnimationInstance CreateInstance(ServerObject targetObject,
+ ExpressionVariant? finalValue);
+
+ internal PropertySetSnapshot CreateSnapshot() => _propertySet.Snapshot();
+
+ void ICompositionAnimationBase.InternalOnly()
+ {
+
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs
index 6a2c07e6ef..163f4e99ba 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs
@@ -5,6 +5,17 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// A Composition Animation that uses a mathematical equation to calculate the value for an animating property every frame.
+ ///
+ ///
+ /// The core of ExpressionAnimations allows a developer to define a mathematical equation that can be used to calculate the value
+ /// of a targeted animating property each frame.
+ /// This contrasts s, which use an interpolator to define how the animating
+ /// property changes over time. The mathematical equation can be defined using references to properties
+ /// of Composition objects, mathematical functions and operators and Input.
+ /// Use the method to start the animation.
+ ///
public class ExpressionAnimation : CompositionAnimation
{
private string? _expression;
@@ -14,6 +25,14 @@ namespace Avalonia.Rendering.Composition.Animations
{
}
+ ///
+ /// The mathematical equation specifying how the animated value is calculated each frame.
+ /// The Expression is the core of an and represents the equation
+ /// the system will use to calculate the value of the animation property each frame.
+ /// The equation is set on this property in the form of a string.
+ /// Although expressions can be defined by simple mathematical equations such as "2+2",
+ /// the real power lies in creating mathematical relationships where the input values can change frame over frame.
+ ///
public string? Expression
{
get => _expression;
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs
index 7944fe7990..445cef9a08 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs
@@ -5,6 +5,10 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations
{
+
+ ///
+ /// Server-side counterpart of with values baked-in.
+ ///
internal class ExpressionAnimationInstance : AnimationInstanceBase, IAnimationInstance
{
private readonly Expression _expression;
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs
index bf40fd3ad2..87e5ad757a 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs
@@ -4,6 +4,9 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// Base class for composition animations.
+ ///
public interface ICompositionAnimationBase
{
internal void InternalOnly();
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs b/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
index fa5b69dae9..f4bcc6ff38 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
@@ -6,6 +6,17 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// A collection of animations triggered when a condition is met.
+ ///
+ ///
+ /// Implicit animations let you drive animations by specifying trigger conditions rather than requiring the manual definition of animation behavior.
+ /// They help decouple animation start logic from core app logic. You define animations and the events that should trigger these animations.
+ /// Currently the only available trigger is animated property change.
+ ///
+ /// When expression is used in ImplicitAnimationCollection a special keyword `this.FinalValue` will represent
+ /// the final value of the animated property that was changed
+ ///
public class ImplicitAnimationCollection : CompositionObject, IDictionary
{
private Dictionary _inner = new Dictionary();
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs b/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs
index 62b790701a..a4eeacef32 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs
@@ -3,6 +3,9 @@ using System.Numerics;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// An interface to define interpolation logic for a particular type
+ ///
internal interface IInterpolator
{
T Interpolate(T from, T to, float progress);
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs
index 065dfd7a8e..49b3ab753a 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs
@@ -1,53 +1,134 @@
+using System;
+using Avalonia.Animation;
+using Avalonia.Animation.Easings;
+
namespace Avalonia.Rendering.Composition.Animations
{
+
+ ///
+ /// A time-based animation with one or more key frames.
+ /// These frames are markers, allowing developers to specify values at specific times for the animating property.
+ /// KeyFrame animations can be further customized by specifying how the animation interpolates between keyframes.
+ ///
public abstract class KeyFrameAnimation : CompositionAnimation
{
+ private TimeSpan _duration = TimeSpan.FromMilliseconds(1);
+
internal KeyFrameAnimation(Compositor compositor) : base(compositor)
{
}
+ ///
+ /// The delay behavior of the key frame animation.
+ ///
public AnimationDelayBehavior DelayBehavior { get; set; }
+
+ ///
+ /// Delay before the animation starts after is called.
+ ///
public System.TimeSpan DelayTime { get; set; }
- public AnimationDirection Direction { get; set; }
- public System.TimeSpan Duration { get; set; }
+
+ ///
+ /// The direction the animation is playing.
+ /// The Direction property allows you to drive your animation from start to end or end to start or alternate
+ /// between start and end or end to start if animation has an greater than one.
+ /// This gives an easy way for customizing animation definitions.
+ ///
+ public PlaybackDirection Direction { get; set; }
+
+ ///
+ /// The duration of the animation.
+ /// Minimum allowed value is 1ms and maximum allowed value is 24 days.
+ ///
+ public TimeSpan Duration
+ {
+ get => _duration;
+ set
+ {
+ if (_duration < TimeSpan.FromMilliseconds(1) || _duration > TimeSpan.FromDays(1))
+ throw new ArgumentException("Minimum allowed value is 1ms and maximum allowed value is 24 days.");
+ _duration = value;
+ }
+ }
+
+ ///
+ /// The iteration behavior for the key frame animation.
+ ///
public AnimationIterationBehavior IterationBehavior { get; set; }
+
+ ///
+ /// The number of times to repeat the key frame animation.
+ ///
public int IterationCount { get; set; } = 1;
+
+ ///
+ /// Specifies how to set the property value when animation is stopped
+ ///
public AnimationStopBehavior StopBehavior { get; set; }
private protected abstract IKeyFrames KeyFrames { get; }
+ ///
+ /// Inserts an expression keyframe.
+ ///
+ ///
+ /// The time the key frame should occur at, expressed as a percentage of the animation Duration. Allowed value is from 0.0 to 1.0.
+ ///
+ /// The expression used to calculate the value of the key frame.
+ /// The easing function to use when interpolating between frames.
public void InsertExpressionKeyFrame(float normalizedProgressKey, string value,
- CompositionEasingFunction easingFunction) =>
- KeyFrames.InsertExpressionKeyFrame(normalizedProgressKey, value, easingFunction);
-
- public void InsertExpressionKeyFrame(float normalizedProgressKey, string value)
- => KeyFrames.InsertExpressionKeyFrame(normalizedProgressKey, value, new LinearEasingFunction(Compositor));
+ Easing? easingFunction = null) =>
+ KeyFrames.InsertExpressionKeyFrame(normalizedProgressKey, value, easingFunction ?? Compositor.DefaultEasing);
}
+ ///
+ /// Specifies the animation delay behavior.
+ ///
public enum AnimationDelayBehavior
{
+ ///
+ /// If a DelayTime is specified, it delays starting the animation according to delay time and after delay
+ /// has expired it applies animation to the object property.
+ ///
SetInitialValueAfterDelay,
+ ///
+ /// Applies the initial value of the animation (i.e. the value at Keyframe 0) to the object before the delay time
+ /// is elapsed (when there is a DelayTime specified), it then delays starting the animation according to the DelayTime.
+ ///
SetInitialValueBeforeDelay
}
- public enum AnimationDirection
- {
- Normal,
- Reverse,
- Alternate,
- AlternateReverse
- }
-
+ ///
+ /// Specifies if the animation should loop.
+ ///
public enum AnimationIterationBehavior
{
+ ///
+ /// The animation should loop the specified number of times.
+ ///
Count,
+ ///
+ /// The animation should loop forever.
+ ///
Forever
}
+ ///
+ /// Specifies the behavior of an animation when it stops.
+ ///
public enum AnimationStopBehavior
{
+ ///
+ /// Leave the animation at its current value.
+ ///
LeaveCurrentValue,
+ ///
+ /// Reset the animation to its initial value.
+ ///
SetToInitialValue,
+ ///
+ /// Set the animation to its final value.
+ ///
SetToFinalValue
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
index 9571cef0b4..7268780298 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
@@ -1,10 +1,14 @@
using System;
using System.Collections.Generic;
+using Avalonia.Animation;
using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// Server-side counterpart of KeyFrameAnimation with values baked-in
+ ///
class KeyFrameAnimationInstance : AnimationInstanceBase, IAnimationInstance where T : struct
{
private readonly IInterpolator _interpolator;
@@ -12,7 +16,7 @@ namespace Avalonia.Rendering.Composition.Animations
private readonly ExpressionVariant? _finalValue;
private readonly AnimationDelayBehavior _delayBehavior;
private readonly TimeSpan _delayTime;
- private readonly AnimationDirection _direction;
+ private readonly PlaybackDirection _direction;
private readonly TimeSpan _duration;
private readonly AnimationIterationBehavior _iterationBehavior;
private readonly int _iterationCount;
@@ -27,7 +31,7 @@ namespace Avalonia.Rendering.Composition.Animations
PropertySetSnapshot snapshot, ExpressionVariant? finalValue,
ServerObject target,
AnimationDelayBehavior delayBehavior, TimeSpan delayTime,
- AnimationDirection direction, TimeSpan duration,
+ PlaybackDirection direction, TimeSpan duration,
AnimationIterationBehavior iterationBehavior,
int iterationCount, AnimationStopBehavior stopBehavior) : base(target, snapshot)
{
@@ -96,11 +100,11 @@ namespace Avalonia.Rendering.Composition.Animations
elapsed = TimeSpan.FromTicks(elapsed.Ticks % _duration.Ticks);
var reverse =
- _direction == AnimationDirection.Alternate
+ _direction == PlaybackDirection.Alternate
? !evenIterationNumber
- : _direction == AnimationDirection.AlternateReverse
+ : _direction == PlaybackDirection.AlternateReverse
? evenIterationNumber
- : _direction == AnimationDirection.Reverse;
+ : _direction == PlaybackDirection.Reverse;
var iterationProgress = elapsed.TotalSeconds / _duration.TotalSeconds;
if (reverse)
@@ -128,7 +132,7 @@ namespace Avalonia.Rendering.Composition.Animations
var keyProgress = Math.Max(0, Math.Min(1, (iterationProgress - left.Key) / (right.Key - left.Key)));
- var easedKeyProgress = right.EasingFunction.Ease((float) keyProgress);
+ var easedKeyProgress = (float)right.EasingFunction.Ease(keyProgress);
if (float.IsNaN(easedKeyProgress) || float.IsInfinity(easedKeyProgress))
return currentValue;
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs
index 26ba35409d..369cc80b95 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs
@@ -1,9 +1,15 @@
using System;
using System.Collections.Generic;
+using Avalonia.Animation.Easings;
using Avalonia.Rendering.Composition.Expressions;
namespace Avalonia.Rendering.Composition.Animations
{
+
+ ///
+ /// Collection of composition animation key frames
+ ///
+ ///
class KeyFrames : List>, IKeyFrames
{
void Validate(float key)
@@ -14,8 +20,7 @@ namespace Avalonia.Rendering.Composition.Animations
throw new ArgumentException("Key frame key " + key + " is less than the previous one");
}
- public void InsertExpressionKeyFrame(float normalizedProgressKey, string value,
- CompositionEasingFunction easingFunction)
+ public void InsertExpressionKeyFrame(float normalizedProgressKey, string value, IEasing easingFunction)
{
Validate(normalizedProgressKey);
Add(new KeyFrame
@@ -26,7 +31,7 @@ namespace Avalonia.Rendering.Composition.Animations
});
}
- public void Insert(float normalizedProgressKey, T value, CompositionEasingFunction easingFunction)
+ public void Insert(float normalizedProgressKey, T value, IEasing easingFunction)
{
Validate(normalizedProgressKey);
Add(new KeyFrame
@@ -47,7 +52,7 @@ namespace Avalonia.Rendering.Composition.Animations
{
Expression = f.Expression,
Value = f.Value,
- EasingFunction = f.EasingFunction.Snapshot(),
+ EasingFunction = f.EasingFunction,
Key = f.NormalizedProgressKey
};
}
@@ -55,26 +60,30 @@ namespace Avalonia.Rendering.Composition.Animations
}
}
+ ///
+ /// Composition animation key frame
+ ///
struct KeyFrame
{
public float NormalizedProgressKey;
public T Value;
public Expression Expression;
- public CompositionEasingFunction EasingFunction;
+ public IEasing EasingFunction;
}
+ ///
+ /// Server-side composition animation key frame
+ ///
struct ServerKeyFrame
{
public T Value;
public Expression? Expression;
- public IEasingFunction EasingFunction;
+ public IEasing EasingFunction;
public float Key;
}
-
-
interface IKeyFrames
{
- public void InsertExpressionKeyFrame(float normalizedProgressKey, string value, CompositionEasingFunction easingFunction);
+ public void InsertExpressionKeyFrame(float normalizedProgressKey, string value, IEasing easingFunction);
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs b/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs
index ca703dfc6f..fc6cfc9f3d 100644
--- a/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs
@@ -3,6 +3,9 @@ using Avalonia.Rendering.Composition.Expressions;
namespace Avalonia.Rendering.Composition.Animations
{
+ ///
+ /// A snapshot of properties used by an animation
+ ///
internal class PropertySetSnapshot : IExpressionParameterCollection, IExpressionObject
{
private readonly Dictionary _dic;
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
index 8cb7daca6b..5e8e9c24f9 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
@@ -13,7 +13,10 @@ using Avalonia.VisualTree;
namespace Avalonia.Rendering.Composition;
-public class CompositingRenderer : RendererBase, IRendererWithCompositor
+///
+/// A renderer that utilizes to render the visual tree
+///
+public class CompositingRenderer : IRendererWithCompositor
{
private readonly IRenderRoot _root;
private readonly Compositor _compositor;
@@ -24,9 +27,10 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
private readonly CompositionTarget _target;
private bool _queuedUpdate;
private Action _update;
+ private Action _invalidateScene;
///
- /// Forces the renderer to only draw frames on the render thread. Makes Paint to wait until frame is rendered
+ /// Asks the renderer to only draw frames on the render thread. Makes Paint to wait until frame is rendered.
///
public bool RenderOnlyOnRenderThread { get; set; } = true;
@@ -39,20 +43,24 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
_target = compositor.CreateCompositionTarget(root.CreateRenderTarget);
_target.Root = ((Visual)root!.VisualRoot!).AttachToCompositor(compositor);
_update = Update;
+ _invalidateScene = InvalidateScene;
}
+ ///
public bool DrawFps
{
get => _target.DrawFps;
set => _target.DrawFps = value;
}
-
+
+ ///
public bool DrawDirtyRects
{
get => _target.DrawDirtyRects;
set => _target.DrawDirtyRects = value;
}
+ ///
public event EventHandler? SceneInvalidated;
void QueueUpdate()
@@ -62,12 +70,15 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
_queuedUpdate = true;
Dispatcher.UIThread.Post(_update, DispatcherPriority.Composition);
}
+
+ ///
public void AddDirty(IVisual visual)
{
_dirty.Add((Visual)visual);
QueueUpdate();
}
+ ///
public IEnumerable HitTest(Point p, IVisual root, Func? filter)
{
var res = _target.TryHitTest(p, filter);
@@ -84,12 +95,14 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
}
}
+ ///
public IVisual? HitTestFirst(Point p, IVisual root, Func? filter)
{
// TODO: Optimize
return HitTest(p, root, filter).FirstOrDefault();
}
+ ///
public void RecalculateChildren(IVisual visual)
{
_recalculateChildren.Add((Visual)visual);
@@ -172,7 +185,10 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
compositionChildren.Add(compositionChild);
}
}
-
+
+ private void InvalidateScene() =>
+ SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs(_root, new Rect(_root.ClientSize)));
+
private void Update()
{
_queuedUpdate = false;
@@ -223,6 +239,7 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
_recalculateChildren.Clear();
_target.Size = _root.ClientSize;
_target.Scaling = _root.RenderScaling;
+ Compositor.InvokeOnNextCommit(_invalidateScene);
}
public void Resized(Size size)
@@ -257,6 +274,8 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
_compositor.RequestCommitAsync().Wait();
}
-
+ ///
+ /// The associated object
+ ///
public Compositor Compositor => _compositor;
}
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
index cc2b411822..47cfcd325b 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
@@ -7,12 +7,23 @@ using Avalonia.VisualTree;
namespace Avalonia.Rendering.Composition;
+
+///
+/// A composition visual that holds a list of drawing commands issued by
+///
internal class CompositionDrawListVisual : CompositionContainerVisual
{
+ ///
+ /// The associated
+ ///
public Visual Visual { get; }
private bool _drawListChanged;
private CompositionDrawList? _drawList;
+
+ ///
+ /// The list of drawing commands
+ ///
public CompositionDrawList? DrawList
{
get => _drawList;
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionEasingFunction.cs b/src/Avalonia.Base/Rendering/Composition/CompositionEasingFunction.cs
deleted file mode 100644
index 90b2bec268..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/CompositionEasingFunction.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using System;
-using System.Numerics;
-using Avalonia.Rendering.Composition.Transport;
-using Avalonia.Rendering.Composition.Utils;
-
-namespace Avalonia.Rendering.Composition
-{
- public abstract class CompositionEasingFunction : CompositionObject
- {
- internal CompositionEasingFunction(Compositor compositor) : base(compositor, null!)
- {
- }
-
- internal abstract IEasingFunction Snapshot();
- }
-
- internal interface IEasingFunction
- {
- float Ease(float progress);
- }
-
- public sealed class DelegateCompositionEasingFunction : CompositionEasingFunction
- {
- private readonly Easing _func;
-
- public delegate float EasingDelegate(float progress);
-
- internal DelegateCompositionEasingFunction(Compositor compositor, EasingDelegate func) : base(compositor)
- {
- _func = new Easing(func);
- }
-
- class Easing : IEasingFunction
- {
- private readonly EasingDelegate _func;
-
- public Easing(EasingDelegate func)
- {
- _func = func;
- }
-
- public float Ease(float progress) => _func(progress);
- }
-
- internal override IEasingFunction Snapshot() => _func;
- }
-
- public class LinearEasingFunction : CompositionEasingFunction
- {
- public LinearEasingFunction(Compositor compositor) : base(compositor)
- {
- }
-
- class Linear : IEasingFunction
- {
- public float Ease(float progress) => progress;
- }
-
- private static readonly Linear Instance = new Linear();
- internal override IEasingFunction Snapshot() => Instance;
- }
-
- public class CubicBezierEasingFunction : CompositionEasingFunction
- {
- private CubicBezier _bezier;
- public Vector2 ControlPoint1 { get; }
- public Vector2 ControlPoint2 { get; }
- //cubic-bezier(0.25, 0.1, 0.25, 1.0)
- internal CubicBezierEasingFunction(Compositor compositor, Vector2 controlPoint1, Vector2 controlPoint2) : base(compositor)
- {
- ControlPoint1 = controlPoint1;
- ControlPoint2 = controlPoint2;
- if (controlPoint1.X < 0 || controlPoint1.X > 1 || controlPoint2.X < 0 || controlPoint2.X > 1)
- throw new ArgumentException();
- _bezier = new CubicBezier(controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y);
- }
-
- class EasingFunction : IEasingFunction
- {
- private readonly CubicBezier _bezier;
-
- public EasingFunction(CubicBezier bezier)
- {
- _bezier = bezier;
- }
-
- public float Ease(float progress) => (float)_bezier.Solve(progress);
- }
-
- internal static IEasingFunction Ease { get; } = new EasingFunction(new CubicBezier(0.25, 0.1, 0.25, 1));
-
- internal override IEasingFunction Snapshot() => new EasingFunction(_bezier);
- }
-
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionGradientBrush.cs b/src/Avalonia.Base/Rendering/Composition/CompositionGradientBrush.cs
deleted file mode 100644
index cf222550dd..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/CompositionGradientBrush.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Avalonia.Rendering.Composition.Server;
-
-namespace Avalonia.Rendering.Composition
-{
- public partial class CompositionGradientBrush : CompositionBrush
- {
- internal CompositionGradientBrush(Compositor compositor, ServerCompositionGradientBrush server) : base(compositor, server)
- {
- ColorStops = new CompositionGradientStopCollection(compositor, server.Stops);
- }
-
- public CompositionGradientStopCollection ColorStops { get; }
- }
-
-
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs b/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
index baf1bfcddf..0ed9a3c75d 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
@@ -6,8 +6,16 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// Base class of the composition API representing a node in the visual tree structure.
+ /// Composition objects are the visual tree structure on which all other features of the composition API use and build on.
+ /// The API allows developers to define and create one or many objects each representing a single node in a Visual tree.
+ ///
public abstract class CompositionObject : IDisposable
{
+ ///
+ /// The collection of implicit animations attached to this object.
+ ///
public ImplicitAnimationCollection? ImplicitAnimations { get; set; }
internal CompositionObject(Compositor compositor, ServerObject server)
{
@@ -15,6 +23,9 @@ namespace Avalonia.Rendering.Composition
Server = server;
}
+ ///
+ /// The associated Compositor
+ ///
public Compositor Compositor { get; }
internal ServerObject Server { get; }
public bool IsDisposed { get; private set; }
@@ -29,14 +40,22 @@ namespace Avalonia.Rendering.Composition
IsDisposed = true;
}
+ ///
+ /// Connects an animation with the specified property of the object and starts the animation.
+ ///
public void StartAnimation(string propertyName, CompositionAnimation animation)
=> StartAnimation(propertyName, animation, null);
- internal virtual void StartAnimation(string propertyName, CompositionAnimation animation, ExpressionVariant? finalValue = null)
+ internal virtual void StartAnimation(string propertyName, CompositionAnimation animation, ExpressionVariant? finalValue)
{
throw new ArgumentException("Unknown property " + propertyName);
}
+ ///
+ /// Starts an animation group.
+ /// The StartAnimationGroup method on CompositionObject lets you start CompositionAnimationGroup.
+ /// All the animations in the group will be started at the same time on the object.
+ ///
public void StartAnimationGroup(ICompositionAnimationBase grp)
{
if (grp is CompositionAnimation animation)
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs b/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
index 584969cbc0..ee4552d154 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
@@ -7,6 +7,15 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// s are s that allow storage of key values pairs
+ /// that can be shared across the application and are not tied to the lifetime of another composition object.
+ /// s are most commonly used with animations, where they maintain key-value pairs
+ /// that are referenced to drive portions of composition animations. s
+ /// provide the ability to insert key-value pairs or retrieve a value for a given key.
+ /// does not support a delete function – ensure you use
+ /// to store values that will be shared across the application.
+ ///
public class CompositionPropertySet : CompositionObject
{
private readonly Dictionary _variants = new Dictionary();
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
index 7e50c43ac1..25bbd4dc88 100644
--- a/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
+++ b/src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
@@ -6,6 +6,9 @@ using Avalonia.VisualTree;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// Represents the composition output (e. g. a window, embedded control, entire screen)
+ ///
public partial class CompositionTarget
{
partial void OnRootChanged()
@@ -20,6 +23,12 @@ namespace Avalonia.Rendering.Composition
Root.Root = null;
}
+ ///
+ /// Attempts to perform a hit-tst
+ ///
+ ///
+ ///
+ ///
public PooledList? TryHitTest(Point point, Func? filter)
{
Server.Readback.NextRead();
@@ -30,6 +39,10 @@ namespace Avalonia.Rendering.Composition
return res;
}
+ ///
+ /// Attempts to transform a point to a particular CompositionVisual coordinate space
+ ///
+ ///
public Point? TryTransformToVisual(CompositionVisual visual, Point point)
{
if (visual.Root != this)
@@ -108,8 +121,14 @@ namespace Avalonia.Rendering.Composition
}
+ ///
+ /// Registers the composition target for explicit redraw
+ ///
public void RequestRedraw() => RegisterForSerialization();
+ ///
+ /// Performs composition directly on the UI thread
+ ///
internal void ImmediateUIThreadRender()
{
Compositor.RequestCommitAsync();
diff --git a/src/Avalonia.Base/Rendering/Composition/Compositor.cs b/src/Avalonia.Base/Rendering/Composition/Compositor.cs
index e92b69bd60..28c81dfb91 100644
--- a/src/Avalonia.Base/Rendering/Composition/Compositor.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Compositor.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Threading.Tasks;
+using Avalonia.Animation.Easings;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering.Composition.Animations;
@@ -13,6 +14,10 @@ using Avalonia.Threading;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// The Compositor class manages communication between UI-thread and render-thread parts of the composition engine.
+ /// It also serves as a factory to create UI-thread parts of various composition objects
+ ///
public partial class Compositor
{
internal IRenderLoop Loop { get; }
@@ -23,22 +28,38 @@ namespace Avalonia.Rendering.Composition
private BatchStreamMemoryPool _batchMemoryPool = new();
private List _objectsForSerialization = new();
internal ServerCompositor Server => _server;
- internal CompositionEasingFunction DefaultEasing { get; }
-
+ internal IEasing DefaultEasing { get; }
+ private List? _invokeOnNextCommit;
+ private readonly Stack> _invokeListPool = new();
+
+ ///
+ /// Creates a new compositor on a specified render loop that would use a particular GPU
+ ///
+ ///
+ ///
public Compositor(IRenderLoop loop, IPlatformGpu? gpu)
{
Loop = loop;
_server = new ServerCompositor(loop, gpu, _batchObjectPool, _batchMemoryPool);
_implicitBatchCommit = ImplicitBatchCommit;
- DefaultEasing = new CubicBezierEasingFunction(this,
- new Vector2(0.25f, 0.1f), new Vector2(0.25f, 1f));
+
+ DefaultEasing = new CubicBezierEasing(new Point(0.25f, 0.1f), new Point(0.25f, 1f));
}
+ ///
+ /// Creates a new CompositionTarget
+ ///
+ /// A factory method to create IRenderTarget to be called from the render thread
+ ///
public CompositionTarget CreateCompositionTarget(Func renderTargetFactory)
{
return new CompositionTarget(this, new ServerCompositionTarget(_server, renderTargetFactory));
}
+ ///
+ /// Requests pending changes in the composition objects to be serialized and sent to the render thread
+ ///
+ /// A task that completes when sent changes are applied and rendered on the render thread
public Task RequestCommitAsync()
{
var batch = new Batch();
@@ -59,64 +80,25 @@ namespace Avalonia.Rendering.Composition
batch.CommitedAt = Server.Clock.Elapsed;
_server.EnqueueBatch(batch);
+ if (_invokeOnNextCommit != null)
+ ScheduleCommitCallbacks(batch.Completed);
+
return batch.Completed;
}
- public CompositionContainerVisual CreateContainerVisual() => new(this, new ServerCompositionContainerVisual(_server));
-
- public CompositionSolidColorVisual CreateSolidColorVisual() => new CompositionSolidColorVisual(this,
- new ServerCompositionSolidColorVisual(_server));
-
- public CompositionSolidColorVisual CreateSolidColorVisual(Avalonia.Media.Color color)
- {
- var v = new CompositionSolidColorVisual(this, new ServerCompositionSolidColorVisual(_server));
- v.Color = color;
- return v;
- }
-
- public CompositionSpriteVisual CreateSpriteVisual() => new CompositionSpriteVisual(this, new ServerCompositionSpriteVisual(_server));
-
- public CompositionLinearGradientBrush CreateLinearGradientBrush()
- => new CompositionLinearGradientBrush(this, new ServerCompositionLinearGradientBrush(_server));
-
- public CompositionColorGradientStop CreateColorGradientStop()
- => new CompositionColorGradientStop(this, new ServerCompositionColorGradientStop(_server));
-
- public CompositionColorGradientStop CreateColorGradientStop(float offset, Avalonia.Media.Color color)
- {
- var stop = CreateColorGradientStop();
- stop.Offset = offset;
- stop.Color = color;
- return stop;
- }
-
- // We want to make it 100% async later
- /*
- public CompositionBitmapSurface LoadBitmapSurface(Stream stream)
+ async void ScheduleCommitCallbacks(Task task)
{
- var bmp = _server.Backend.LoadCpuMemoryBitmap(stream);
- return new CompositionBitmapSurface(this, bmp);
+ var list = _invokeOnNextCommit;
+ _invokeOnNextCommit = null;
+ await task;
+ foreach (var i in list!)
+ i();
+ list.Clear();
+ _invokeListPool.Push(list);
}
- public async Task LoadBitmapSurfaceAsync(Stream stream)
- {
- var bmp = await Task.Run(() => _server.Backend.LoadCpuMemoryBitmap(stream));
- return new CompositionBitmapSurface(this, bmp);
- }
- */
- public CompositionColorBrush CreateColorBrush(Avalonia.Media.Color color) =>
- new CompositionColorBrush(this, new ServerCompositionColorBrush(_server)) {Color = color};
-
- public CompositionSurfaceBrush CreateSurfaceBrush() =>
- new CompositionSurfaceBrush(this, new ServerCompositionSurfaceBrush(_server));
-
- /*
- public CompositionGaussianBlurEffectBrush CreateGaussianBlurEffectBrush() =>
- new CompositionGaussianBlurEffectBrush(this, new ServerCompositionGaussianBlurEffectBrush(_server));
-
- public CompositionBackdropBrush CreateBackdropBrush() =>
- new CompositionBackdropBrush(this, new ServerCompositionBackdropBrush(Server));*/
-
+ public CompositionContainerVisual CreateContainerVisual() => new(this, new ServerCompositionContainerVisual(_server));
+
public ExpressionAnimation CreateExpressionAnimation() => new ExpressionAnimation(this);
public ExpressionAnimation CreateExpressionAnimation(string expression) => new ExpressionAnimation(this)
@@ -147,5 +129,11 @@ namespace Avalonia.Rendering.Composition
_objectsForSerialization.Add(compositionObject);
QueueImplicitBatchCommit();
}
+
+ internal void InvokeOnNextCommit(Action action)
+ {
+ _invokeOnNextCommit ??= _invokeListPool.Count > 0 ? _invokeListPool.Pop() : new();
+ _invokeOnNextCommit.Add(action);
+ }
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/CompositorRenderLoopTask.cs b/src/Avalonia.Base/Rendering/Composition/CompositorRenderLoopTask.cs
deleted file mode 100644
index 074c0a9ccf..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/CompositorRenderLoopTask.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Avalonia.Rendering.Composition;
-
-partial class Compositor
-{
- class CompositorRenderLoopTask : IRenderLoopTask
- {
- public bool NeedsUpdate { get; }
- public void Update(TimeSpan time)
- {
- throw new NotImplementedException();
- }
-
- public void Render()
- {
- throw new NotImplementedException();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs
index 5b2a4be1bc..caf074dd6b 100644
--- a/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs
@@ -2,6 +2,9 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// A node in the visual tree that can have children.
+ ///
public partial class CompositionContainerVisual : CompositionVisual
{
public CompositionVisualCollection Children { get; private set; } = null!;
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs
index 1d416f5a8a..315faf2c86 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs
@@ -6,6 +6,9 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Drawing;
+///
+/// A list of serialized drawing commands
+///
internal class CompositionDrawList : PooledList>
{
public Size? Size { get; set; }
@@ -47,6 +50,9 @@ internal class CompositionDrawList : PooledList>
}
}
+///
+/// An helper class for building
+///
internal class CompositionDrawListBuilder
{
private CompositionDrawList? _operations;
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
index 0c5a98b239..e678a85fcf 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
@@ -10,6 +10,9 @@ using Avalonia.Utilities;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.Composition;
+///
+/// An IDrawingContextImpl implementation that builds
+///
internal class CompositionDrawingContext : IDrawingContextImpl
{
private CompositionDrawListBuilder _builder = new();
diff --git a/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs b/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs
index afda314276..1397a20fb6 100644
--- a/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs
+++ b/src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs
@@ -1,6 +1,14 @@
namespace Avalonia.Rendering.Composition;
-public static class ElementCompositionPreview
+///
+/// Enables access to composition visual objects that back XAML elements in the XAML composition tree.
+///
+public static class ElementComposition
{
+ ///
+ /// Gets CompositionVisual that backs a Visual
+ ///
+ ///
+ ///
public static CompositionVisual? GetElementVisual(Visual visual) => visual.CompositionVisual;
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs
index db9a26e301..44347d2c7a 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs
@@ -2,10 +2,13 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using Avalonia.Rendering.Composition.Animations;
-using Avalonia.Rendering.Composition.Utils;
+using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Expressions
{
+ ///
+ /// Built-in functions for Foreign Function Interface available from composition animation expressions
+ ///
internal class BuiltInExpressionFfi : IExpressionForeignFunctionInterface
{
private readonly DelegateExpressionFfi _registry;
@@ -26,7 +29,7 @@ namespace Avalonia.Rendering.Composition.Expressions
static float SmoothStep(float edge0, float edge1, float x)
{
- var t = MathExt.Clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
+ var t = MathUtilities.Clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return t * t * (3.0f - 2.0f * t);
}
@@ -72,7 +75,7 @@ namespace Avalonia.Rendering.Composition.Expressions
{"ATan", (float f) => (float) Math.Atan(f)},
{"Ceil", (float f) => (float) Math.Ceiling(f)},
- {"Clamp", (float a1, float a2, float a3) => MathExt.Clamp(a1, a2, a3)},
+ {"Clamp", (float a1, float a2, float a3) => MathUtilities.Clamp(a1, a2, a3)},
{"Clamp", (Vector2 a1, Vector2 a2, Vector2 a3) => Vector2.Clamp(a1, a2, a3)},
{"Clamp", (Vector3 a1, Vector3 a2, Vector3 a3) => Vector3.Clamp(a1, a2, a3)},
{"Clamp", (Vector4 a1, Vector4 a2, Vector4 a3) => Vector4.Clamp(a1, a2, a3)},
@@ -96,10 +99,10 @@ namespace Avalonia.Rendering.Composition.Expressions
},
{
"ColorRGB", (float a, float r, float g, float b) => Avalonia.Media.Color.FromArgb(
- (byte) MathExt.Clamp(a, 0, 255),
- (byte) MathExt.Clamp(r, 0, 255),
- (byte) MathExt.Clamp(g, 0, 255),
- (byte) MathExt.Clamp(b, 0, 255)
+ (byte) MathUtilities.Clamp(a, 0, 255),
+ (byte) MathUtilities.Clamp(r, 0, 255),
+ (byte) MathUtilities.Clamp(g, 0, 255),
+ (byte) MathUtilities.Clamp(b, 0, 255)
)
},
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs
index 002cf37522..85c6141409 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs
@@ -7,6 +7,9 @@ using Avalonia.Media;
namespace Avalonia.Rendering.Composition.Expressions
{
+ ///
+ /// Foreign function interface for composition animations based on calling delegates
+ ///
internal class DelegateExpressionFfi : IExpressionForeignFunctionInterface, IEnumerable
{
struct FfiRecord
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
index 088771e1ba..5abba00365 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
@@ -6,6 +6,9 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Expressions
{
+ ///
+ /// A parsed composition expression
+ ///
internal abstract class Expression
{
public abstract ExpressionType Type { get; }
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs
index 086c8ce276..7b900534d8 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs
@@ -22,6 +22,9 @@ namespace Avalonia.Rendering.Composition.Expressions
Color
}
+ ///
+ /// A VARIANT type used in expression animations. Can represent multiple value types
+ ///
[StructLayout(LayoutKind.Explicit)]
internal struct ExpressionVariant
{
diff --git a/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs b/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs
index 1050c7274c..27782c8c2c 100644
--- a/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs
@@ -3,6 +3,9 @@ using System.Globalization;
namespace Avalonia.Rendering.Composition.Expressions
{
+ ///
+ /// Helper class for composition expression parser
+ ///
internal ref struct TokenParser
{
private ReadOnlySpan _s;
diff --git a/src/Avalonia.Base/Rendering/Composition/ICompositionSurface.cs b/src/Avalonia.Base/Rendering/Composition/ICompositionSurface.cs
deleted file mode 100644
index 9ef31c30e0..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/ICompositionSurface.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Avalonia.Rendering.Composition.Server;
-
-namespace Avalonia.Rendering.Composition
-{
- public interface ICompositionSurface
- {
- internal ServerCompositionSurface Server { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
index 8b6ac5b0c2..1b85159b02 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
@@ -8,6 +8,13 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Server;
+///
+/// A bunch of hacks to make the existing rendering operations and IDrawingContext
+/// to work with composition rendering infrastructure.
+/// 1) Keeps and applies the transform of the current visual since drawing operations think that
+/// they have information about the full render transform (they are not)
+/// 2) Keeps the draw list for the VisualBrush contents of the current drawing operation.
+///
internal class CompositorDrawingContextProxy : IDrawingContextImpl
{
private IDrawingContextImpl _impl;
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs b/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs
index a60084d8f3..a09de2c0ff 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs
@@ -8,6 +8,9 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Server;
+///
+/// An FPS counter helper that can draw itself on the render thread
+///
internal class FpsCounter
{
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
@@ -17,6 +20,7 @@ internal class FpsCounter
private TimeSpan _lastFpsUpdate;
const int FirstChar = 32;
const int LastChar = 126;
+ // ASCII chars
private GlyphRun[] _runs = new GlyphRun[LastChar - FirstChar + 1];
public FpsCounter(GlyphTypeface typeface)
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs b/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs
index 1971451811..c9592b70ab 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs
@@ -1,5 +1,10 @@
namespace Avalonia.Rendering.Composition.Server
{
+ ///
+ /// A helper class used to manage the current slots for writing data from the render thread
+ /// and reading it from the UI thread.
+ /// Used mostly by hit-testing which needs to know the last transform of the visual
+ ///
internal class ReadbackIndices
{
private readonly object _lock = new object();
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionBrush.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionBrush.cs
deleted file mode 100644
index eb041aaf88..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionBrush.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Avalonia.Rendering.Composition.Server
-{
- internal abstract partial class ServerCompositionBrush : ServerObject
- {
-
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
index 45062632c7..eff1af65e2 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
@@ -9,9 +9,13 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Server;
+///
+/// Server-side counterpart of
+///
internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisual
{
#if DEBUG
+ // This is needed for debugging purposes so we could see inspect the associated visual from debugger
public readonly Visual UiVisual;
#endif
private CompositionDrawList? _renderCommands;
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionGradientBrush.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionGradientBrush.cs
deleted file mode 100644
index 0948b9692f..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionGradientBrush.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-
-namespace Avalonia.Rendering.Composition.Server
-{
- internal abstract partial class ServerCompositionGradientBrush : ServerCompositionBrush
- {
- public ServerCompositionGradientStopCollection Stops { get; }
- public ServerCompositionGradientBrush(ServerCompositor compositor) : base(compositor)
- {
- Stops = new ServerCompositionGradientStopCollection(compositor);
- }
-
- public override long LastChangedBy => Math.Max(base.LastChangedBy, (long)Stops.LastChangedBy);
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
index 24a5f0294a..8b903c4382 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
@@ -10,6 +10,10 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Server
{
+ ///
+ /// Server-side counterpart of the
+ /// That's the place where we update visual transforms, track dirty rects and actually do rendering
+ ///
internal partial class ServerCompositionTarget : IDisposable
{
private readonly ServerCompositor _compositor;
@@ -172,6 +176,7 @@ namespace Avalonia.Rendering.Composition.Server
_renderTarget?.Dispose();
_renderTarget = null;
}
+ _compositor.RemoveCompositionTarget(this);
}
public void AddVisual(ServerCompositionVisual visual)
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
index 811fffd8eb..73792fdf98 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
@@ -8,6 +8,12 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition.Server
{
+ ///
+ /// Server-side counterpart of the .
+ /// 1) manages deserialization of changes received from the UI thread
+ /// 2) triggers animation ticks
+ /// 3) asks composition targets to render themselves
+ ///
internal class ServerCompositor : IRenderLoopTask
{
private readonly IRenderLoop _renderLoop;
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs
index bcfcfbe4f2..136ebc1d63 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs
@@ -3,6 +3,11 @@ using Avalonia.Platform;
namespace Avalonia.Rendering.Composition.Server
{
+ ///
+ /// Server-side counterpart of .
+ /// Mostly propagates update and render calls, but is also responsible
+ /// for updating adorners in deferred manner
+ ///
internal partial class ServerCompositionContainerVisual : ServerCompositionVisual
{
public ServerCompositionVisualCollection Children { get; private set; } = null!;
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs
index 4beea4715b..39d6a8dc70 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs
@@ -4,6 +4,10 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition.Server
{
+ ///
+ /// A server-side list container capable of receiving changes from the UI thread
+ /// Right now it's quite dumb since it always receives the full list
+ ///
class ServerList : ServerObject where T : ServerObject
{
public List List { get; } = new List();
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs
index f55c9439e4..e5ae7fa859 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs
@@ -9,6 +9,10 @@ using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Server
{
+ ///
+ /// Server-side counterpart.
+ /// Is responsible for animation activation and invalidation
+ ///
internal abstract class ServerObject : IExpressionObject
{
public ServerCompositor Compositor { get; }
@@ -92,13 +96,15 @@ namespace Avalonia.Rendering.Composition.Server
public void SubscribeToInvalidation(int member, IAnimationInstance animation)
{
ref var store = ref GetStoreFromOffset(member);
+ if (store.Subscribers == null)
+ store.Subscribers = new();
store.Subscribers.AddRef(animation);
}
public void UnsubscribeFromInvalidation(int member, IAnimationInstance animation)
{
ref var store = ref GetStoreFromOffset(member);
- store.Subscribers.ReleaseRef(animation);
+ store.Subscribers?.ReleaseRef(animation);
}
public virtual int? GetFieldOffset(string fieldName) => null;
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs
deleted file mode 100644
index 5720d80304..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Numerics;
-using Avalonia.Media.Immutable;
-using Avalonia.Platform;
-
-namespace Avalonia.Rendering.Composition.Server
-{
- internal partial class ServerCompositionSolidColorVisual
- {
- protected override void RenderCore(CompositorDrawingContextProxy canvas)
- {
- canvas.DrawRectangle(new ImmutableSolidColorBrush(Color), null, new RoundedRect(new Rect(new Size(Size))));
- base.RenderCore(canvas);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs
deleted file mode 100644
index 2f4c446cfa..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Numerics;
-using Avalonia.Platform;
-
-namespace Avalonia.Rendering.Composition.Server
-{
- internal partial class ServerCompositionSpriteVisual
- {
-
- protected override void RenderCore(CompositorDrawingContextProxy canvas)
- {
- if (Brush != null)
- {
- //SetTransform(canvas, transform);
- //canvas.FillRect((Vector2)Size, (ICbBrush)Brush.Brush!);
- }
-
- base.RenderCore(canvas);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs
index d42bcae7e7..0c58647319 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs
@@ -4,7 +4,13 @@ using Avalonia.Rendering.Composition.Transport;
namespace Avalonia.Rendering.Composition.Server
{
- unsafe partial class ServerCompositionVisual : ServerObject
+ ///
+ /// Server-side counterpart.
+ /// Is responsible for computing the transformation matrix, for applying various visual
+ /// properties before calling visual-specific drawing code and for notifying the
+ /// for new dirty rects
+ ///
+ partial class ServerCompositionVisual : ServerObject
{
private bool _isDirty;
private bool _isBackface;
@@ -51,7 +57,10 @@ namespace Avalonia.Rendering.Composition.Server
private ReadbackData _readback0, _readback1, _readback2;
-
+ ///
+ /// Obtains "readback" data - the data that is sent from the render thread to the UI thread
+ /// in non-blocking manner. Used mostly by hit-testing
+ ///
public ref ReadbackData GetReadback(int idx)
{
if (idx == 0)
@@ -119,6 +128,9 @@ namespace Avalonia.Rendering.Composition.Server
}
+ ///
+ /// Data that can be read from the UI thread
+ ///
public struct ReadbackData
{
public Matrix4x4 Matrix;
@@ -126,7 +138,6 @@ namespace Avalonia.Rendering.Composition.Server
public long TargetId;
public bool Visible;
}
-
partial void DeserializeChangesExtra(BatchStreamReader c)
{
diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs b/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs
index 0714db5781..e69768d3bf 100644
--- a/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
namespace Avalonia.Rendering.Composition.Transport
{
+ ///
+ /// Represents a group of serialized changes from the UI thread to be atomically applied at the render thread
+ ///
internal class Batch
{
private static long _nextSequenceId = 1;
diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs
index 9e9ed739fb..65237473fb 100644
--- a/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs
@@ -7,6 +7,12 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Transport;
+///
+/// The batch data is separated into 2 "streams":
+/// - objects: CLR reference types that are references to either server-side or common objects
+/// - structs: blittable types like int, Matrix, Color
+/// Each "stream" consists of memory segments that are pooled
+///
internal class BatchStreamData
{
public Queue> Objects { get; } = new();
diff --git a/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs b/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs
index 2399bd71d7..e295c3c2c8 100644
--- a/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs
@@ -4,6 +4,11 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition.Transport
{
+ ///
+ /// A helper class used from generated UI-thread-side collections of composition objects.
+ ///
+ // NOTE: This should probably be a base class since TServer isn't used anymore and it was the reason why
+ // it couldn't be exposed as a base class
class ServerListProxyHelper : IList
where TServer : ServerObject
where TClient : CompositionObject
diff --git a/src/Avalonia.Base/Rendering/Composition/Utils/MathExt.cs b/src/Avalonia.Base/Rendering/Composition/Utils/MathExt.cs
deleted file mode 100644
index 0be19a8e9d..0000000000
--- a/src/Avalonia.Base/Rendering/Composition/Utils/MathExt.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-
-namespace Avalonia.Rendering.Composition.Utils
-{
- static class MathExt
- {
- public static float Clamp(float value, float min, float max)
- {
- var amax = Math.Max(min, max);
- var amin = Math.Min(min, max);
- return Math.Min(Math.Max(value, amin), amax);
- }
-
- public static double Clamp(double value, double min, double max)
- {
- var amax = Math.Max(min, max);
- var amin = Math.Min(min, max);
- return Math.Min(Math.Max(value, amin), amax);
- }
-
-
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Rendering/Composition/Visual.cs b/src/Avalonia.Base/Rendering/Composition/Visual.cs
index f092029457..f9e1eae2ab 100644
--- a/src/Avalonia.Base/Rendering/Composition/Visual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Visual.cs
@@ -5,6 +5,9 @@ using Avalonia.VisualTree;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// The base visual object in the composition visual hierarchy.
+ ///
public abstract partial class CompositionVisual
{
private IBrush? _opacityMask;
diff --git a/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs b/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs
index 42226a8b4d..60ebd9271c 100644
--- a/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs
+++ b/src/Avalonia.Base/Rendering/Composition/VisualCollection.cs
@@ -3,6 +3,9 @@ using Avalonia.Rendering.Composition.Server;
namespace Avalonia.Rendering.Composition
{
+ ///
+ /// A collection of CompositionVisual objects
+ ///
public partial class CompositionVisualCollection : CompositionObject
{
private CompositionVisual _owner;
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index 596cbf1d7e..3d5be806e1 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -251,6 +251,20 @@ namespace Avalonia.Utilities
return val;
}
}
+
+ ///
+ /// Clamps a value between a minimum and maximum value.
+ ///
+ /// The value.
+ /// The minimum value.
+ /// The maximum value.
+ /// The clamped value.
+ public static float Clamp(float value, float min, float max)
+ {
+ var amax = Math.Max(min, max);
+ var amin = Math.Min(min, max);
+ return Math.Min(Math.Max(value, amin), amax);
+ }
///
/// Clamps a value between a minimum and maximum value.
diff --git a/src/Avalonia.Base/Utilities/RefTrackingDictionary.cs b/src/Avalonia.Base/Utilities/RefTrackingDictionary.cs
index 71305a8305..9400e37f21 100644
--- a/src/Avalonia.Base/Utilities/RefTrackingDictionary.cs
+++ b/src/Avalonia.Base/Utilities/RefTrackingDictionary.cs
@@ -5,6 +5,9 @@ using System.Runtime.InteropServices;
namespace Avalonia.Utilities;
+///
+/// Maintains a set of objects with reference counts
+///
internal class RefTrackingDictionary : Dictionary where TKey : class
{
///
diff --git a/src/Avalonia.Base/composition-schema.xml b/src/Avalonia.Base/composition-schema.xml
index 2b555359c6..e0e177da44 100644
--- a/src/Avalonia.Base/composition-schema.xml
+++ b/src/Avalonia.Base/composition-schema.xml
@@ -7,7 +7,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
index 297eef9e80..a88bfc3651 100644
--- a/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
+++ b/src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
@@ -8,6 +8,9 @@ using Avalonia.Controls;
namespace Avalonia.Markup.Parsers
{
+ ///
+ /// Parser for composition expressions
+ ///
internal class ExpressionParser
{
private readonly bool _enableValidation;
diff --git a/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs b/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs
index 314ac1acbf..7ad40f68e4 100644
--- a/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs
+++ b/src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs
@@ -34,7 +34,7 @@ namespace Avalonia.Rendering.Composition
private KeyFrames<{a.Type}> _keyFrames = new KeyFrames<{a.Type}>();
private protected override IKeyFrames KeyFrames => _keyFrames;
- public void InsertKeyFrame(float normalizedProgressKey, {a.Type} value, CompositionEasingFunction easingFunction)
+ public void InsertKeyFrame(float normalizedProgressKey, {a.Type} value, Avalonia.Animation.Easings.IEasing easingFunction)
{{
_keyFrames.Insert(normalizedProgressKey, value, easingFunction);
}}