Browse Source

Some docs and refactorings

Nikita Tsukanov 3 years ago
parent
commit
27e87857af
60 changed files with 565 additions and 417 deletions
  1. 3 3
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  2. 6 2
      src/Avalonia.Base/Animation/Easings/CubicBezier.cs
  3. 29 0
      src/Avalonia.Base/Animation/Easings/CubicBezierEasing.cs
  4. 5 1
      src/Avalonia.Base/Avalonia.Base.csproj
  5. 16 4
      src/Avalonia.Base/Rendering/Composition/Animations/AnimatedValueStore.cs
  6. 5 0
      src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs
  7. 62 47
      src/Avalonia.Base/Rendering/Composition/Animations/CompositionAnimation.cs
  8. 19 0
      src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs
  9. 4 0
      src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs
  10. 3 0
      src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs
  11. 11 0
      src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs
  12. 3 0
      src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs
  13. 96 15
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimation.cs
  14. 10 6
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrameAnimationInstance.cs
  15. 18 9
      src/Avalonia.Base/Rendering/Composition/Animations/KeyFrames.cs
  16. 3 0
      src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs
  17. 24 5
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  18. 11 0
      src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs
  19. 0 95
      src/Avalonia.Base/Rendering/Composition/CompositionEasingFunction.cs
  20. 0 16
      src/Avalonia.Base/Rendering/Composition/CompositionGradientBrush.cs
  21. 20 1
      src/Avalonia.Base/Rendering/Composition/CompositionObject.cs
  22. 9 0
      src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs
  23. 19 0
      src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
  24. 44 56
      src/Avalonia.Base/Rendering/Composition/Compositor.cs
  25. 0 20
      src/Avalonia.Base/Rendering/Composition/CompositorRenderLoopTask.cs
  26. 3 0
      src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs
  27. 6 0
      src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs
  28. 3 0
      src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs
  29. 9 1
      src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs
  30. 10 7
      src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs
  31. 3 0
      src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs
  32. 3 0
      src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs
  33. 3 0
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs
  34. 3 0
      src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs
  35. 0 9
      src/Avalonia.Base/Rendering/Composition/ICompositionSurface.cs
  36. 7 0
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
  37. 4 0
      src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs
  38. 5 0
      src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs
  39. 0 7
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionBrush.cs
  40. 4 0
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
  41. 0 15
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionGradientBrush.cs
  42. 5 0
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  43. 6 0
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
  44. 5 0
      src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs
  45. 4 0
      src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs
  46. 7 1
      src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs
  47. 0 15
      src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs
  48. 0 20
      src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs
  49. 14 3
      src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs
  50. 3 0
      src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs
  51. 6 0
      src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs
  52. 5 0
      src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs
  53. 0 23
      src/Avalonia.Base/Rendering/Composition/Utils/MathExt.cs
  54. 3 0
      src/Avalonia.Base/Rendering/Composition/Visual.cs
  55. 3 0
      src/Avalonia.Base/Rendering/Composition/VisualCollection.cs
  56. 14 0
      src/Avalonia.Base/Utilities/MathUtilities.cs
  57. 3 0
      src/Avalonia.Base/Utilities/RefTrackingDictionary.cs
  58. 0 35
      src/Avalonia.Base/composition-schema.xml
  59. 3 0
      src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs
  60. 1 1
      src/tools/DevGenerators/CompositionGenerator/Generator.KeyFrameAnimation.cs

+ 3 - 3
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;
     }
 

+ 6 - 2
src/Avalonia.Base/Rendering/Composition/Utils/CubicBezier.cs → 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
 {
+    /// <summary>
+    /// Represents a cubic bezier curve and can compute Y coordinate for a given X
+    /// </summary>
     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);

+ 29 - 0
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);
+    }
+}

+ 5 - 1
src/Avalonia.Base/Avalonia.Base.csproj

@@ -35,6 +35,10 @@
     <InternalsVisibleTo Include="Avalonia.Skia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
     <InternalsVisibleTo Include="Avalonia.Web.Blazor, PublicKey=$(AvaloniaPublicKey)" />
-    <InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7"/>
+    <InternalsVisibleTo Include="DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Rendering\Composition\Utils" />
   </ItemGroup>
 </Project>

+ 16 - 4
src/Avalonia.Base/Rendering/Composition/Animations/AnimatedValueStore.cs

@@ -7,10 +7,15 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    /// <summary>
+    /// This is the first element of both animated and non-animated value stores.
+    /// It's used to propagate property invalidation to subscribers 
+    /// </summary>
+    
     internal struct ServerObjectSubscriptionStore
     {
         public bool IsValid;
-        public RefTrackingDictionary<IAnimationInstance> Subscribers;
+        public RefTrackingDictionary<IAnimationInstance>? Subscribers;
 
         public void Invalidate()
         {
@@ -23,6 +28,10 @@ namespace Avalonia.Rendering.Composition.Animations
         }
     }
 
