From cb9f1bc9bd2b709e080f72fcd3517ae51799270b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 15:26:40 +0200 Subject: [PATCH 01/23] Add Transform property for Brush class --- src/Avalonia.Visuals/Media/Brush.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/Brush.cs b/src/Avalonia.Visuals/Media/Brush.cs index cf7f5f531c1..fe0dc63297a 100644 --- a/src/Avalonia.Visuals/Media/Brush.cs +++ b/src/Avalonia.Visuals/Media/Brush.cs @@ -18,13 +18,19 @@ public abstract class Brush : Animatable, IMutableBrush public static readonly StyledProperty OpacityProperty = AvaloniaProperty.Register(nameof(Opacity), 1.0); + /// + /// Defines the property. + /// + public static readonly StyledProperty TransformProperty = + AvaloniaProperty.Register(nameof(Transform)); + /// public event EventHandler Invalidated; static Brush() { Animation.Animation.RegisterAnimator(prop => typeof(IBrush).IsAssignableFrom(prop.PropertyType)); - AffectsRender(OpacityProperty); + AffectsRender(OpacityProperty, TransformProperty); } /// @@ -36,6 +42,15 @@ public double Opacity set { SetValue(OpacityProperty, value); } } + /// + /// Gets or sets the transform of the brush. + /// + public Transform Transform + { + get { return GetValue(TransformProperty); } + set { SetValue(TransformProperty, value); } + } + /// /// Parses a brush string. /// From 4cea7a703fec2ed746e0007cadf0aa4ebdb73fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 18:11:48 +0200 Subject: [PATCH 02/23] Add Transform property to IBrush interface --- src/Avalonia.Visuals/ApiCompatBaseline.txt | 4 +- src/Avalonia.Visuals/Media/IBrush.cs | 5 ++ .../Media/Immutable/ImmutableGradientBrush.cs | 5 ++ .../Immutable/ImmutableSolidColorBrush.cs | 9 ++- .../Media/Immutable/ImmutableTileBrush.cs | 5 ++ src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 67 ++++++++++++++++--- 6 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index 39a4c3004c2..7d2151a4851 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -5,6 +5,8 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Task MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.IPageTransition.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IPageTransition.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean, System.Threading.CancellationToken)' is present in the implementation but not in the contract. MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.PageSlide.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.Transform Avalonia.Media.IBrush.Transform' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.Transform Avalonia.Media.IBrush.Transform.get()' is present in the implementation but not in the contract. TypeCannotChangeClassification : Type 'Avalonia.Media.Immutable.ImmutableSolidColorBrush' is a 'class' in the implementation but is a 'struct' in the contract. MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' does not exist in the implementation but it does exist in the contract. CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' is abstract in the implementation but is missing in the contract. @@ -74,4 +76,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWr InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmap(System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmapToHeight(System.IO.Stream, System.Int32, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmapToWidth(System.IO.Stream, System.Int32, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the implementation but not in the contract. -Total Issues: 75 +Total Issues: 77 diff --git a/src/Avalonia.Visuals/Media/IBrush.cs b/src/Avalonia.Visuals/Media/IBrush.cs index 15b7681be4a..f481bbff549 100644 --- a/src/Avalonia.Visuals/Media/IBrush.cs +++ b/src/Avalonia.Visuals/Media/IBrush.cs @@ -12,5 +12,10 @@ public interface IBrush /// Gets the opacity of the brush. /// double Opacity { get; } + + /// + /// Gets the transform of the brush. + /// + Transform Transform { get; } } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs index 1f6e3bbcfd8..6ae1bfe88af 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs @@ -39,6 +39,11 @@ protected ImmutableGradientBrush(GradientBrush source) /// public double Opacity { get; } + /// + /// Gets the transform of the brush. + /// + public Transform Transform { get; } + /// public GradientSpreadMethod SpreadMethod { get; } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs index 8e93ac580e3..1e48d91f05c 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs @@ -46,11 +46,16 @@ public ImmutableSolidColorBrush(ISolidColorBrush source) /// public double Opacity { get; } + /// + /// Gets the transform of the brush. + /// + public Transform Transform { get; } + public bool Equals(ImmutableSolidColorBrush other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return Color.Equals(other.Color) && Opacity.Equals(other.Opacity); + return Color.Equals(other.Color) && Opacity.Equals(other.Opacity) && (Transform == null && other.Transform == null ? true : Transform.Equals(other.Transform)); } public override bool Equals(object obj) @@ -62,7 +67,7 @@ public override int GetHashCode() { unchecked { - return (Color.GetHashCode() * 397) ^ Opacity.GetHashCode(); + return (Color.GetHashCode() * 397) ^ Opacity.GetHashCode() ^ (Transform is null ? 0 : Transform.GetHashCode()); } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index fd4d9215163..0557f5c1d65 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -69,6 +69,11 @@ protected ImmutableTileBrush(ITileBrush source) /// public double Opacity { get; } + /// + /// Gets the transform of the brush. + /// + public Transform Transform { get; } + /// public RelativeRect SourceRect { get; } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 2352b8b076c..5bade6c5e5e 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -608,10 +608,21 @@ private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect targetRe var end = position + linearGradient.EndPoint.ToPixels(targetRect.Size).ToSKPoint(); // would be nice to cache these shaders possibly? - using (var shader = - SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode)) + if (linearGradient.Transform is null) { - paintWrapper.Paint.Shader = shader; + using (var shader = + SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode)) + { + paintWrapper.Paint.Shader = shader; + } + } + else + { + using (var shader = + SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, linearGradient.Transform.Value.ToSKMatrix())) + { + paintWrapper.Paint.Shader = shader; + } } break; @@ -626,10 +637,21 @@ private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect targetRe if (origin.Equals(center)) { // when the origin is the same as the center the Skia RadialGradient acts the same as D2D - using (var shader = - SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode)) + if (radialGradient.Transform is null) { - paintWrapper.Paint.Shader = shader; + using (var shader = + SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode)) + { + paintWrapper.Paint.Shader = shader; + } + } + else + { + using (var shader = + SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, radialGradient.Transform.Value.ToSKMatrix())) + { + paintWrapper.Paint.Shader = shader; + } } } else @@ -653,12 +675,25 @@ private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect targetRe } // compose with a background colour of the final stop to match D2D's behaviour of filling with the final color - using (var shader = SKShader.CreateCompose( - SKShader.CreateColor(reversedColors[0]), - SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode) - )) + if (radialGradient.Transform is null) { - paintWrapper.Paint.Shader = shader; + using (var shader = SKShader.CreateCompose( + SKShader.CreateColor(reversedColors[0]), + SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode) + )) + { + paintWrapper.Paint.Shader = shader; + } + } + else + { + using (var shader = SKShader.CreateCompose( + SKShader.CreateColor(reversedColors[0]), + SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, radialGradient.Transform.Value.ToSKMatrix()) + )) + { + paintWrapper.Paint.Shader = shader; + } } } @@ -673,6 +708,11 @@ private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect targetRe var angle = (float)(conicGradient.Angle - 90); var rotation = SKMatrix.CreateRotationDegrees(angle, center.X, center.Y); + if (conicGradient.Transform is not null) + { + rotation = rotation.PreConcat(conicGradient.Transform.Value.ToSKMatrix()); + } + using (var shader = SKShader.CreateSweepGradient(center, stopColors, stopOffsets, rotation)) { @@ -740,6 +780,11 @@ private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, var paintTransform = default(SKMatrix); + if (tileBrush.Transform is not null) + { + paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix()); + } + SKMatrix.Concat( ref paintTransform, tileTransform, From 4a443f691675bd82a50a768c8d21102c2a2f6884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 19:10:26 +0200 Subject: [PATCH 03/23] Move transform --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 5bade6c5e5e..c282b4c24de 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -780,16 +780,16 @@ private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, var paintTransform = default(SKMatrix); - if (tileBrush.Transform is not null) - { - paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix()); - } - SKMatrix.Concat( ref paintTransform, tileTransform, SKMatrix.CreateScale((float)(96.0 / _dpi.X), (float)(96.0 / _dpi.Y))); + if (tileBrush.Transform is not null) + { + paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix()); + } + using (var shader = image.ToShader(tileX, tileY, paintTransform)) { paintWrapper.Paint.Shader = shader; From d47c47935e354fc24a076b0c3383d233b3b84792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 19:26:27 +0200 Subject: [PATCH 04/23] Do not use not pattern --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index c282b4c24de..4e47953863b 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -708,7 +708,7 @@ private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Rect targetRe var angle = (float)(conicGradient.Angle - 90); var rotation = SKMatrix.CreateRotationDegrees(angle, center.X, center.Y); - if (conicGradient.Transform is not null) + if (conicGradient.Transform is { }) { rotation = rotation.PreConcat(conicGradient.Transform.Value.ToSKMatrix()); } @@ -785,7 +785,7 @@ private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, tileTransform, SKMatrix.CreateScale((float)(96.0 / _dpi.X), (float)(96.0 / _dpi.Y))); - if (tileBrush.Transform is not null) + if (tileBrush.Transform is { }) { paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix()); } From 13f137c7abbbbb0fec8eec756c170b734e8e97d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 20:36:48 +0200 Subject: [PATCH 05/23] Fix deferred rendering by using immutable transform --- .../Animators/GradientBrushAnimator.cs | 6 +++++ src/Avalonia.Visuals/ApiCompatBaseline.txt | 12 ++++++--- src/Avalonia.Visuals/Media/Brush.cs | 6 ++--- src/Avalonia.Visuals/Media/IBrush.cs | 2 +- .../Media/IMutableTransform.cs | 6 +++++ .../Media/Immutable/IImmutableTransform.cs | 21 ++++++++++++++++ .../Immutable/ImmutableConicGradientBrush.cs | 4 ++- .../Media/Immutable/ImmutableGradientBrush.cs | 7 ++++-- .../Media/Immutable/ImmutableImageBrush.cs | 3 +++ .../Immutable/ImmutableLinearGradientBrush.cs | 4 ++- .../Immutable/ImmutableRadialGradientBrush.cs | 4 ++- .../Immutable/ImmutableSolidColorBrush.cs | 2 +- .../Media/Immutable/ImmutableTileBrush.cs | 6 ++++- .../Media/Immutable/ImmutableVisualBrush.cs | 3 +++ src/Avalonia.Visuals/Media/Transform.cs | 7 ++++++ .../Media/TransformExtensions.cs | 25 +++++++++++++++++++ 16 files changed, 104 insertions(+), 14 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/Immutable/IImmutableTransform.cs create mode 100644 src/Avalonia.Visuals/Media/TransformExtensions.cs diff --git a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs index 864e12413fc..bb8457de9ac 100644 --- a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs @@ -30,6 +30,7 @@ public class GradientBrushAnimator : Animator return new ImmutableRadialGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), + oldValue.Transform, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -39,6 +40,7 @@ public class GradientBrushAnimator : Animator return new ImmutableConicGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), + oldValue.Transform, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -47,6 +49,7 @@ public class GradientBrushAnimator : Animator return new ImmutableLinearGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), + oldValue.Transform, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); @@ -93,16 +96,19 @@ internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush g case IRadialGradientBrush oldRadial: return new ImmutableRadialGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity, + oldRadial.Transform, oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius); case IConicGradientBrush oldConic: return new ImmutableConicGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity, + oldConic.Transform, oldConic.SpreadMethod, oldConic.Center, oldConic.Angle); case ILinearGradientBrush oldLinear: return new ImmutableLinearGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity, + oldLinear.Transform, oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint); default: diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index 7d2151a4851..41985dc078c 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -5,9 +5,15 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Task MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.IPageTransition.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Tasks.Task Avalonia.Animation.IPageTransition.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean, System.Threading.CancellationToken)' is present in the implementation but not in the contract. MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.PageSlide.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.Transform Avalonia.Media.IBrush.Transform' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.Transform Avalonia.Media.IBrush.Transform.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IBrush.Transform' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IBrush.Transform.get()' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IMutableTransform.ToImmutable()' is present in the implementation but not in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableConicGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Double)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected void Avalonia.Media.Immutable.ImmutableGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableLinearGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Nullable)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableRadialGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Nullable, System.Double)' does not exist in the implementation but it does exist in the contract. TypeCannotChangeClassification : Type 'Avalonia.Media.Immutable.ImmutableSolidColorBrush' is a 'class' in the implementation but is a 'struct' in the contract. +MembersMustExist : Member 'protected void Avalonia.Media.Immutable.ImmutableTileBrush..ctor(Avalonia.Media.AlignmentX, Avalonia.Media.AlignmentY, Avalonia.RelativeRect, System.Double, Avalonia.RelativeRect, Avalonia.Media.Stretch, Avalonia.Media.TileMode, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' does not exist in the implementation but it does exist in the contract. CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' is abstract in the implementation but is missing in the contract. CannotSealType : Type 'Avalonia.Media.TextFormatting.GenericTextParagraphProperties' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. @@ -76,4 +82,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWr InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmap(System.String)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmapToHeight(System.IO.Stream, System.Int32, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.IWriteableBitmapImpl Avalonia.Platform.IPlatformRenderInterface.LoadWriteableBitmapToWidth(System.IO.Stream, System.Int32, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the implementation but not in the contract. -Total Issues: 77 +Total Issues: 83 diff --git a/src/Avalonia.Visuals/Media/Brush.cs b/src/Avalonia.Visuals/Media/Brush.cs index fe0dc63297a..101b28a3762 100644 --- a/src/Avalonia.Visuals/Media/Brush.cs +++ b/src/Avalonia.Visuals/Media/Brush.cs @@ -21,8 +21,8 @@ public abstract class Brush : Animatable, IMutableBrush /// /// Defines the property. /// - public static readonly StyledProperty TransformProperty = - AvaloniaProperty.Register(nameof(Transform)); + public static readonly StyledProperty TransformProperty = + AvaloniaProperty.Register(nameof(Transform)); /// public event EventHandler Invalidated; @@ -45,7 +45,7 @@ public double Opacity /// /// Gets or sets the transform of the brush. /// - public Transform Transform + public ITransform Transform { get { return GetValue(TransformProperty); } set { SetValue(TransformProperty, value); } diff --git a/src/Avalonia.Visuals/Media/IBrush.cs b/src/Avalonia.Visuals/Media/IBrush.cs index f481bbff549..c3d03fb35bd 100644 --- a/src/Avalonia.Visuals/Media/IBrush.cs +++ b/src/Avalonia.Visuals/Media/IBrush.cs @@ -16,6 +16,6 @@ public interface IBrush /// /// Gets the transform of the brush. /// - Transform Transform { get; } + ITransform Transform { get; } } } diff --git a/src/Avalonia.Visuals/Media/IMutableTransform.cs b/src/Avalonia.Visuals/Media/IMutableTransform.cs index 2033c434c08..d7a106b22b5 100644 --- a/src/Avalonia.Visuals/Media/IMutableTransform.cs +++ b/src/Avalonia.Visuals/Media/IMutableTransform.cs @@ -8,5 +8,11 @@ public interface IMutableTransform : ITransform /// Raised when the transform changes. /// event EventHandler Changed; + + /// + /// Converts a transform to an immutable transform. + /// + /// The immutable transform + ITransform ToImmutable(); } } diff --git a/src/Avalonia.Visuals/Media/Immutable/IImmutableTransform.cs b/src/Avalonia.Visuals/Media/Immutable/IImmutableTransform.cs new file mode 100644 index 00000000000..d5ff2b8317a --- /dev/null +++ b/src/Avalonia.Visuals/Media/Immutable/IImmutableTransform.cs @@ -0,0 +1,21 @@ +using Avalonia.VisualTree; + +namespace Avalonia.Media.Immutable +{ + /// + /// Represents a transform on an . + /// + public class ImmutableTransform : ITransform + { + public Matrix Value { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The transform matrix. + public ImmutableTransform(Matrix matrix) + { + Value = matrix; + } + } +} diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs index d3c80dfcad9..dc9360d1626 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs @@ -12,16 +12,18 @@ public class ImmutableConicGradientBrush : ImmutableGradientBrush, IConicGradien /// /// The gradient stops. /// The opacity of the brush. + /// The transform of the brush. /// The spread method. /// The center point for the gradient. /// The starting angle for the gradient. public ImmutableConicGradientBrush( IReadOnlyList gradientStops, double opacity = 1, + ITransform transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, double angle = 0) - : base(gradientStops, opacity, spreadMethod) + : base(gradientStops, opacity, transform, spreadMethod) { Center = center ?? RelativePoint.Center; Angle = angle; diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs index 6ae1bfe88af..12e1a396351 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs @@ -12,14 +12,17 @@ public abstract class ImmutableGradientBrush : IGradientBrush /// /// The gradient stops. /// The opacity of the brush. + /// The transform of the brush. /// The spread method. protected ImmutableGradientBrush( IReadOnlyList gradientStops, double opacity, + ITransform transform, GradientSpreadMethod spreadMethod) { GradientStops = gradientStops; Opacity = opacity; + Transform = transform; SpreadMethod = spreadMethod; } @@ -28,7 +31,7 @@ protected ImmutableGradientBrush( /// /// The brush from which this brush's properties should be copied. protected ImmutableGradientBrush(GradientBrush source) - : this(source.GradientStops.ToImmutable(), source.Opacity, source.SpreadMethod) + : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform.ToImmutable(), source.SpreadMethod) { } @@ -42,7 +45,7 @@ protected ImmutableGradientBrush(GradientBrush source) /// /// Gets the transform of the brush. /// - public Transform Transform { get; } + public ITransform Transform { get; } /// public GradientSpreadMethod SpreadMethod { get; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs index 15da8f8b432..43b157faa98 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs @@ -16,6 +16,7 @@ internal class ImmutableImageBrush : ImmutableTileBrush, IImageBrush /// The vertical alignment of a tile in the destination. /// The rectangle on the destination in which to paint a tile. /// The opacity of the brush. + /// The transform of the brush. /// The rectangle of the source image that will be displayed. /// /// How the source rectangle will be stretched to fill the destination rect. @@ -28,6 +29,7 @@ public ImmutableImageBrush( AlignmentY alignmentY = AlignmentY.Center, RelativeRect? destinationRect = null, double opacity = 1, + ITransform transform = null, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, @@ -37,6 +39,7 @@ public ImmutableImageBrush( alignmentY, destinationRect ?? RelativeRect.Fill, opacity, + transform, sourceRect ?? RelativeRect.Fill, stretch, tileMode, diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs index 912d77d763d..2270a5e855d 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs @@ -12,16 +12,18 @@ public class ImmutableLinearGradientBrush : ImmutableGradientBrush, ILinearGradi /// /// The gradient stops. /// The opacity of the brush. + /// The transform of the brush. /// The spread method. /// The start point for the gradient. /// The end point for the gradient. public ImmutableLinearGradientBrush( IReadOnlyList gradientStops, double opacity = 1, + ITransform transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? startPoint = null, RelativePoint? endPoint = null) - : base(gradientStops, opacity, spreadMethod) + : base(gradientStops, opacity, transform, spreadMethod) { StartPoint = startPoint ?? RelativePoint.TopLeft; EndPoint = endPoint ?? RelativePoint.BottomRight; diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs index e26fbab5f53..f621d83213e 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs @@ -12,6 +12,7 @@ public class ImmutableRadialGradientBrush : ImmutableGradientBrush, IRadialGradi /// /// The gradient stops. /// The opacity of the brush. + /// The transform of the brush. /// The spread method. /// The start point for the gradient. /// @@ -23,11 +24,12 @@ public class ImmutableRadialGradientBrush : ImmutableGradientBrush, IRadialGradi public ImmutableRadialGradientBrush( IReadOnlyList gradientStops, double opacity = 1, + ITransform transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, RelativePoint? gradientOrigin = null, double radius = 0.5) - : base(gradientStops, opacity, spreadMethod) + : base(gradientStops, opacity, transform, spreadMethod) { Center = center ?? RelativePoint.Center; GradientOrigin = gradientOrigin ?? RelativePoint.Center; diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs index 1e48d91f05c..daf73f89740 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs @@ -49,7 +49,7 @@ public ImmutableSolidColorBrush(ISolidColorBrush source) /// /// Gets the transform of the brush. /// - public Transform Transform { get; } + public ITransform Transform { get; } public bool Equals(ImmutableSolidColorBrush other) { diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index 0557f5c1d65..e96ef026aff 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -14,6 +14,7 @@ public abstract class ImmutableTileBrush : ITileBrush /// The vertical alignment of a tile in the destination. /// The rectangle on the destination in which to paint a tile. /// The opacity of the brush. + /// The transform of the brush. /// The rectangle of the source image that will be displayed. /// /// How the source rectangle will be stretched to fill the destination rect. @@ -25,6 +26,7 @@ protected ImmutableTileBrush( AlignmentY alignmentY, RelativeRect destinationRect, double opacity, + ITransform transform, RelativeRect sourceRect, Stretch stretch, TileMode tileMode, @@ -34,6 +36,7 @@ protected ImmutableTileBrush( AlignmentY = alignmentY; DestinationRect = destinationRect; Opacity = opacity; + Transform = transform; SourceRect = sourceRect; Stretch = stretch; TileMode = tileMode; @@ -50,6 +53,7 @@ protected ImmutableTileBrush(ITileBrush source) source.AlignmentY, source.DestinationRect, source.Opacity, + source.Transform.ToImmutable(), source.SourceRect, source.Stretch, source.TileMode, @@ -72,7 +76,7 @@ protected ImmutableTileBrush(ITileBrush source) /// /// Gets the transform of the brush. /// - public Transform Transform { get; } + public ITransform Transform { get; } /// public RelativeRect SourceRect { get; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs index 4c6aae08ab4..ccc0b64f987 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs @@ -16,6 +16,7 @@ internal class ImmutableVisualBrush : ImmutableTileBrush, IVisualBrush /// The vertical alignment of a tile in the destination. /// The rectangle on the destination in which to paint a tile. /// The opacity of the brush. + /// The transform of the brush. /// The rectangle of the source image that will be displayed. /// /// How the source rectangle will be stretched to fill the destination rect. @@ -28,6 +29,7 @@ public ImmutableVisualBrush( AlignmentY alignmentY = AlignmentY.Center, RelativeRect? destinationRect = null, double opacity = 1, + Transform transform = null, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, @@ -37,6 +39,7 @@ public ImmutableVisualBrush( alignmentY, destinationRect ?? RelativeRect.Fill, opacity, + transform, sourceRect ?? RelativeRect.Fill, stretch, tileMode, diff --git a/src/Avalonia.Visuals/Media/Transform.cs b/src/Avalonia.Visuals/Media/Transform.cs index 7cf1b35ada4..2df0c7cc27b 100644 --- a/src/Avalonia.Visuals/Media/Transform.cs +++ b/src/Avalonia.Visuals/Media/Transform.cs @@ -1,6 +1,7 @@ using System; using Avalonia.Animation; using Avalonia.Animation.Animators; +using Avalonia.Media.Immutable; using Avalonia.VisualTree; namespace Avalonia.Media @@ -44,6 +45,12 @@ protected void RaiseChanged() Changed?.Invoke(this, EventArgs.Empty); } + /// + public ITransform ToImmutable() + { + return new ImmutableTransform(this.Value); + } + /// /// Returns a String representing this transform matrix instance. /// diff --git a/src/Avalonia.Visuals/Media/TransformExtensions.cs b/src/Avalonia.Visuals/Media/TransformExtensions.cs new file mode 100644 index 00000000000..2f473fcadb7 --- /dev/null +++ b/src/Avalonia.Visuals/Media/TransformExtensions.cs @@ -0,0 +1,25 @@ +using System; + +namespace Avalonia.Media +{ + /// + /// Extension methods for transform classes. + /// + public static class TransformExtensions + { + /// + /// Converts a transform to an immutable transform. + /// + /// The transform. + /// + /// The result of calling if the transform is mutable, + /// otherwise . + /// + public static ITransform ToImmutable(this ITransform transform) + { + Contract.Requires(transform != null); + + return (transform as IMutableTransform)?.ToImmutable() ?? transform; + } + } +} From 90a027aef82e1fcddfbc4a8dcb6f40009328acf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 20:39:22 +0200 Subject: [PATCH 06/23] Rename --- .../Immutable/{IImmutableTransform.cs => ImmutableTransform.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Avalonia.Visuals/Media/Immutable/{IImmutableTransform.cs => ImmutableTransform.cs} (100%) diff --git a/src/Avalonia.Visuals/Media/Immutable/IImmutableTransform.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTransform.cs similarity index 100% rename from src/Avalonia.Visuals/Media/Immutable/IImmutableTransform.cs rename to src/Avalonia.Visuals/Media/Immutable/ImmutableTransform.cs From e3bfa12909d1f9d8840a0114512bd4d587a8942f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 21:40:19 +0200 Subject: [PATCH 07/23] Use ImmutableTransform --- .../Animation/Animators/GradientBrushAnimator.cs | 13 +++++++------ .../Animation/Animators/TransformAnimator.cs | 7 +++++++ src/Avalonia.Visuals/Media/IMutableTransform.cs | 6 ------ .../Media/Immutable/ImmutableConicGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableImageBrush.cs | 2 +- .../Media/Immutable/ImmutableLinearGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableRadialGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableVisualBrush.cs | 2 +- src/Avalonia.Visuals/Media/Transform.cs | 7 +++++-- src/Avalonia.Visuals/Media/TransformExtensions.cs | 7 ++++--- 11 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs index bb8457de9ac..5d206ad9e1c 100644 --- a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs @@ -16,6 +16,7 @@ public class GradientBrushAnimator : Animator { private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator(); private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator(); + private static readonly TransformAnimator s_transformAnimator = new TransformAnimator(); public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue) { @@ -30,7 +31,7 @@ public class GradientBrushAnimator : Animator return new ImmutableRadialGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform, + s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform), oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -40,7 +41,7 @@ public class GradientBrushAnimator : Animator return new ImmutableConicGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform, + s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform), oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -49,7 +50,7 @@ public class GradientBrushAnimator : Animator return new ImmutableLinearGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform, + s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform), oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); @@ -96,19 +97,19 @@ internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush g case IRadialGradientBrush oldRadial: return new ImmutableRadialGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity, - oldRadial.Transform, + new ImmutableTransform(oldRadial.Transform.Value), oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius); case IConicGradientBrush oldConic: return new ImmutableConicGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity, - oldConic.Transform, + new ImmutableTransform(oldConic.Transform.Value), oldConic.SpreadMethod, oldConic.Center, oldConic.Angle); case ILinearGradientBrush oldLinear: return new ImmutableLinearGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity, - oldLinear.Transform, + new ImmutableTransform(oldLinear.Transform.Value), oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint); default: diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index 1b2142f6c95..0299cba0e5c 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -2,6 +2,7 @@ using System.Reactive.Disposables; using Avalonia.Logging; using Avalonia.Media; +using Avalonia.Media.Immutable; using Avalonia.Media.Transformation; namespace Avalonia.Animation.Animators @@ -86,6 +87,12 @@ public override IDisposable Apply(Animation animation, Animatable control, ICloc return null; } + internal ImmutableTransform InterpolateTransform(double progress, ITransform oldValue, ITransform newValue) + { + // TODO: + return new ImmutableTransform(newValue.Value); + } + /// public override double Interpolate(double p, double o, double n) => 0; } diff --git a/src/Avalonia.Visuals/Media/IMutableTransform.cs b/src/Avalonia.Visuals/Media/IMutableTransform.cs index d7a106b22b5..2033c434c08 100644 --- a/src/Avalonia.Visuals/Media/IMutableTransform.cs +++ b/src/Avalonia.Visuals/Media/IMutableTransform.cs @@ -8,11 +8,5 @@ public interface IMutableTransform : ITransform /// Raised when the transform changes. /// event EventHandler Changed; - - /// - /// Converts a transform to an immutable transform. - /// - /// The immutable transform - ITransform ToImmutable(); } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs index dc9360d1626..869262c7a46 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs @@ -19,7 +19,7 @@ public class ImmutableConicGradientBrush : ImmutableGradientBrush, IConicGradien public ImmutableConicGradientBrush( IReadOnlyList gradientStops, double opacity = 1, - ITransform transform = null, + ImmutableTransform transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, double angle = 0) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs index 12e1a396351..87ada91cbda 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs @@ -17,7 +17,7 @@ public abstract class ImmutableGradientBrush : IGradientBrush protected ImmutableGradientBrush( IReadOnlyList gradientStops, double opacity, - ITransform transform, + ImmutableTransform transform, GradientSpreadMethod spreadMethod) { GradientStops = gradientStops; diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs index 43b157faa98..41456b7f92b 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs @@ -29,7 +29,7 @@ public ImmutableImageBrush( AlignmentY alignmentY = AlignmentY.Center, RelativeRect? destinationRect = null, double opacity = 1, - ITransform transform = null, + ImmutableTransform transform = null, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs index 2270a5e855d..1c905c166e7 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs @@ -19,7 +19,7 @@ public class ImmutableLinearGradientBrush : ImmutableGradientBrush, ILinearGradi public ImmutableLinearGradientBrush( IReadOnlyList gradientStops, double opacity = 1, - ITransform transform = null, + ImmutableTransform transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? startPoint = null, RelativePoint? endPoint = null) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs index f621d83213e..910e14faf74 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs @@ -24,7 +24,7 @@ public class ImmutableRadialGradientBrush : ImmutableGradientBrush, IRadialGradi public ImmutableRadialGradientBrush( IReadOnlyList gradientStops, double opacity = 1, - ITransform transform = null, + ImmutableTransform transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, RelativePoint? gradientOrigin = null, diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs index ccc0b64f987..abec1704199 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs @@ -29,7 +29,7 @@ public ImmutableVisualBrush( AlignmentY alignmentY = AlignmentY.Center, RelativeRect? destinationRect = null, double opacity = 1, - Transform transform = null, + ImmutableTransform transform = null, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, diff --git a/src/Avalonia.Visuals/Media/Transform.cs b/src/Avalonia.Visuals/Media/Transform.cs index 2df0c7cc27b..5a757b44c67 100644 --- a/src/Avalonia.Visuals/Media/Transform.cs +++ b/src/Avalonia.Visuals/Media/Transform.cs @@ -45,8 +45,11 @@ protected void RaiseChanged() Changed?.Invoke(this, EventArgs.Empty); } - /// - public ITransform ToImmutable() + /// + /// Converts a transform to an immutable transform. + /// + /// The immutable transform + public ImmutableTransform ToImmutable() { return new ImmutableTransform(this.Value); } diff --git a/src/Avalonia.Visuals/Media/TransformExtensions.cs b/src/Avalonia.Visuals/Media/TransformExtensions.cs index 2f473fcadb7..c264d483cd6 100644 --- a/src/Avalonia.Visuals/Media/TransformExtensions.cs +++ b/src/Avalonia.Visuals/Media/TransformExtensions.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Media.Immutable; namespace Avalonia.Media { @@ -12,14 +13,14 @@ public static class TransformExtensions /// /// The transform. /// - /// The result of calling if the transform is mutable, + /// The result of calling if the transform is mutable, /// otherwise . /// - public static ITransform ToImmutable(this ITransform transform) + public static ImmutableTransform ToImmutable(this ITransform transform) { Contract.Requires(transform != null); - return (transform as IMutableTransform)?.ToImmutable() ?? transform; + return (transform as Transform)?.ToImmutable() ?? new ImmutableTransform(transform.Value); } } } From 4f90ab46f0a7869d0f6294a93c61d7dad748f423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 21:44:54 +0200 Subject: [PATCH 08/23] Check for null --- .../Animation/Animators/GradientBrushAnimator.cs | 12 ++++++------ .../Media/Immutable/ImmutableGradientBrush.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs index 5d206ad9e1c..817c53698e4 100644 --- a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs @@ -31,7 +31,7 @@ public class GradientBrushAnimator : Animator return new ImmutableRadialGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform), + oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -41,7 +41,7 @@ public class GradientBrushAnimator : Animator return new ImmutableConicGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform), + oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -50,7 +50,7 @@ public class GradientBrushAnimator : Animator return new ImmutableLinearGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform), + oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); @@ -97,19 +97,19 @@ internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush g case IRadialGradientBrush oldRadial: return new ImmutableRadialGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity, - new ImmutableTransform(oldRadial.Transform.Value), + oldRadial.Transform is { } ? new ImmutableTransform(oldRadial.Transform.Value) : null, oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius); case IConicGradientBrush oldConic: return new ImmutableConicGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity, - new ImmutableTransform(oldConic.Transform.Value), + oldConic.Transform is { } ? new ImmutableTransform(oldConic.Transform.Value) : null, oldConic.SpreadMethod, oldConic.Center, oldConic.Angle); case ILinearGradientBrush oldLinear: return new ImmutableLinearGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity, - new ImmutableTransform(oldLinear.Transform.Value), + oldLinear.Transform is { } ? new ImmutableTransform(oldLinear.Transform.Value) : null, oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint); default: diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs index 87ada91cbda..78e46f52d00 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs @@ -31,7 +31,7 @@ protected ImmutableGradientBrush( /// /// The brush from which this brush's properties should be copied. protected ImmutableGradientBrush(GradientBrush source) - : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform.ToImmutable(), source.SpreadMethod) + : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform?.ToImmutable(), source.SpreadMethod) { } From e361b827eb6ad7edf0cf08831f8de8002a25a72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 21:51:01 +0200 Subject: [PATCH 09/23] Add transform --- src/Avalonia.Visuals/ApiCompatBaseline.txt | 2 +- .../Media/Immutable/ImmutableSolidColorBrush.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index 41985dc078c..18b8f4c5a83 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -7,12 +7,12 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Threading.Task MembersMustExist : Member 'public System.Threading.Tasks.Task Avalonia.Animation.PageSlide.Start(Avalonia.Visual, Avalonia.Visual, System.Boolean)' does not exist in the implementation but it does exist in the contract. InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IBrush.Transform' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IBrush.Transform.get()' is present in the implementation but not in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IMutableTransform.ToImmutable()' is present in the implementation but not in the contract. MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableConicGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Double)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Media.Immutable.ImmutableGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableLinearGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Nullable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableRadialGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Nullable, System.Double)' does not exist in the implementation but it does exist in the contract. TypeCannotChangeClassification : Type 'Avalonia.Media.Immutable.ImmutableSolidColorBrush' is a 'class' in the implementation but is a 'struct' in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableSolidColorBrush..ctor(Avalonia.Media.Color, System.Double)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Media.Immutable.ImmutableTileBrush..ctor(Avalonia.Media.AlignmentX, Avalonia.Media.AlignmentY, Avalonia.RelativeRect, System.Double, Avalonia.RelativeRect, Avalonia.Media.Stretch, Avalonia.Media.TileMode, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext)' does not exist in the implementation but it does exist in the contract. CannotAddAbstractMembers : Member 'public void Avalonia.Media.TextFormatting.DrawableTextRun.Draw(Avalonia.Media.DrawingContext, Avalonia.Point)' is abstract in the implementation but is missing in the contract. diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs index daf73f89740..ac7d336f308 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs @@ -12,10 +12,12 @@ public class ImmutableSolidColorBrush : ISolidColorBrush, IEquatable /// The color to use. /// The opacity of the brush. - public ImmutableSolidColorBrush(Color color, double opacity = 1) + /// The transform of the brush. + public ImmutableSolidColorBrush(Color color, double opacity = 1, ImmutableTransform transform = null) { Color = color; Opacity = opacity; + Transform = null; } /// @@ -32,7 +34,7 @@ public ImmutableSolidColorBrush(uint color) /// /// The brush from which this brush's properties should be copied. public ImmutableSolidColorBrush(ISolidColorBrush source) - : this(source.Color, source.Opacity) + : this(source.Color, source.Opacity, source.Transform?.ToImmutable()) { } From 167ad6c003ad58ea5739a8574ba25102b19c1d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 21:51:08 +0200 Subject: [PATCH 10/23] Use ImmutableTransform --- src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index e96ef026aff..1eaf3bce67d 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -26,7 +26,7 @@ protected ImmutableTileBrush( AlignmentY alignmentY, RelativeRect destinationRect, double opacity, - ITransform transform, + ImmutableTransform transform, RelativeRect sourceRect, Stretch stretch, TileMode tileMode, From 81daa4f03b50c53cae15f2a770daba79eb613d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 22:10:51 +0200 Subject: [PATCH 11/23] Add Matrix interpolation --- .../Animators/GradientBrushAnimator.cs | 6 +++--- .../Animation/Animators/TransformAnimator.cs | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs index 817c53698e4..ce0cfa2ce31 100644 --- a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs @@ -31,7 +31,7 @@ public class GradientBrushAnimator : Animator return new ImmutableRadialGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateMatrix(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -41,7 +41,7 @@ public class GradientBrushAnimator : Animator return new ImmutableConicGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateMatrix(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -50,7 +50,7 @@ public class GradientBrushAnimator : Animator return new ImmutableLinearGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateMatrix(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index 0299cba0e5c..102e0f83a85 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -87,10 +87,19 @@ public override IDisposable Apply(Animation animation, Animatable control, ICloc return null; } - internal ImmutableTransform InterpolateTransform(double progress, ITransform oldValue, ITransform newValue) - { - // TODO: - return new ImmutableTransform(newValue.Value); + internal ImmutableTransform InterpolateMatrix(double progress, ITransform oldValue, ITransform newValue) + { + var from = oldValue.Value; + var to = newValue.Value; + var matrix = new Matrix( + ((to.M11 - from.M11) * progress) + from.M11, + ((to.M12 - from.M12) * progress) + from.M12, + ((to.M21 - from.M21) * progress) + from.M21, + ((to.M22 - from.M22) * progress) + from.M22, + ((to.M31 - from.M31) * progress) + from.M31, + ((to.M32 - from.M32) * progress) + from.M32); + + return new ImmutableTransform(matrix); } /// From cca7b962287be0b209de79181e0ef6a8375d822f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 22:57:27 +0200 Subject: [PATCH 12/23] Mark field as private --- src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index 102e0f83a85..271430ee42b 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -12,7 +12,7 @@ namespace Avalonia.Animation.Animators /// public class TransformAnimator : Animator { - DoubleAnimator _doubleAnimator; + private DoubleAnimator _doubleAnimator; /// public override IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable obsMatch, Action onComplete) From 97332822c368ae1250b854c8370337a52566d459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Sun, 1 Aug 2021 22:57:40 +0200 Subject: [PATCH 13/23] Add MatrixAnimator --- .../Animators/GradientBrushAnimator.cs | 12 ++++++++--- .../Animation/Animators/MatrixAnimator.cs | 20 +++++++++++++++++++ .../Animation/Animators/TransformAnimator.cs | 15 -------------- .../Animation/Transitions/MatrixTransition.cs | 11 ++++++++++ src/Avalonia.Visuals/Matrix.cs | 10 ++++++++++ 5 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs create mode 100644 src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs diff --git a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs index ce0cfa2ce31..3c13752992c 100644 --- a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs @@ -17,6 +17,7 @@ public class GradientBrushAnimator : Animator private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator(); private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator(); private static readonly TransformAnimator s_transformAnimator = new TransformAnimator(); + private static readonly MatrixAnimator _matrixAnimator = new MatrixAnimator(); public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue) { @@ -31,7 +32,7 @@ public class GradientBrushAnimator : Animator return new ImmutableRadialGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateMatrix(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } && newValue.Transform is { } ? InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -41,7 +42,7 @@ public class GradientBrushAnimator : Animator return new ImmutableConicGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateMatrix(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } && newValue.Transform is { } ? InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -50,7 +51,7 @@ public class GradientBrushAnimator : Animator return new ImmutableLinearGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? s_transformAnimator.InterpolateMatrix(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } && newValue.Transform is { } ? InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); @@ -90,6 +91,11 @@ private IReadOnlyList InterpolateStops(double progress, I return stops; } + private ImmutableTransform InterpolateTransform(double progress, ITransform oldValue, ITransform newValue) + { + return new ImmutableTransform(_matrixAnimator.Interpolate(progress, oldValue.Value, newValue.Value)); + } + internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush gradientBrush, ISolidColorBrush solidColorBrush) { switch (gradientBrush) diff --git a/src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs new file mode 100644 index 00000000000..d5b6267a3c6 --- /dev/null +++ b/src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs @@ -0,0 +1,20 @@ +namespace Avalonia.Animation.Animators +{ + /// + /// Animator that handles properties. + /// + public class MatrixAnimator : Animator + { + /// + public override Matrix Interpolate(double progress, Matrix oldValue, Matrix newValue) + { + return new Matrix( + ((newValue.M11 - oldValue.M11) * progress) + oldValue.M11, + ((newValue.M12 - oldValue.M12) * progress) + oldValue.M12, + ((newValue.M21 - oldValue.M21) * progress) + oldValue.M21, + ((newValue.M22 - oldValue.M22) * progress) + oldValue.M22, + ((newValue.M31 - oldValue.M31) * progress) + oldValue.M31, + ((newValue.M32 - oldValue.M32) * progress) + oldValue.M32); + } + } +} diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index 271430ee42b..1c5f6fa7862 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -87,21 +87,6 @@ public override IDisposable Apply(Animation animation, Animatable control, ICloc return null; } - internal ImmutableTransform InterpolateMatrix(double progress, ITransform oldValue, ITransform newValue) - { - var from = oldValue.Value; - var to = newValue.Value; - var matrix = new Matrix( - ((to.M11 - from.M11) * progress) + from.M11, - ((to.M12 - from.M12) * progress) + from.M12, - ((to.M21 - from.M21) * progress) + from.M21, - ((to.M22 - from.M22) * progress) + from.M22, - ((to.M31 - from.M31) * progress) + from.M31, - ((to.M32 - from.M32) * progress) + from.M32); - - return new ImmutableTransform(matrix); - } - /// public override double Interpolate(double p, double o, double n) => 0; } diff --git a/src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs new file mode 100644 index 00000000000..59bf06ca261 --- /dev/null +++ b/src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs @@ -0,0 +1,11 @@ +using Avalonia.Animation.Animators; + +namespace Avalonia.Animation +{ + /// + /// Transition class that handles with type. + /// + public class MatrixTransition : AnimatorDrivenTransition + { + } +} diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 8136f843dfd..7a56aa6fe27 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -1,5 +1,8 @@ using System; using System.Globalization; +#if !BUILDTASK +using Avalonia.Animation.Animators; +#endif using Avalonia.Utilities; namespace Avalonia @@ -12,6 +15,13 @@ namespace Avalonia #endif readonly struct Matrix : IEquatable { + static Matrix() + { +#if !BUILDTASK + Animation.Animation.RegisterAnimator(prop => typeof(Matrix).IsAssignableFrom(prop.PropertyType)); +#endif + } + private readonly double _m11; private readonly double _m12; private readonly double _m21; From 0beaa1c642a71fa40b3e03264834b47c6a4548ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Mon, 2 Aug 2021 08:34:10 +0200 Subject: [PATCH 14/23] Fix tests --- src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index 1eaf3bce67d..ed722275f57 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -53,7 +53,7 @@ protected ImmutableTileBrush(ITileBrush source) source.AlignmentY, source.DestinationRect, source.Opacity, - source.Transform.ToImmutable(), + source.Transform?.ToImmutable(), source.SourceRect, source.Stretch, source.TileMode, From addf992e533e6cbed86e0b92f77c789bdc24524d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 19:06:43 +0100 Subject: [PATCH 15/23] Revert --- src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index 1c5f6fa7862..1b2142f6c95 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -2,7 +2,6 @@ using System.Reactive.Disposables; using Avalonia.Logging; using Avalonia.Media; -using Avalonia.Media.Immutable; using Avalonia.Media.Transformation; namespace Avalonia.Animation.Animators @@ -12,7 +11,7 @@ namespace Avalonia.Animation.Animators /// public class TransformAnimator : Animator { - private DoubleAnimator _doubleAnimator; + DoubleAnimator _doubleAnimator; /// public override IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable obsMatch, Action onComplete) From a887a412b3bb24198e9cbee6307997b3ed97ec6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 19:07:07 +0100 Subject: [PATCH 16/23] Remove animator --- .../Animators/GradientBrushAnimator.cs | 13 +++--------- .../Animation/Animators/MatrixAnimator.cs | 20 ------------------- .../Animation/Transitions/MatrixTransition.cs | 11 ---------- src/Avalonia.Visuals/Matrix.cs | 7 ------- 4 files changed, 3 insertions(+), 48 deletions(-) delete mode 100644 src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs delete mode 100644 src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs diff --git a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs index 3c13752992c..f2d5632995d 100644 --- a/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/GradientBrushAnimator.cs @@ -16,8 +16,6 @@ public class GradientBrushAnimator : Animator { private static readonly RelativePointAnimator s_relativePointAnimator = new RelativePointAnimator(); private static readonly DoubleAnimator s_doubleAnimator = new DoubleAnimator(); - private static readonly TransformAnimator s_transformAnimator = new TransformAnimator(); - private static readonly MatrixAnimator _matrixAnimator = new MatrixAnimator(); public override IGradientBrush? Interpolate(double progress, IGradientBrush? oldValue, IGradientBrush? newValue) { @@ -32,7 +30,7 @@ public class GradientBrushAnimator : Animator return new ImmutableRadialGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -42,7 +40,7 @@ public class GradientBrushAnimator : Animator return new ImmutableConicGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -51,7 +49,7 @@ public class GradientBrushAnimator : Animator return new ImmutableLinearGradientBrush( InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), - oldValue.Transform is { } && newValue.Transform is { } ? InterpolateTransform(progress, oldValue.Transform, newValue.Transform) : null, + oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); @@ -91,11 +89,6 @@ private IReadOnlyList InterpolateStops(double progress, I return stops; } - private ImmutableTransform InterpolateTransform(double progress, ITransform oldValue, ITransform newValue) - { - return new ImmutableTransform(_matrixAnimator.Interpolate(progress, oldValue.Value, newValue.Value)); - } - internal static IGradientBrush ConvertSolidColorBrushToGradient(IGradientBrush gradientBrush, ISolidColorBrush solidColorBrush) { switch (gradientBrush) diff --git a/src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs deleted file mode 100644 index d5b6267a3c6..00000000000 --- a/src/Avalonia.Visuals/Animation/Animators/MatrixAnimator.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Avalonia.Animation.Animators -{ - /// - /// Animator that handles properties. - /// - public class MatrixAnimator : Animator - { - /// - public override Matrix Interpolate(double progress, Matrix oldValue, Matrix newValue) - { - return new Matrix( - ((newValue.M11 - oldValue.M11) * progress) + oldValue.M11, - ((newValue.M12 - oldValue.M12) * progress) + oldValue.M12, - ((newValue.M21 - oldValue.M21) * progress) + oldValue.M21, - ((newValue.M22 - oldValue.M22) * progress) + oldValue.M22, - ((newValue.M31 - oldValue.M31) * progress) + oldValue.M31, - ((newValue.M32 - oldValue.M32) * progress) + oldValue.M32); - } - } -} diff --git a/src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs deleted file mode 100644 index 59bf06ca261..00000000000 --- a/src/Avalonia.Visuals/Animation/Transitions/MatrixTransition.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Avalonia.Animation.Animators; - -namespace Avalonia.Animation -{ - /// - /// Transition class that handles with type. - /// - public class MatrixTransition : AnimatorDrivenTransition - { - } -} diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 7a56aa6fe27..af62375b526 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -15,13 +15,6 @@ namespace Avalonia #endif readonly struct Matrix : IEquatable { - static Matrix() - { -#if !BUILDTASK - Animation.Animation.RegisterAnimator(prop => typeof(Matrix).IsAssignableFrom(prop.PropertyType)); -#endif - } - private readonly double _m11; private readonly double _m12; private readonly double _m21; From 3d567425db6c7f6247ae70897a84b760bd7cbfdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 19:14:50 +0100 Subject: [PATCH 17/23] Revert --- src/Avalonia.Visuals/Matrix.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index af62375b526..8136f843dfd 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -1,8 +1,5 @@ using System; using System.Globalization; -#if !BUILDTASK -using Avalonia.Animation.Animators; -#endif using Avalonia.Utilities; namespace Avalonia From 5efb44806623c4420f42294fb574308ef4113680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 20:02:14 +0100 Subject: [PATCH 18/23] Add nullable annotations --- .../Media/Immutable/ImmutableConicGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableGradientBrush.cs | 4 ++-- src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs | 2 +- .../Media/Immutable/ImmutableLinearGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableRadialGradientBrush.cs | 2 +- .../Media/Immutable/ImmutableSolidColorBrush.cs | 4 ++-- src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs | 4 ++-- src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs | 2 +- src/Avalonia.Visuals/Media/TransformExtensions.cs | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs index 869262c7a46..4b97615c4cb 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs @@ -19,7 +19,7 @@ public class ImmutableConicGradientBrush : ImmutableGradientBrush, IConicGradien public ImmutableConicGradientBrush( IReadOnlyList gradientStops, double opacity = 1, - ImmutableTransform transform = null, + ImmutableTransform? transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, double angle = 0) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs index 78e46f52d00..f1e51687d07 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableGradientBrush.cs @@ -17,7 +17,7 @@ public abstract class ImmutableGradientBrush : IGradientBrush protected ImmutableGradientBrush( IReadOnlyList gradientStops, double opacity, - ImmutableTransform transform, + ImmutableTransform? transform, GradientSpreadMethod spreadMethod) { GradientStops = gradientStops; @@ -45,7 +45,7 @@ protected ImmutableGradientBrush(GradientBrush source) /// /// Gets the transform of the brush. /// - public ITransform Transform { get; } + public ITransform? Transform { get; } /// public GradientSpreadMethod SpreadMethod { get; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs index 41456b7f92b..2d4fe45c8e6 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs @@ -29,7 +29,7 @@ public ImmutableImageBrush( AlignmentY alignmentY = AlignmentY.Center, RelativeRect? destinationRect = null, double opacity = 1, - ImmutableTransform transform = null, + ImmutableTransform? transform = null, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs index 1c905c166e7..64c0f9b44e1 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableLinearGradientBrush.cs @@ -19,7 +19,7 @@ public class ImmutableLinearGradientBrush : ImmutableGradientBrush, ILinearGradi public ImmutableLinearGradientBrush( IReadOnlyList gradientStops, double opacity = 1, - ImmutableTransform transform = null, + ImmutableTransform? transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? startPoint = null, RelativePoint? endPoint = null) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs index 910e14faf74..3da4bdd8e9c 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableRadialGradientBrush.cs @@ -24,7 +24,7 @@ public class ImmutableRadialGradientBrush : ImmutableGradientBrush, IRadialGradi public ImmutableRadialGradientBrush( IReadOnlyList gradientStops, double opacity = 1, - ImmutableTransform transform = null, + ImmutableTransform? transform = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, RelativePoint? gradientOrigin = null, diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs index 8c6de8082ad..9cd453183aa 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs @@ -13,7 +13,7 @@ public class ImmutableSolidColorBrush : ISolidColorBrush, IEquatableThe color to use. /// The opacity of the brush. /// The transform of the brush. - public ImmutableSolidColorBrush(Color color, double opacity = 1, ImmutableTransform transform = null) + public ImmutableSolidColorBrush(Color color, double opacity = 1, ImmutableTransform? transform = null) { Color = color; Opacity = opacity; @@ -51,7 +51,7 @@ public ImmutableSolidColorBrush(ISolidColorBrush source) /// /// Gets the transform of the brush. /// - public ITransform Transform { get; } + public ITransform? Transform { get; } public bool Equals(ImmutableSolidColorBrush? other) { diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index ed722275f57..10197517333 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -26,7 +26,7 @@ protected ImmutableTileBrush( AlignmentY alignmentY, RelativeRect destinationRect, double opacity, - ImmutableTransform transform, + ImmutableTransform? transform, RelativeRect sourceRect, Stretch stretch, TileMode tileMode, @@ -76,7 +76,7 @@ protected ImmutableTileBrush(ITileBrush source) /// /// Gets the transform of the brush. /// - public ITransform Transform { get; } + public ITransform? Transform { get; } /// public RelativeRect SourceRect { get; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs index abec1704199..0fd29056600 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs @@ -29,7 +29,7 @@ public ImmutableVisualBrush( AlignmentY alignmentY = AlignmentY.Center, RelativeRect? destinationRect = null, double opacity = 1, - ImmutableTransform transform = null, + ImmutableTransform? transform = null, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, diff --git a/src/Avalonia.Visuals/Media/TransformExtensions.cs b/src/Avalonia.Visuals/Media/TransformExtensions.cs index c264d483cd6..2295632bd63 100644 --- a/src/Avalonia.Visuals/Media/TransformExtensions.cs +++ b/src/Avalonia.Visuals/Media/TransformExtensions.cs @@ -16,7 +16,7 @@ public static class TransformExtensions /// The result of calling if the transform is mutable, /// otherwise . /// - public static ImmutableTransform ToImmutable(this ITransform transform) + public static ImmutableTransform ToImmutable(this ITransform? transform) { Contract.Requires(transform != null); From 1228dc05e6215675ad6a89b1ea47a7f1c65450a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 20:07:35 +0100 Subject: [PATCH 19/23] Make nullable --- src/Avalonia.Visuals/Media/Brush.cs | 6 +++--- src/Avalonia.Visuals/Media/IBrush.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Brush.cs b/src/Avalonia.Visuals/Media/Brush.cs index c67cc39df7a..9d989979a7e 100644 --- a/src/Avalonia.Visuals/Media/Brush.cs +++ b/src/Avalonia.Visuals/Media/Brush.cs @@ -21,8 +21,8 @@ public abstract class Brush : Animatable, IMutableBrush /// /// Defines the property. /// - public static readonly StyledProperty TransformProperty = - AvaloniaProperty.Register(nameof(Transform)); + public static readonly StyledProperty TransformProperty = + AvaloniaProperty.Register(nameof(Transform)); /// public event EventHandler? Invalidated; @@ -45,7 +45,7 @@ public double Opacity /// /// Gets or sets the transform of the brush. /// - public ITransform Transform + public ITransform? Transform { get { return GetValue(TransformProperty); } set { SetValue(TransformProperty, value); } diff --git a/src/Avalonia.Visuals/Media/IBrush.cs b/src/Avalonia.Visuals/Media/IBrush.cs index c3d03fb35bd..830c066182e 100644 --- a/src/Avalonia.Visuals/Media/IBrush.cs +++ b/src/Avalonia.Visuals/Media/IBrush.cs @@ -16,6 +16,6 @@ public interface IBrush /// /// Gets the transform of the brush. /// - ITransform Transform { get; } + ITransform? Transform { get; } } } From 34833ad6b6ca1bf108aef4009b01da058c4edab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 20:20:59 +0100 Subject: [PATCH 20/23] Update TransformExtensions.cs --- src/Avalonia.Visuals/Media/TransformExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Media/TransformExtensions.cs b/src/Avalonia.Visuals/Media/TransformExtensions.cs index 2295632bd63..ccf2231ce20 100644 --- a/src/Avalonia.Visuals/Media/TransformExtensions.cs +++ b/src/Avalonia.Visuals/Media/TransformExtensions.cs @@ -16,9 +16,9 @@ public static class TransformExtensions /// The result of calling if the transform is mutable, /// otherwise . /// - public static ImmutableTransform ToImmutable(this ITransform? transform) + public static ImmutableTransform ToImmutable(this ITransform transform) { - Contract.Requires(transform != null); + _ = transform ?? throw new ArgumentNullException(nameof(transform)); return (transform as Transform)?.ToImmutable() ?? new ImmutableTransform(transform.Value); } From a5992d363a2344e208f6bb3edd8ebca821394c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 20:27:56 +0100 Subject: [PATCH 21/23] Fix --- .../Media/Immutable/ImmutableSolidColorBrush.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs index 9cd453183aa..9b1b2500ef4 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableSolidColorBrush.cs @@ -57,7 +57,7 @@ public bool Equals(ImmutableSolidColorBrush? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return Color.Equals(other.Color) && Opacity.Equals(other.Opacity) && (Transform == null && other.Transform == null ? true : Transform.Equals(other.Transform)); + return Color.Equals(other.Color) && Opacity.Equals(other.Opacity) && (Transform == null && other.Transform == null ? true : (Transform != null && Transform.Equals(other.Transform))); } public override bool Equals(object? obj) From 8b2730b0ea859da3852a598998f070af61f4a9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 20:28:24 +0100 Subject: [PATCH 22/23] Update ApiCompatBaseline.txt --- src/Avalonia.Visuals/ApiCompatBaseline.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index ee142fe5a7c..c02b9d8639c 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -41,6 +41,8 @@ MembersMustExist : Member 'public void Avalonia.Media.GlyphRun.GlyphIndices.set( MembersMustExist : Member 'public Avalonia.Utilities.ReadOnlySlice Avalonia.Media.GlyphRun.GlyphOffsets.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.GlyphRun.GlyphOffsets.set(Avalonia.Utilities.ReadOnlySlice)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.GlyphRun.GlyphTypeface.set(Avalonia.Media.GlyphTypeface)' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IBrush.Transform' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.ITransform Avalonia.Media.IBrush.Transform.get()' is present in the implementation but not in the contract. CannotSealType : Type 'Avalonia.Media.Pen' is actually (has the sealed modifier) sealed in the implementation but not sealed in the contract. MembersMustExist : Member 'protected void Avalonia.Media.Pen.AffectsRender(Avalonia.AvaloniaProperty[])' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Media.Pen.RaiseInvalidated(System.EventArgs)' does not exist in the implementation but it does exist in the contract. @@ -52,6 +54,10 @@ MembersMustExist : Member 'public void Avalonia.Media.TextHitTestResult.IsTraili MembersMustExist : Member 'public void Avalonia.Media.TextHitTestResult.TextPosition.set(System.Int32)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.Typeface..ctor(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.Typeface..ctor(System.String, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableConicGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Double)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'protected void Avalonia.Media.Immutable.ImmutableGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableLinearGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Nullable)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableRadialGradientBrush..ctor(System.Collections.Generic.IReadOnlyList, System.Double, Avalonia.Media.GradientSpreadMethod, System.Nullable, System.Nullable, System.Double)' does not exist in the implementation but it does exist in the contract. TypeCannotChangeClassification : Type 'Avalonia.Media.Immutable.ImmutableSolidColorBrush' is a 'class' in the implementation but is a 'struct' in the contract. MembersMustExist : Member 'public void Avalonia.Media.Immutable.ImmutableSolidColorBrush..ctor(Avalonia.Media.Color, System.Double)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Media.Immutable.ImmutableTileBrush..ctor(Avalonia.Media.AlignmentX, Avalonia.Media.AlignmentY, Avalonia.RelativeRect, System.Double, Avalonia.RelativeRect, Avalonia.Media.Stretch, Avalonia.Media.TileMode, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' does not exist in the implementation but it does exist in the contract. @@ -155,4 +161,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.GlyphR MembersMustExist : Member 'public Avalonia.Media.GlyphRun Avalonia.Platform.ITextShaperImpl.ShapeText(Avalonia.Utilities.ReadOnlySlice, Avalonia.Media.Typeface, System.Double, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Rendering.RendererBase.RenderFps(Avalonia.Platform.IDrawingContextImpl, Avalonia.Rect, System.Nullable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Utilities.ReadOnlySlice..ctor(System.ReadOnlyMemory, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -Total Issues: 153 +Total Issues: 162 From d2caf1241ff095260c957a7325f26e3c9fe05e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Thu, 10 Mar 2022 22:12:46 +0100 Subject: [PATCH 23/23] Add demo page for brushes with transforms --- samples/RenderDemo/MainWindow.xaml | 3 + samples/RenderDemo/Pages/BrushesPage.axaml | 71 +++++++++++++++++++ samples/RenderDemo/Pages/BrushesPage.axaml.cs | 18 +++++ 3 files changed, 92 insertions(+) create mode 100644 samples/RenderDemo/Pages/BrushesPage.axaml create mode 100644 samples/RenderDemo/Pages/BrushesPage.axaml.cs diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml index 4a8fb819cab..923b51814f5 100644 --- a/samples/RenderDemo/MainWindow.xaml +++ b/samples/RenderDemo/MainWindow.xaml @@ -66,5 +66,8 @@ + + + diff --git a/samples/RenderDemo/Pages/BrushesPage.axaml b/samples/RenderDemo/Pages/BrushesPage.axaml new file mode 100644 index 00000000000..9d5b6ee9872 --- /dev/null +++ b/samples/RenderDemo/Pages/BrushesPage.axaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/RenderDemo/Pages/BrushesPage.axaml.cs b/samples/RenderDemo/Pages/BrushesPage.axaml.cs new file mode 100644 index 00000000000..5852b72d9e1 --- /dev/null +++ b/samples/RenderDemo/Pages/BrushesPage.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace RenderDemo.Pages; + +public class BrushesPage : UserControl +{ + public BrushesPage() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} +