Skip to content

Commit

Permalink
Enable VisualBrush to be used as Visual's OpacityMask (#17072)
Browse files Browse the repository at this point in the history
* Enable VisualBrush to be used as Visual's OpacityMask

* Add missing test file

---------

Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com>
  • Loading branch information
kekekeks and Gillibald committed Sep 20, 2024
1 parent 85fff4a commit 2299d96
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 6 deletions.
21 changes: 19 additions & 2 deletions src/Avalonia.Base/Rendering/Composition/Visual.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Numerics;
using Avalonia.Media;
using Avalonia.Rendering.Composition.Drawing;
using Avalonia.VisualTree;

namespace Avalonia.Rendering.Composition
Expand All @@ -25,9 +26,25 @@ public IBrush? OpacityMask
get => _opacityMask;
set
{
if (_opacityMask == value)
if (ReferenceEquals(_opacityMask, value))
return;
OpacityMaskBrush = (_opacityMask = value)?.ToImmutable();

// Release the previous compositor-resource based brush
if (_opacityMask is ICompositionRenderResource<IBrush> oldCompositorBrush)
{
oldCompositorBrush.ReleaseOnCompositor(Compositor);
_opacityMask = null;
OpacityMaskBrushTransportField = null;
}

if (value is ICompositionRenderResource<IBrush> newCompositorBrush)
{
newCompositorBrush.AddRefOnCompositor(Compositor);
OpacityMaskBrushTransportField = newCompositorBrush.GetForCompositor(Compositor);
_opacityMask = value;
}
else
OpacityMaskBrushTransportField = (_opacityMask = value)?.ToImmutable();
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/Avalonia.Base/Visual.Composition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal virtual void DetachFromCompositor()
CompositionVisual.Children.Remove(ChildCompositionVisual);

CompositionVisual.DrawList = null;
CompositionVisual.OpacityMask = null;
CompositionVisual = null;
}
}
Expand Down Expand Up @@ -141,7 +142,7 @@ internal virtual void SynchronizeCompositionProperties()
comp.Clip = Clip?.PlatformImpl;

if (!Equals(comp.OpacityMask, OpacityMask))
comp.OpacityMask = OpacityMask?.ToImmutable();
comp.OpacityMask = OpacityMask;

if (!comp.Effect.EffectEquals(Effect))
comp.Effect = Effect?.ToImmutable();
Expand Down
2 changes: 1 addition & 1 deletion src/Avalonia.Base/composition-schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<Property Name="TransformMatrix" Type="Avalonia.Matrix" DefaultValue="Avalonia.Matrix.Identity" Animated="true" Internal="true"/>
<Property Name="AdornedVisual" Type="CompositionVisual?" Internal="true" />
<Property Name="AdornerIsClipped" Type="bool" Internal="true" />
<Property Name="OpacityMaskBrush" Type="Avalonia.Media.IImmutableBrush?" Internal="true" />
<Property Name="OpacityMaskBrush" ClientName="OpacityMaskBrushTransportField" Type="Avalonia.Media.IBrush?" Private="true" />
<Property Name="Effect" Type="Avalonia.Media.IImmutableEffect?" Internal="true" />
<Property Name="RenderOptions" Type="Avalonia.Media.RenderOptions" />
</Object>
Expand Down
4 changes: 4 additions & 0 deletions src/tools/DevGenerators/CompositionGenerator/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public class GProperty
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string ClientName { get; set; }
[XmlAttribute]
public string Type { get; set; }
[XmlAttribute]
public string DefaultValue { get; set; }
Expand All @@ -116,6 +118,8 @@ public class GProperty
public bool InternalSet { get; set; }
[XmlAttribute]
public bool Internal { get; set; }
[XmlAttribute]
public bool Private { get; set; }
}

public class GAnimationType
Expand Down
5 changes: 3 additions & 2 deletions src/tools/DevGenerators/CompositionGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,9 @@ private static ClassDeclarationSyntax GenerateClientProperty(ClassDeclarationSyn
var fieldName = PropertyBackingFieldName(prop);
return client
.AddMembers(DeclareField(prop.Type, fieldName))
.AddMembers(PropertyDeclaration(propType, prop.Name)
.AddModifiers(prop.Internal ? SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword)
.AddMembers(PropertyDeclaration(propType, prop.ClientName ?? prop.Name)
.AddModifiers(
prop.Private ? SyntaxKind.PrivateKeyword : prop.Internal ? SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword)
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration,
Block(ReturnStatement(IdentifierName(fieldName)))),
Expand Down
52 changes: 52 additions & 0 deletions tests/Avalonia.RenderTests/Media/VisualBrushTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -710,5 +710,57 @@ public async Task VisualBrush_Is_Properly_Mapped(bool relative)
await RenderToFile(new RelativePointTestPrimitivesHelper(brush), testName);
CompareImages(testName);
}


[Fact]
public async Task VisualBrush_Should_Be_Usable_As_Opacity_Mask()
{
var target = new Border()
{
Padding = new Thickness(8),
Width = 920,
Height = 920,
Background = Brushes.Magenta,
OpacityMask = new VisualBrush
{
Stretch = Stretch.Fill,
TileMode = TileMode.None,

Visual = new Border()
{
Width = 200,
Height = 200,
Padding = new Thickness(20),
Child = new Grid()
{

ColumnDefinitions = ColumnDefinitions.Parse("*,*,*"),
RowDefinitions = RowDefinitions.Parse("*,*,*"),
Children =
{
new Border()
{
Background = Brushes.Aqua,
},
new Border()
{
[Grid.ColumnProperty] = 1,
[Grid.RowProperty] = 2,
Background = Brushes.Aqua,
},
new Border()
{
[Grid.ColumnProperty] = 3,
Background = Brushes.Aqua,
},
}
},
}
}
};

await RenderToFile(target);
CompareImages();
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2299d96

Please sign in to comment.