+    /// <summary>
+    /// The value store for non-animated values that can still be referenced by animations.
+    /// Simply stores the value and notifies subscribers
+    /// </summary>
     [StructLayout(LayoutKind.Sequential)]
     internal struct ServerValueStore<T>
     {
@@ -43,7 +52,12 @@ namespace Avalonia.Rendering.Composition.Animations
             }
         }
     }
-
+    
+    /// <summary>
+    /// 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 
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
     [StructLayout(LayoutKind.Sequential)]
     internal struct ServerAnimatedValueStore<T> 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;

+ 5 - 0
src/Avalonia.Base/Rendering/Composition/Animations/AnimationInstanceBase.cs

@@ -5,6 +5,11 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Animations;
 
+
+/// <summary>
+/// The base class for both key-frame and expression animation instances
+/// Is responsible for activation tracking and for subscribing to properties used in dependencies
+/// </summary>
 internal abstract class AnimationInstanceBase : IAnimationInstance
 {
     private List<(ServerObject obj, int member)>? _trackedObjects;

+ 62 - 47
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()
-          {
-              
-          }
-      }
+    /// <summary>
+    /// This is the base class for ExpressionAnimation and KeyFrameAnimation.
+    /// </summary>
+    /// <remarks>
+    /// Use the <see cref="CompositionObject.StartAnimation"/> method to start the animation.
+    /// Value parameters (as opposed to reference parameters which are set using <see cref="SetReferenceParameter"/>)
+    /// are copied and "embedded" into an expression at the time CompositionObject.StartAnimation is called.
+    /// Changing the value of the variable after <see cref="CompositionObject.StartAnimation"/> is called will not affect
+    /// the value of the ExpressionAnimation.
+    /// See the remarks section of ExpressionAnimation for additional information.
+    /// </remarks>
+    public abstract class CompositionAnimation : CompositionObject,  ICompositionAnimationBase
+    {
+        private readonly CompositionPropertySet _propertySet;
+        internal CompositionAnimation(Compositor compositor) : base(compositor, null!)
+        {
+            _propertySet = new CompositionPropertySet(compositor);
+        }
+        
+        /// <summary>
+        /// Clears all of the parameters of the animation.
+        /// </summary>
+        public void ClearAllParameters() => _propertySet.ClearAll();
+
+        /// <summary>
+        /// Clears a parameter from the animation.
+        /// </summary>
+        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()
+        {
+            
+        }
+    }
 }

+ 19 - 0
src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimation.cs

