diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml
index 6653e52d49..48fb468baa 100644
--- a/api/Avalonia.nupkg.xml
+++ b/api/Avalonia.nupkg.xml
@@ -241,6 +241,12 @@
baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
current/Avalonia/lib/net10.0/Avalonia.Base.dll
+
+ CP0006
+ P:Avalonia.Media.IBrush.RelativeTransform
+ baseline/Avalonia/lib/net10.0/Avalonia.Base.dll
+ current/Avalonia/lib/net10.0/Avalonia.Base.dll
+
CP0006
P:Avalonia.Media.IImageBrushSource.Bitmap
@@ -301,6 +307,12 @@
baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
current/Avalonia/lib/net8.0/Avalonia.Base.dll
+
+ CP0006
+ P:Avalonia.Media.IBrush.RelativeTransform
+ baseline/Avalonia/lib/net8.0/Avalonia.Base.dll
+ current/Avalonia/lib/net8.0/Avalonia.Base.dll
+
CP0006
P:Avalonia.Media.IImageBrushSource.Bitmap
diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
index cb64e11919..7fc05d8e4f 100644
--- a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
+++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs
@@ -38,7 +38,8 @@ namespace Avalonia.Animation.Animators
s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center),
s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin),
s_relativeScalarAnimator.Interpolate(progress, oldRadial.RadiusX, newRadial.RadiusX),
- s_relativeScalarAnimator.Interpolate(progress, oldRadial.RadiusY, newRadial.RadiusY)
+ s_relativeScalarAnimator.Interpolate(progress, oldRadial.RadiusY, newRadial.RadiusY),
+ InterpolateTransform(progress, oldValue.RelativeTransform, newValue.RelativeTransform)
);
case IConicGradientBrush oldConic when newValue is IConicGradientBrush newConic:
@@ -49,7 +50,8 @@ namespace Avalonia.Animation.Animators
s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
oldValue.SpreadMethod,
s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center),
- s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle));
+ s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle),
+ InterpolateTransform(progress, oldValue.RelativeTransform, newValue.RelativeTransform));
case ILinearGradientBrush oldLinear when newValue is ILinearGradientBrush newLinear:
return new ImmutableLinearGradientBrush(
@@ -59,7 +61,8 @@ namespace Avalonia.Animation.Animators
s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin),
oldValue.SpreadMethod,
s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint),
- s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint));
+ s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint),
+ InterpolateTransform(progress, oldValue.RelativeTransform, newValue.RelativeTransform));
default:
return progress >= 0.5 ? newValue : oldValue;
diff --git a/src/Avalonia.Base/Media/Brush.cs b/src/Avalonia.Base/Media/Brush.cs
index fb9dca26c9..dfebb87216 100644
--- a/src/Avalonia.Base/Media/Brush.cs
+++ b/src/Avalonia.Base/Media/Brush.cs
@@ -33,6 +33,12 @@ namespace Avalonia.Media
public static readonly StyledProperty TransformOriginProperty =
AvaloniaProperty.Register(nameof(TransformOrigin));
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty RelativeTransformProperty =
+ AvaloniaProperty.Register(nameof(RelativeTransform));
+
///
/// Gets or sets the opacity of the brush.
///
@@ -60,6 +66,13 @@ namespace Avalonia.Media
set => SetValue(TransformOriginProperty, value);
}
+ ///
+ public ITransform? RelativeTransform
+ {
+ get => GetValue(RelativeTransformProperty);
+ set => SetValue(RelativeTransformProperty, value);
+ }
+
///
/// Parses a brush string.
///
@@ -90,7 +103,7 @@ namespace Avalonia.Media
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- if (change.Property == TransformProperty)
+ if (change.Property == TransformProperty || change.Property == RelativeTransformProperty)
_resource.ProcessPropertyChangeNotification(change);
RegisterForSerialization();
@@ -117,8 +130,10 @@ namespace Avalonia.Media
private protected virtual void OnReferencedFromCompositor(Compositor c)
{
- if (Transform is ICompositionRenderResource resource)
- resource.AddRefOnCompositor(c);
+ if (Transform is ICompositionRenderResource transform)
+ transform.AddRefOnCompositor(c);
+ if (RelativeTransform is ICompositionRenderResource relativeTransform)
+ relativeTransform.AddRefOnCompositor(c);
}
void ICompositionRenderResource.ReleaseOnCompositor(Compositor c)
@@ -129,15 +144,18 @@ namespace Avalonia.Media
protected virtual void OnUnreferencedFromCompositor(Compositor c)
{
- if (Transform is ICompositionRenderResource resource)
- resource.ReleaseOnCompositor(c);
+ if (Transform is ICompositionRenderResource transform)
+ transform.ReleaseOnCompositor(c);
+ if (RelativeTransform is ICompositionRenderResource relativeTransform)
+ relativeTransform.ReleaseOnCompositor(c);
}
SimpleServerObject? ICompositorSerializable.TryGetServer(Compositor c) => _resource.TryGetForCompositor(c);
private protected virtual void SerializeChanges(Compositor c, BatchStreamWriter writer)
{
- ServerCompositionSimpleBrush.SerializeAllChanges(writer, Opacity, TransformOrigin, Transform.GetServer(c));
+ ServerCompositionSimpleBrush.SerializeAllChanges(writer, Opacity, TransformOrigin, Transform.GetServer(c),
+ RelativeTransform.GetServer(c));
}
void ICompositorSerializable.SerializeChanges(Compositor c, BatchStreamWriter writer) => SerializeChanges(c, writer);
diff --git a/src/Avalonia.Base/Media/IBrush.cs b/src/Avalonia.Base/Media/IBrush.cs
index e32894f67c..260edacf71 100644
--- a/src/Avalonia.Base/Media/IBrush.cs
+++ b/src/Avalonia.Base/Media/IBrush.cs
@@ -24,5 +24,14 @@ namespace Avalonia.Media
/// Gets the origin of the brushes
///
RelativePoint TransformOrigin { get; }
+
+ ///
+ /// Gets the transform applied in the relative coordinate space of the area being painted:
+ /// the unit square (0,0)-(1,1) maps onto the painted bounds, this transform applies inside
+ /// that space, and follows in target space. It lets a single brush
+ /// express a bounds-dependent transform - an SVG gradientTransform in objectBoundingBox
+ /// units, for example - without baking any one consumer's bounds into a matrix.
+ ///
+ ITransform? RelativeTransform { get; }
}
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs
index 70232f0a63..7308142078 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs
@@ -17,6 +17,7 @@ namespace Avalonia.Media.Immutable
/// The spread method.
/// The center point for the gradient.
/// The starting angle for the gradient.
+ // TODO13: remove, folding relativeTransform into the overload below as an optional parameter.
public ImmutableConicGradientBrush(
IReadOnlyList gradientStops,
double opacity = 1,
@@ -25,7 +26,32 @@ namespace Avalonia.Media.Immutable
GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad,
RelativePoint? center = null,
double angle = 0)
- : base(gradientStops, opacity, transform, transformOrigin, spreadMethod)
+ : this(gradientStops, opacity, transform, transformOrigin, spreadMethod, center, angle, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The gradient stops.
+ /// The opacity of the brush.
+ /// The transform of the brush.
+ /// The transform origin of the brush
+ /// The spread method.
+ /// The center point for the gradient.
+ /// The starting angle for the gradient.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
+ public ImmutableConicGradientBrush(
+ IReadOnlyList gradientStops,
+ double opacity,
+ ImmutableTransform? transform,
+ RelativePoint? transformOrigin,
+ GradientSpreadMethod spreadMethod,
+ RelativePoint? center,
+ double angle,
+ ImmutableTransform? relativeTransform)
+ : base(gradientStops, opacity, transform, transformOrigin, spreadMethod, relativeTransform)
{
Center = center ?? RelativePoint.Center;
Angle = angle;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
index c86d86d20a..69d8ba74a2 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs
@@ -15,18 +15,41 @@ namespace Avalonia.Media.Immutable
/// The transform of the brush.
/// The transform origin of the brush
/// The spread method.
+ // TODO13: remove, folding relativeTransform into the overload below as an optional parameter.
protected ImmutableGradientBrush(
IReadOnlyList gradientStops,
double opacity,
ImmutableTransform? transform,
RelativePoint? transformOrigin,
GradientSpreadMethod spreadMethod)
+ : this(gradientStops, opacity, transform, transformOrigin, spreadMethod, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The gradient stops.
+ /// The opacity of the brush.
+ /// The transform of the brush.
+ /// The transform origin of the brush
+ /// The spread method.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
+ protected ImmutableGradientBrush(
+ IReadOnlyList gradientStops,
+ double opacity,
+ ImmutableTransform? transform,
+ RelativePoint? transformOrigin,
+ GradientSpreadMethod spreadMethod,
+ ImmutableTransform? relativeTransform)
{
GradientStops = gradientStops;
Opacity = opacity;
Transform = transform;
TransformOrigin = transformOrigin.HasValue ? transformOrigin.Value : RelativePoint.TopLeft;
SpreadMethod = spreadMethod;
+ RelativeTransform = relativeTransform;
}
///
@@ -35,9 +58,8 @@ namespace Avalonia.Media.Immutable
/// 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.TransformOrigin, source.SpreadMethod)
+ source.TransformOrigin, source.SpreadMethod, source.RelativeTransform?.ToImmutable())
{
-
}
///
@@ -58,5 +80,8 @@ namespace Avalonia.Media.Immutable
///
public GradientSpreadMethod SpreadMethod { get; }
+
+ ///
+ public ITransform? RelativeTransform { get; }
}
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
index ce4ba5d140..19bac465bf 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs
@@ -22,6 +22,8 @@ namespace Avalonia.Media.Immutable
/// How the source rectangle will be stretched to fill the destination rect.
///
/// The tile mode.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
public ImmutableImageBrush(
Bitmap? source,
AlignmentX alignmentX = AlignmentX.Center,
@@ -32,7 +34,8 @@ namespace Avalonia.Media.Immutable
RelativePoint transformOrigin = default,
RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform,
- TileMode tileMode = TileMode.None)
+ TileMode tileMode = TileMode.None,
+ ImmutableTransform? relativeTransform = null)
: base(
alignmentX,
alignmentY,
@@ -42,7 +45,8 @@ namespace Avalonia.Media.Immutable
transformOrigin,
sourceRect ?? RelativeRect.Fill,
stretch,
- tileMode)
+ tileMode,
+ relativeTransform)
{
Source = source;
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs
index 3c26b5c009..17b2df93e1 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs
@@ -17,6 +17,7 @@ namespace Avalonia.Media.Immutable
/// The spread method.
/// The start point for the gradient.
/// The end point for the gradient.
+ // TODO13: remove, folding relativeTransform into the overload below as an optional parameter.
public ImmutableLinearGradientBrush(
IReadOnlyList gradientStops,
double opacity = 1,
@@ -25,7 +26,32 @@ namespace Avalonia.Media.Immutable
GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad,
RelativePoint? startPoint = null,
RelativePoint? endPoint = null)
- : base(gradientStops, opacity, transform, transformOrigin, spreadMethod)
+ : this(gradientStops, opacity, transform, transformOrigin, spreadMethod, startPoint, endPoint, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The gradient stops.
+ /// The opacity of the brush.
+ /// The transform of the brush.
+ /// The transform origin of the brush
+ /// The spread method.
+ /// The start point for the gradient.
+ /// The end point for the gradient.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
+ public ImmutableLinearGradientBrush(
+ IReadOnlyList gradientStops,
+ double opacity,
+ ImmutableTransform? transform,
+ RelativePoint? transformOrigin,
+ GradientSpreadMethod spreadMethod,
+ RelativePoint? startPoint,
+ RelativePoint? endPoint,
+ ImmutableTransform? relativeTransform)
+ : base(gradientStops, opacity, transform, transformOrigin, spreadMethod, relativeTransform)
{
StartPoint = startPoint ?? RelativePoint.TopLeft;
EndPoint = endPoint ?? RelativePoint.BottomRight;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs
index 3b210874d9..dd77d9d2f7 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs
@@ -41,6 +41,7 @@ namespace Avalonia.Media.Immutable
}
+ // TODO13: remove, folding relativeTransform into the overload below as an optional parameter.
public ImmutableRadialGradientBrush(
IReadOnlyList gradientStops,
double opacity = 1,
@@ -52,7 +53,39 @@ namespace Avalonia.Media.Immutable
RelativeScalar? radiusX = null,
RelativeScalar? radiusY = null
)
- : base(gradientStops, opacity, transform, transformOrigin, spreadMethod)
+ : this(gradientStops, opacity, transform, transformOrigin, spreadMethod, center, gradientOrigin,
+ radiusX, radiusY, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The gradient stops.
+ /// The opacity of the brush.
+ /// The transform of the brush.
+ /// The transform origin of the brush
+ /// The spread method.
+ /// The start point for the gradient.
+ ///
+ /// The location of the two-dimensional focal point that defines the beginning of the gradient.
+ ///
+ /// The horizontal radius of the outermost circle.
+ /// The vertical radius of the outermost circle.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
+ public ImmutableRadialGradientBrush(
+ IReadOnlyList gradientStops,
+ double opacity,
+ ImmutableTransform? transform,
+ RelativePoint? transformOrigin,
+ GradientSpreadMethod spreadMethod,
+ RelativePoint? center,
+ RelativePoint? gradientOrigin,
+ RelativeScalar? radiusX,
+ RelativeScalar? radiusY,
+ ImmutableTransform? relativeTransform)
+ : base(gradientStops, opacity, transform, transformOrigin, spreadMethod, relativeTransform)
{
Center = center ?? RelativePoint.Center;
GradientOrigin = gradientOrigin ?? RelativePoint.Center;
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
index c88aea7e9e..d074963f0f 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs
@@ -13,11 +13,30 @@ namespace Avalonia.Media.Immutable
/// The color to use.
/// The opacity of the brush.
/// The transform of the brush.
+ // TODO13: remove, folding relativeTransform into the overload below as an optional parameter.
public ImmutableSolidColorBrush(Color color, double opacity = 1, ImmutableTransform? transform = null)
+ : this(color, opacity, transform, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color to use.
+ /// The opacity of the brush.
+ /// The transform of the brush.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
+ public ImmutableSolidColorBrush(
+ Color color,
+ double opacity,
+ ImmutableTransform? transform,
+ ImmutableTransform? relativeTransform)
{
Color = color;
Opacity = opacity;
Transform = transform;
+ RelativeTransform = relativeTransform;
}
///
@@ -34,7 +53,8 @@ namespace Avalonia.Media.Immutable
///
/// The brush from which this brush's properties should be copied.
public ImmutableSolidColorBrush(ISolidColorBrush source)
- : this(source.Color, source.Opacity, source.Transform?.ToImmutable())
+ : this(source.Color, source.Opacity, source.Transform?.ToImmutable(),
+ source.RelativeTransform?.ToImmutable())
{
}
@@ -58,11 +78,15 @@ namespace Avalonia.Media.Immutable
///
public RelativePoint TransformOrigin { get; }
+ ///
+ public ITransform? RelativeTransform { 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) && (Transform == null && other.Transform == null ? true : (Transform != null && Transform.Equals(other.Transform)));
+ return Color.Equals(other.Color) && Opacity.Equals(other.Opacity)
+ && Equals(Transform, other.Transform) && Equals(RelativeTransform, other.RelativeTransform);
}
public override bool Equals(object? obj)
@@ -74,7 +98,8 @@ namespace Avalonia.Media.Immutable
{
unchecked
{
- return (Color.GetHashCode() * 397) ^ Opacity.GetHashCode() ^ (Transform is null ? 0 : Transform.GetHashCode());
+ return (Color.GetHashCode() * 397) ^ Opacity.GetHashCode() ^ (Transform is null ? 0 : Transform.GetHashCode())
+ ^ (RelativeTransform is null ? 0 : RelativeTransform.GetHashCode());
}
}
diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
index df6d14ecf9..5bf317db08 100644
--- a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
+++ b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs
@@ -21,6 +21,8 @@ namespace Avalonia.Media.Immutable
/// How the source rectangle will be stretched to fill the destination rect.
///
/// The tile mode.
+ /// The transform of the brush in the relative coordinate
+ /// space of the area being painted, applied before .
private protected ImmutableTileBrush(
AlignmentX alignmentX,
AlignmentY alignmentY,
@@ -30,7 +32,8 @@ namespace Avalonia.Media.Immutable
RelativePoint transformOrigin,
RelativeRect sourceRect,
Stretch stretch,
- TileMode tileMode)
+ TileMode tileMode,
+ ImmutableTransform? relativeTransform)
{
AlignmentX = alignmentX;
AlignmentY = alignmentY;
@@ -41,6 +44,7 @@ namespace Avalonia.Media.Immutable
SourceRect = sourceRect;
Stretch = stretch;
TileMode = tileMode;
+ RelativeTransform = relativeTransform;
}
///
@@ -57,7 +61,8 @@ namespace Avalonia.Media.Immutable
source.TransformOrigin,
source.SourceRect,
source.Stretch,
- source.TileMode)
+ source.TileMode,
+ source.RelativeTransform?.ToImmutable())
{
}
@@ -91,5 +96,8 @@ namespace Avalonia.Media.Immutable
///
public TileMode TileMode { get; }
+
+ ///
+ public ITransform? RelativeTransform { get; }
}
}
diff --git a/src/Avalonia.Base/Rendering/Composition/Brushes/ServerCompositionBrush.cs b/src/Avalonia.Base/Rendering/Composition/Brushes/ServerCompositionBrush.cs
index e537db319a..1588bd3a36 100644
--- a/src/Avalonia.Base/Rendering/Composition/Brushes/ServerCompositionBrush.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Brushes/ServerCompositionBrush.cs
@@ -9,6 +9,7 @@ namespace Avalonia.Rendering.Composition.Server;
internal partial class ServerCompositionBrush : IBrush
{
ITransform? IBrush.Transform => Transform;
+ ITransform? IBrush.RelativeTransform => RelativeTransform;
}
internal partial class ServerCompositionGradientBrush : ServerCompositionBrush, IGradientBrush
diff --git a/src/Avalonia.Base/Rendering/Composition/Brushes/ServerSimpleCompositionBrush.cs b/src/Avalonia.Base/Rendering/Composition/Brushes/ServerSimpleCompositionBrush.cs
index d15b76cca5..c4cd282dc4 100644
--- a/src/Avalonia.Base/Rendering/Composition/Brushes/ServerSimpleCompositionBrush.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Brushes/ServerSimpleCompositionBrush.cs
@@ -12,6 +12,7 @@ namespace Avalonia.Rendering.Composition.Server
internal partial class ServerCompositionSimpleBrush : IBrush
{
ITransform? IBrush.Transform => Transform;
+ ITransform? IBrush.RelativeTransform => RelativeTransform;
}
internal class ServerCompositionSimpleGradientBrush : ServerCompositionSimpleBrush, IGradientBrush
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionRenderDataSceneBrushContent.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionRenderDataSceneBrushContent.cs
index a8b9da743a..ea27912359 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionRenderDataSceneBrushContent.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/CompositionRenderDataSceneBrushContent.cs
@@ -25,6 +25,7 @@ internal class CompositionRenderDataSceneBrushContent : ISceneBrushContent
public double Opacity => Brush.Opacity;
public ITransform? Transform => Brush.Transform;
public RelativePoint TransformOrigin => Brush.TransformOrigin;
+ public ITransform? RelativeTransform => Brush.RelativeTransform;
public void Dispose()
{
diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/ImmediateRenderDataSceneBrushContent.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/ImmediateRenderDataSceneBrushContent.cs
index e3b43655bc..e84083783f 100644
--- a/src/Avalonia.Base/Rendering/Composition/Drawing/ImmediateRenderDataSceneBrushContent.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Drawing/ImmediateRenderDataSceneBrushContent.cs
@@ -22,6 +22,7 @@ internal class ImmediateRenderDataSceneBrushContent : ISceneBrushContent
public double Opacity => Brush.Opacity;
public ITransform? Transform => Brush.Transform;
public RelativePoint TransformOrigin => Brush.TransformOrigin;
+ public ITransform? RelativeTransform => Brush.RelativeTransform;
public void Dispose()
{
diff --git a/src/Avalonia.Base/composition-schema.xml b/src/Avalonia.Base/composition-schema.xml
index 1256355fa4..aaf958efdf 100644
--- a/src/Avalonia.Base/composition-schema.xml
+++ b/src/Avalonia.Base/composition-schema.xml
@@ -91,6 +91,7 @@
+