@@ -5,6 +5,17 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    /// <summary>
+    /// A Composition Animation that uses a mathematical equation to calculate the value for an animating property every frame.
+    /// </summary>
+    /// <remarks>
+    /// 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 <see cref="KeyFrameAnimation"/>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 <see cref="CompositionObject.StartAnimation"/> method to start the animation.
+    /// </remarks>
     public class ExpressionAnimation : CompositionAnimation
     {
         private string? _expression;
@@ -14,6 +25,14 @@ namespace Avalonia.Rendering.Composition.Animations
         {
         }
 
+        /// <summary>
+        /// The mathematical equation specifying how the animated value is calculated each frame.
+        /// The Expression is the core of an <see cref="ExpressionAnimation"/> 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.
+        /// </summary>
         public string? Expression
         {
             get => _expression;

+ 4 - 0
src/Avalonia.Base/Rendering/Composition/Animations/ExpressionAnimationInstance.cs

@@ -5,6 +5,10 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    
+    /// <summary>
+    /// Server-side counterpart of <see cref="ExpressionAnimation"/> with values baked-in.
+    /// </summary>
     internal class ExpressionAnimationInstance : AnimationInstanceBase, IAnimationInstance
     {
         private readonly Expression _expression;

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Animations/ICompositionAnimationBase.cs

@@ -4,6 +4,9 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    /// <summary>
+    /// Base class for composition animations.
+    /// </summary>
     public interface ICompositionAnimationBase
     {
         internal void InternalOnly();

+ 11 - 0
src/Avalonia.Base/Rendering/Composition/Animations/ImplicitAnimationCollection.cs

@@ -6,6 +6,17 @@ using Avalonia.Rendering.Composition.Transport;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    /// <summary>
+    /// A collection of animations triggered when a condition is met.
+    /// </summary>
+    /// <remarks>
+    /// 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 
+    /// </remarks>
     public class ImplicitAnimationCollection : CompositionObject, IDictionary<string, ICompositionAnimationBase>
     {
         private Dictionary<string, ICompositionAnimationBase> _inner = new Dictionary<string, ICompositionAnimationBase>();

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs

@@ -3,6 +3,9 @@ using System.Numerics;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    /// <summary>
+    ///  An interface to define interpolation logic for a particular type
+    /// </summary>
     internal interface IInterpolator<T>
     {
         T Interpolate(T from, T to, float progress);

+ 96 - 15
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
 {
+    
+    /// <summary>
+    /// 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.
+    /// </summary>
     public abstract class KeyFrameAnimation : CompositionAnimation
     {
+        private TimeSpan _duration = TimeSpan.FromMilliseconds(1);
+
         internal KeyFrameAnimation(Compositor compositor) : base(compositor)
         {
         }
         
+        /// <summary>
+        /// The delay behavior of the key frame animation.
+        /// </summary>
         public AnimationDelayBehavior DelayBehavior { get; set; }
+        
+        /// <summary>
+        /// Delay before the animation starts after <see cref="CompositionObject.StartAnimation"/> is called.
+        /// </summary>
         public System.TimeSpan DelayTime { get; set; }
-        public AnimationDirection Direction { get; set; }
-        public System.TimeSpan Duration { get; set; }
+        
+        /// <summary>
+        /// 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 <see cref="IterationCount"/> greater than one.
+        /// This gives an easy way for customizing animation definitions.
+        /// </summary>
+        public PlaybackDirection Direction { get; set; }
+
+        /// <summary>
+        /// The duration of the animation.
+        /// Minimum allowed value is 1ms and maximum allowed value is 24 days.
+        /// </summary>
+        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;
+            }
+        }
+        
+        /// <summary>
+        /// The iteration behavior for the key frame animation.
+        /// </summary>
         public AnimationIterationBehavior IterationBehavior { get; set; }
+        
+        /// <summary>
+        /// The number of times to repeat the key frame animation.
+        /// </summary>
         public int IterationCount { get; set; } = 1;
+        
+        /// <summary>
+        /// Specifies how to set the property value when animation is stopped
+        /// </summary>
         public AnimationStopBehavior StopBehavior { get; set; }
         
         private protected abstract IKeyFrames KeyFrames { get; }
         
+        /// <summary>
+        /// Inserts an expression keyframe.
+        /// </summary>
+        /// <param name="normalizedProgressKey">
+        /// 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.
+        /// </param>
+        /// <param name="value">The expression used to calculate the value of the key frame.</param>
+        /// <param name="easingFunction">The easing function to use when interpolating between frames.</param>
         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);
     }
 
+    /// <summary>
+    /// Specifies the animation delay behavior.
+    /// </summary>
     public enum AnimationDelayBehavior
     {
+        /// <summary>
+        /// 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.
+        /// </summary>
         SetInitialValueAfterDelay,
+        /// <summary>
+        /// 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.
+        /// </summary>
         SetInitialValueBeforeDelay
     }
 
-    public enum AnimationDirection
-    {
-        Normal,
-        Reverse,
-        Alternate,
-        AlternateReverse
-    }
-
+    /// <summary>
+    /// Specifies if the animation should loop.
+    /// </summary>
     public enum AnimationIterationBehavior
     {
+        /// <summary>
+        /// The animation should loop the specified number of times.
+        /// </summary>
         Count,
+        /// <summary>
+        /// The animation should loop forever.
+        /// </summary>
         Forever
     }
 
+    /// <summary>
+    /// Specifies the behavior of an animation when it stops.
+    /// </summary>
     public enum AnimationStopBehavior
     {
+        /// <summary>
+        /// Leave the animation at its current value.
+        /// </summary>
         LeaveCurrentValue,
+        /// <summary>
+        /// Reset the animation to its initial value.
+        /// </summary>
         SetToInitialValue,
+        /// <summary>
+        /// Set the animation to its final value.
+        /// </summary>
         SetToFinalValue
     }
 }

+ 10 - 6
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
 {
+    /// <summary>
+    /// Server-side counterpart of KeyFrameAnimation with values baked-in
+    /// </summary>
     class KeyFrameAnimationInstance<T> : AnimationInstanceBase, IAnimationInstance where T : struct
     {
         private readonly IInterpolator<T> _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;
             

+ 18 - 9
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
 {
+    
+    /// <summary>
+    /// Collection of composition animation key frames
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
     class KeyFrames<T> : List<KeyFrame<T>>, 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<T>
@@ -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<T>
@@ -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
         }
     }
 
+    /// <summary>
+    /// Composition animation key frame
+    /// </summary>
     struct KeyFrame<T>
     {
         public float NormalizedProgressKey;
         public T Value;
         public Expression Expression;
-        public CompositionEasingFunction EasingFunction;
+        public IEasing EasingFunction;
     }
     
+    /// <summary>
+    /// Server-side composition animation key frame
+    /// </summary>
     struct ServerKeyFrame<T>
     {
         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);
     }
 }

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Animations/PropertySetSnapshot.cs

@@ -3,6 +3,9 @@ using Avalonia.Rendering.Composition.Expressions;
 
 namespace Avalonia.Rendering.Composition.Animations
 {
+    /// <summary>
+    /// A snapshot of properties used by an animation
+    /// </summary>
     internal class PropertySetSnapshot : IExpressionParameterCollection, IExpressionObject
     {
         private readonly Dictionary<string, Value> _dic;

+ 24 - 5
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@@ -13,7 +13,10 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.Composition;
 
-public class CompositingRenderer : RendererBase, IRendererWithCompositor
+/// <summary>
+/// A renderer that utilizes <see cref="Avalonia.Rendering.Composition.Compositor"/> to render the visual tree 
+/// </summary>
+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;
 
     /// <summary>
-    /// 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.
     /// </summary>
     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;
     }
 
+    /// <inheritdoc/>
     public bool DrawFps
     {
         get => _target.DrawFps;
         set => _target.DrawFps = value;
     }
-
+    
+    /// <inheritdoc/>
     public bool DrawDirtyRects
     {
         get => _target.DrawDirtyRects;
         set => _target.DrawDirtyRects = value;
     }
 
+    /// <inheritdoc/>
     public event EventHandler<SceneInvalidatedEventArgs>? SceneInvalidated;
 
     void QueueUpdate()
@@ -62,12 +70,15 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
         _queuedUpdate = true;
         Dispatcher.UIThread.Post(_update, DispatcherPriority.Composition);
     }
+    
+    /// <inheritdoc/>
     public void AddDirty(IVisual visual)
     {
         _dirty.Add((Visual)visual);
         QueueUpdate();
     }
 
+    /// <inheritdoc/>
     public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool>? filter)
     {
         var res = _target.TryHitTest(p, filter);
@@ -84,12 +95,14 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor
         }
     }
 
+    /// <inheritdoc/>
     public IVisual? HitTestFirst(Point p, IVisual root, Func<IVisual, bool>? filter)
     {
         // TODO: Optimize
         return HitTest(p, root, filter).FirstOrDefault();
     }
 
+    /// <inheritdoc/>
     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();
     }
 
-
+    /// <summary>
+    /// The associated <see cref="Avalonia.Rendering.Composition.Compositor"/> object
+    /// </summary>
     public Compositor Compositor => _compositor;
 }

+ 11 - 0
src/Avalonia.Base/Rendering/Composition/CompositionDrawListVisual.cs

@@ -7,12 +7,23 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.Composition;
 
+
+/// <summary>
+/// A composition visual that holds a list of drawing commands issued by <see cref="Avalonia.Visual"/>
+/// </summary>
 internal class CompositionDrawListVisual : CompositionContainerVisual
 {
+    /// <summary>
+    /// The associated <see cref="Avalonia.Visual"/>
+    /// </summary>
     public Visual Visual { get; }
 
     private bool _drawListChanged;
     private CompositionDrawList? _drawList;
+    
+    /// <summary>
+    /// The list of drawing commands
+    /// </summary>
     public CompositionDrawList? DrawList
     {
         get => _drawList;

+ 0 - 95
src/Avalonia.Base/Rendering/Composition/CompositionEasingFunction.cs

@@ -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);
-    }
-
-}

+ 0 - 16
src/Avalonia.Base/Rendering/Composition/CompositionGradientBrush.cs

@@ -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; }
-    }
-    
-    
-}

+ 20 - 1
src/Avalonia.Base/Rendering/Composition/CompositionObject.cs

@@ -6,8 +6,16 @@ using Avalonia.Rendering.Composition.Transport;
 
 namespace Avalonia.Rendering.Composition
 {
+    /// <summary>
+    /// 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 <see cref="CompositionVisual" /> objects each representing a single node in a Visual tree.
+    /// </summary>
     public abstract class CompositionObject : IDisposable
     {
+        /// <summary>
+        /// The collection of implicit animations attached to this object.
+        /// </summary>
         public ImplicitAnimationCollection? ImplicitAnimations { get; set; }
         internal CompositionObject(Compositor compositor, ServerObject server)
         {
@@ -15,6 +23,9 @@ namespace Avalonia.Rendering.Composition
             Server = server;
         }
         
+        /// <summary>
+        /// The associated Compositor
+        /// </summary>
         public Compositor Compositor { get; }
         internal ServerObject Server { get; }
         public bool IsDisposed { get; private set; }
@@ -29,14 +40,22 @@ namespace Avalonia.Rendering.Composition
             IsDisposed = true;
         }
 
+        /// <summary>
+        /// Connects an animation with the specified property of the object and starts the animation.
+        /// </summary>
         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);
         }
 
+        /// <summary>
+        /// 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.
+        /// </summary>
         public void StartAnimationGroup(ICompositionAnimationBase grp)
         {
             if (grp is CompositionAnimation animation)

+ 9 - 0
src/Avalonia.Base/Rendering/Composition/CompositionPropertySet.cs

@@ -7,6 +7,15 @@ using Avalonia.Rendering.Composition.Transport;
 
 namespace Avalonia.Rendering.Composition
 {
+    /// <summary>
+    /// <see cref="CompositionPropertySet"/>s are <see cref="CompositionObject"/>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.
+    /// <see cref="CompositionPropertySet"/>s are most commonly used with animations, where they maintain key-value pairs
+    /// that are referenced to drive portions of composition animations. <see cref="CompositionPropertySet"/>s
+    /// provide the ability to insert key-value pairs or retrieve a value for a given key.
+    /// <see cref="CompositionPropertySet"/> does not support a delete function – ensure you use <see cref="CompositionPropertySet"/>
+    /// to store values that will be shared across the application.
+    /// </summary>
     public class CompositionPropertySet : CompositionObject
     {
         private readonly Dictionary<string, ExpressionVariant> _variants = new Dictionary<string, ExpressionVariant>();

+ 19 - 0
src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs

@@ -6,6 +6,9 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.Composition
 {
+    /// <summary>
+    /// Represents the composition output (e. g. a window, embedded control, entire screen)
+    /// </summary>
     public partial class CompositionTarget
     {
         partial void OnRootChanged()
@@ -20,6 +23,12 @@ namespace Avalonia.Rendering.Composition
                 Root.Root = null;
         }
         
+        /// <summary>
+        /// Attempts to perform a hit-tst
+        /// </summary>
+        /// <param name="point"></param>
+        /// <param name="filter"></param>
+        /// <returns></returns>
         public PooledList<CompositionVisual>? TryHitTest(Point point, Func<IVisual, bool>? filter)
         {
             Server.Readback.NextRead();
@@ -30,6 +39,10 @@ namespace Avalonia.Rendering.Composition
             return res;
         }
 
+        /// <summary>
+        /// Attempts to transform a point to a particular CompositionVisual coordinate space
+        /// </summary>
+        /// <returns></returns>
         public Point? TryTransformToVisual(CompositionVisual visual, Point point)
         {
             if (visual.Root != this)
@@ -108,8 +121,14 @@ namespace Avalonia.Rendering.Composition
 
         }
 
+        /// <summary>
+        /// Registers the composition target for explicit redraw
+        /// </summary>
         public void RequestRedraw() => RegisterForSerialization();
 
+        /// <summary>
+        /// Performs composition directly on the UI thread 
+        /// </summary>
         internal void ImmediateUIThreadRender()
         {
             Compositor.RequestCommitAsync();

+ 44 - 56
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
 {
+    /// <summary>
+    /// 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 
+    /// </summary>
     public partial class Compositor
     {
         internal IRenderLoop Loop { get; }
@@ -23,22 +28,38 @@ namespace Avalonia.Rendering.Composition
         private BatchStreamMemoryPool _batchMemoryPool = new();
         private List<CompositionObject> _objectsForSerialization = new();
         internal ServerCompositor Server => _server;
-        internal CompositionEasingFunction DefaultEasing { get; }
-        
+        internal IEasing DefaultEasing { get; }
+        private List<Action>? _invokeOnNextCommit;
+        private readonly Stack<List<Action>> _invokeListPool = new();
+
+        /// <summary>
+        /// Creates a new compositor on a specified render loop that would use a particular GPU
+        /// </summary>
+        /// <param name="loop"></param>
+        /// <param name="gpu"></param>
         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));
         }
 
+        /// <summary>
+        /// Creates a new CompositionTarget
+        /// </summary>
+        /// <param name="renderTargetFactory">A factory method to create IRenderTarget to be called from the render thread</param>
+        /// <returns></returns>
         public CompositionTarget CreateCompositionTarget(Func<IRenderTarget> renderTargetFactory)
         {
             return new CompositionTarget(this, new ServerCompositionTarget(_server, renderTargetFactory));
         }
 
+        /// <summary>
+        /// Requests pending changes in the composition objects to be serialized and sent to the render thread
+        /// </summary>
+        /// <returns>A task that completes when sent changes are applied and rendered on the render thread</returns>
         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<CompositionBitmapSurface> 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);
+        }
     }
 }

+ 0 - 20
src/Avalonia.Base/Rendering/Composition/CompositorRenderLoopTask.cs

@@ -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();
-        }
-    }
-}

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/ContainerVisual.cs

@@ -2,6 +2,9 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition
 {
+    /// <summary>
+    /// A node in the visual tree that can have children.
+    /// </summary>
     public partial class CompositionContainerVisual : CompositionVisual
     {
         public CompositionVisualCollection Children { get; private set; } = null!;

+ 6 - 0
src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawList.cs

@@ -6,6 +6,9 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Drawing;
 
+/// <summary>
+/// A list of serialized drawing commands
+/// </summary>
 internal class CompositionDrawList : PooledList<IRef<IDrawOperation>>
 {
     public Size? Size { get; set; }
@@ -47,6 +50,9 @@ internal class CompositionDrawList : PooledList<IRef<IDrawOperation>>
     }
 }
 
+/// <summary>
+/// An helper class for building <see cref="CompositionDrawList"/>
+/// </summary>
 internal class CompositionDrawListBuilder
 {
     private CompositionDrawList? _operations;

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Drawing/CompositionDrawingContext.cs

@@ -10,6 +10,9 @@ using Avalonia.Utilities;
 using Avalonia.VisualTree;
 namespace Avalonia.Rendering.Composition;
 
+/// <summary>
+/// An IDrawingContextImpl implementation that builds <see cref="CompositionDrawList"/>
+/// </summary>
 internal class CompositionDrawingContext : IDrawingContextImpl
 {
     private CompositionDrawListBuilder _builder = new();

+ 9 - 1
src/Avalonia.Base/Rendering/Composition/ElementCompositionPreview.cs

@@ -1,6 +1,14 @@
 namespace Avalonia.Rendering.Composition;
 
-public static class ElementCompositionPreview
+/// <summary>
+/// Enables access to composition visual objects that back XAML elements in the XAML composition tree.
+/// </summary>
+public static class ElementComposition
 {
+    /// <summary>
+    /// Gets CompositionVisual that backs a Visual
+    /// </summary>
+    /// <param name="visual"></param>
+    /// <returns></returns>
     public static CompositionVisual? GetElementVisual(Visual visual) => visual.CompositionVisual;
 }

+ 10 - 7
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
 {
+    /// <summary>
+    /// Built-in functions for Foreign Function Interface available from composition animation expressions
+    /// </summary>
     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)
                     )
                 },
 

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs

@@ -7,6 +7,9 @@ using Avalonia.Media;
 
 namespace Avalonia.Rendering.Composition.Expressions
 {
+    /// <summary>
+    /// Foreign function interface for composition animations based on calling delegates
+    /// </summary>
     internal class DelegateExpressionFfi : IExpressionForeignFunctionInterface, IEnumerable
     {
         struct FfiRecord

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Expressions/Expression.cs

@@ -6,6 +6,9 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Expressions
 {
+    /// <summary>
+    /// A parsed composition expression
+    /// </summary>
     internal abstract class Expression
     {
         public abstract ExpressionType Type { get; }

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs

@@ -22,6 +22,9 @@ namespace Avalonia.Rendering.Composition.Expressions
         Color
     }
 
+    /// <summary>
+    /// A VARIANT type used in expression animations. Can represent multiple value types
+    /// </summary>
     [StructLayout(LayoutKind.Explicit)]
     internal struct ExpressionVariant
     {

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Expressions/TokenParser.cs

@@ -3,6 +3,9 @@ using System.Globalization;
 
 namespace Avalonia.Rendering.Composition.Expressions
 {
+    /// <summary>
+    /// Helper class for composition expression parser
+    /// </summary>
     internal ref struct TokenParser
     {
         private ReadOnlySpan<char> _s;

+ 0 - 9
src/Avalonia.Base/Rendering/Composition/ICompositionSurface.cs

@@ -1,9 +0,0 @@
-using Avalonia.Rendering.Composition.Server;
-
-namespace Avalonia.Rendering.Composition
-{
-    public interface ICompositionSurface
-    {
-        internal ServerCompositionSurface Server { get; }
-    }
-}

+ 7 - 0
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@@ -8,6 +8,13 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Server;
 
+/// <summary>
+/// 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.
+/// </summary>
 internal class CompositorDrawingContextProxy : IDrawingContextImpl
 {
     private IDrawingContextImpl _impl;

+ 4 - 0
src/Avalonia.Base/Rendering/Composition/Server/FpsCounter.cs

@@ -8,6 +8,9 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Server;
 
+/// <summary>
+/// An FPS counter helper that can draw itself on the render thread
+/// </summary>
 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)

+ 5 - 0
src/Avalonia.Base/Rendering/Composition/Server/ReadbackIndices.cs

@@ -1,5 +1,10 @@
 namespace Avalonia.Rendering.Composition.Server
 {
+    /// <summary>
+    /// 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
+    /// </summary>
     internal class ReadbackIndices
     {
         private readonly object _lock = new object();

+ 0 - 7
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionBrush.cs

@@ -1,7 +0,0 @@
-namespace Avalonia.Rendering.Composition.Server
-{
-    internal abstract partial class ServerCompositionBrush : ServerObject
-    {
-
-    }
-}

+ 4 - 0
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs

@@ -9,9 +9,13 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Server;
 
+/// <summary>
+/// Server-side counterpart of <see cref="CompositionDrawListVisual"/>
+/// </summary>
 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;

+ 0 - 15
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionGradientBrush.cs

@@ -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);
-    }
-}

+ 5 - 0
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@@ -10,6 +10,10 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Server
 {
+    /// <summary>
+    /// Server-side counterpart of the <see cref="CompositionTarget"/>
+    /// That's the place where we update visual transforms, track dirty rects and actually do rendering
+    /// </summary>
     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)

+ 6 - 0
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs

@@ -8,6 +8,12 @@ using Avalonia.Rendering.Composition.Transport;
 
 namespace Avalonia.Rendering.Composition.Server
 {
+    /// <summary>
+    /// Server-side counterpart of the <see cref="Compositor"/>.
+    /// 1) manages deserialization of changes received from the UI thread
+    /// 2) triggers animation ticks
+    /// 3) asks composition targets to render themselves
+    /// </summary>
     internal class ServerCompositor : IRenderLoopTask
     {
         private readonly IRenderLoop _renderLoop;

+ 5 - 0
src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs

@@ -3,6 +3,11 @@ using Avalonia.Platform;
 
 namespace Avalonia.Rendering.Composition.Server
 {
+    /// <summary>
+    /// Server-side counterpart of <see cref="CompositionContainerVisual"/>.
+    /// Mostly propagates update and render calls, but is also responsible
+    /// for updating adorners in deferred manner
+    /// </summary>
     internal partial class ServerCompositionContainerVisual : ServerCompositionVisual
     {
         public ServerCompositionVisualCollection Children { get; private set; } = null!;

+ 4 - 0
src/Avalonia.Base/Rendering/Composition/Server/ServerList.cs

@@ -4,6 +4,10 @@ using Avalonia.Rendering.Composition.Transport;
 
 namespace Avalonia.Rendering.Composition.Server
 {
+    /// <summary>
+    /// 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
+    /// </summary>
     class ServerList<T> : ServerObject where T : ServerObject
     {
         public List<T> List { get; } = new List<T>();

+ 7 - 1
src/Avalonia.Base/Rendering/Composition/Server/ServerObject.cs

@@ -9,6 +9,10 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.Composition.Server
 {
+    /// <summary>
+    /// Server-side <see cref="CompositionObject" /> counterpart.
+    /// Is responsible for animation activation and invalidation
+    /// </summary>
     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;

+ 0 - 15
src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs

@@ -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);
-        }
-    }
-}

+ 0 - 20
src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs

@@ -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);
-        }
-    }
-}

+ 14 - 3
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
+    /// <summary>
+    /// Server-side <see cref="CompositionVisual"/> counterpart.
+    /// Is responsible for computing the transformation matrix, for applying various visual
+    /// properties before calling visual-specific drawing code and for notifying the
+    /// <see cref="ServerCompositionTarget"/> for new dirty rects
+    /// </summary>
+    partial class ServerCompositionVisual : ServerObject
     {
         private bool _isDirty;
         private bool _isBackface;
@@ -51,7 +57,10 @@ namespace Avalonia.Rendering.Composition.Server
         
         private ReadbackData _readback0, _readback1, _readback2;
 
-
+        /// <summary>
+        /// 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
+        /// </summary>
         public ref ReadbackData GetReadback(int idx)
         {
             if (idx == 0)
@@ -119,6 +128,9 @@ namespace Avalonia.Rendering.Composition.Server
 
         }
         
+        /// <summary>
+        /// Data that can be read from the UI thread
+        /// </summary>
         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)
         {

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Transport/Batch.cs

@@ -6,6 +6,9 @@ using System.Threading.Tasks;
 
 namespace Avalonia.Rendering.Composition.Transport
 {
+    /// <summary>
+    /// Represents a group of serialized changes from the UI thread to be atomically applied at the render thread
+    /// </summary>
     internal class Batch
     {
         private static long _nextSequenceId = 1;

+ 6 - 0
src/Avalonia.Base/Rendering/Composition/Transport/BatchStream.cs

@@ -7,6 +7,12 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Transport;
 
+/// <summary>
+/// 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 
+/// </summary>
 internal class BatchStreamData
 {
     public Queue<BatchStreamSegment<object?[]>> Objects { get; } = new();

+ 5 - 0
src/Avalonia.Base/Rendering/Composition/Transport/ServerListProxyHelper.cs

@@ -4,6 +4,11 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition.Transport
 {
+    /// <summary>
+    /// A helper class used from generated UI-thread-side collections of composition objects.
+    /// </summary>
+    // 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<TClient, TServer> : IList<TClient>
         where TServer : ServerObject
         where TClient : CompositionObject

+ 0 - 23
src/Avalonia.Base/Rendering/Composition/Utils/MathExt.cs

@@ -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);
-        }
-
-
-    }
-}

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/Visual.cs

@@ -5,6 +5,9 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.Composition
 {
+    /// <summary>
+    /// The base visual object in the composition visual hierarchy.
+    /// </summary>
     public abstract partial class CompositionVisual
     {
         private IBrush? _opacityMask;

+ 3 - 0
src/Avalonia.Base/Rendering/Composition/VisualCollection.cs

@@ -3,6 +3,9 @@ using Avalonia.Rendering.Composition.Server;
 
 namespace Avalonia.Rendering.Composition
 {
+    /// <summary>
+    /// A collection of CompositionVisual objects
+    /// </summary>
     public partial class CompositionVisualCollection : CompositionObject
     {
         private CompositionVisual _owner;

+ 14 - 0
src/Avalonia.Base/Utilities/MathUtilities.cs

@@ -251,6 +251,20 @@ namespace Avalonia.Utilities
                 return val;
             }
         }
+        
+        /// <summary>
+        /// Clamps a value between a minimum and maximum value.
+        /// </summary>
+        /// <param name="val">The value.</param>
+        /// <param name="min">The minimum value.</param>
+        /// <param name="max">The maximum value.</param>
+        /// <returns>The clamped value.</returns>
+        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);
+        }
 
         /// <summary>
         /// Clamps a value between a minimum and maximum value.

+ 3 - 0
src/Avalonia.Base/Utilities/RefTrackingDictionary.cs

@@ -5,6 +5,9 @@ using System.Runtime.InteropServices;
 
 namespace Avalonia.Utilities;
 
+/// <summary>
+/// Maintains a set of objects with reference counts
+/// </summary>
 internal class RefTrackingDictionary<TKey> : Dictionary<TKey, int> where TKey : class
 {
     /// <summary>

+ 0 - 35
src/Avalonia.Base/composition-schema.xml

@@ -7,7 +7,6 @@
     
     <Manual Name="Avalonia.Platform.IGeometryImpl" Passthrough="true"/>
     <Manual Name="Avalonia.Media.IBrush" Passthrough="true"/>
-    <Manual Name="ICompositionSurface" ServerName="ServerCompositionSurface" />
     <Object Name="CompositionVisual" Abstract="true">
         <Property Name="Root" Type="CompositionTarget?" InternalSet="true" />
         <Property Name="Parent" Type="CompositionVisual?" InternalSet="true"  />
@@ -37,40 +36,6 @@
         <Property Name="Scaling" Type="double"/>
         <Property Name="Size" Type="Size" />
     </Object>
-    
-    <Object Name="CompositionSolidColorVisual" Inherits="CompositionContainerVisual" ChangesBase="CompositionVisual">
-        <Property Name="Color" Type="Avalonia.Media.Color" Animated="true"/>
-    </Object>
-    
-    <Object Name="CompositionSpriteVisual" Inherits="CompositionContainerVisual" ChangesBase="CompositionVisual">
-        <Property Name="Brush" Type="CompositionBrush?"/>
-    </Object>
-    
-    <Object Name="CompositionBrush" Abstract="true">
-        
-    </Object>
-        
-    <Object Name="CompositionColorGradientStop">
-        <Property Name="Color" Type="Avalonia.Media.Color" Animated="true"/>
-        <Property Name="Offset" Type="float" Animated="true"/>
-    </Object>
-    <List Name="CompositionGradientStopCollection" ItemType="CompositionColorGradientStop" />
-    <Brush Name="CompositionGradientBrush" Abstract="true" CustomCtor="true" CustomServerCtor="true">
-        <Property Name="ExtendMode" Type="CompositionGradientExtendMode"/>
-    </Brush>
-    <Brush Name="CompositionLinearGradientBrush" Inherits="CompositionGradientBrush" CustomUpdate="true">
-        <Property Name="StartPoint" Type="Vector2" Animated="true"/>
-        <Property Name="EndPoint" Type="Vector2" Animated="true"/>
-    </Brush>
-    <Brush Name="CompositionColorBrush">
-        <Property Name="Color" Type="Avalonia.Media.Color" Animated="true"/>
-    </Brush>
-    <Brush Name="CompositionSurfaceBrush">
-        <Property Name="Surface" Type="ICompositionSurface?"/>
-        <Property Name="Stretch" Type="CompositionStretch" DefaultValue="CompositionStretch.Fill" />
-        <Property Name="TileMode" Type="CompositionTileMode" />
-    </Brush>
-    
     <KeyFrameAnimation Name="Scalar" Type="float"/>
     <KeyFrameAnimation Name="Boolean" Type="bool"/>
     <KeyFrameAnimation Name="Color" Type="Avalonia.Media.Color"/>

+ 3 - 0
src/Markup/Avalonia.Markup/Markup/Parsers/ExpressionParser.cs

@@ -8,6 +8,9 @@ using Avalonia.Controls;
 
 namespace Avalonia.Markup.Parsers
 {
+    /// <summary>
+    /// Parser for composition expressions
+    /// </summary>
     internal class ExpressionParser
     {
         private readonly bool _enableValidation;

+ 1 - 1
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);
         }}