diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs
index da33347215..d56d2ae1ad 100644
--- a/src/Avalonia.SceneGraph/Media/DrawingContext.cs
+++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs
@@ -128,7 +128,8 @@ namespace Avalonia.Media
Opacity,
Clip,
MatrixContainer,
- GeometryClip
+ GeometryClip,
+ OpacityMask
}
public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default(Matrix))
@@ -156,6 +157,8 @@ namespace Avalonia.Media
_context._impl.PopOpacity();
else if (_type == PushedStateType.GeometryClip)
_context._impl.PopGeometryClip();
+ else if (_type == PushedStateType.OpacityMask)
+ _context._impl.PopOpacityMask();
else if (_type == PushedStateType.MatrixContainer)
{
var cont = _context._transformContainers.Pop();
@@ -201,6 +204,17 @@ namespace Avalonia.Media
return new PushedState(this, PushedState.PushedStateType.Opacity);
}
+ ///
+ /// Pushes an opacity mask.
+ ///
+ /// The opacity mask.
+ /// A disposable to undo the opacity mask.
+ public PushedState PushOpacityMask(IBrush mask, Rect bounds)
+ {
+ _impl.PushOpacityMask(mask, bounds);
+ return new PushedState(this, PushedState.PushedStateType.OpacityMask);
+ }
+
///
/// Pushes a matrix transformation.
///
diff --git a/src/Avalonia.SceneGraph/Media/IDrawingContext.cs b/src/Avalonia.SceneGraph/Media/IDrawingContext.cs
index a798726cca..c63abc160f 100644
--- a/src/Avalonia.SceneGraph/Media/IDrawingContext.cs
+++ b/src/Avalonia.SceneGraph/Media/IDrawingContext.cs
@@ -81,6 +81,10 @@ namespace Avalonia.Media
void PopOpacity();
+ void PushOpacityMask(IBrush mask, Rect bounds);
+
+ void PopOpacityMask();
+
///
/// Pushes a clip geometry.
///
diff --git a/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs b/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs
index b26d825064..1f784f0017 100644
--- a/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs
+++ b/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs
@@ -120,6 +120,7 @@ namespace Avalonia.Rendering
using (context.PushOpacity(opacity))
using (clipToBounds ? context.PushClip(bounds) : default(DrawingContext.PushedState))
using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default(DrawingContext.PushedState))
+ using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, clipToBounds ? bounds : clipRect) : default(DrawingContext.PushedState))
using (context.PushTransformContainer())
{
visual.Render(context);
diff --git a/src/Avalonia.SceneGraph/Visual.cs b/src/Avalonia.SceneGraph/Visual.cs
index 8bdbfecb4a..82ce1b85c7 100644
--- a/src/Avalonia.SceneGraph/Visual.cs
+++ b/src/Avalonia.SceneGraph/Visual.cs
@@ -57,6 +57,12 @@ namespace Avalonia
public static readonly StyledProperty OpacityProperty =
AvaloniaProperty.Register(nameof(Opacity), 1);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty OpacityMaskProperty =
+ AvaloniaProperty.Register(nameof(OpacityMask));
+
///
/// Defines the property.
///
@@ -168,6 +174,16 @@ namespace Avalonia
set { SetValue(OpacityProperty, value); }
}
+
+ ///
+ /// Gets the opacity mask of the scene graph node.
+ ///
+ public IBrush OpacityMask
+ {
+ get { return GetValue(OpacityMaskProperty); }
+ set { SetValue(OpacityMaskProperty, value); }
+ }
+
///
/// Gets the render transform of the scene graph node.
///
diff --git a/src/Avalonia.SceneGraph/VisualTree/IVisual.cs b/src/Avalonia.SceneGraph/VisualTree/IVisual.cs
index fb4416f78e..9b4a4fccf5 100644
--- a/src/Avalonia.SceneGraph/VisualTree/IVisual.cs
+++ b/src/Avalonia.SceneGraph/VisualTree/IVisual.cs
@@ -66,6 +66,11 @@ namespace Avalonia.VisualTree
///
double Opacity { get; set; }
+ ///
+ /// Gets or sets the opacity mask of the scene graph node.
+ ///
+ IBrush OpacityMask { get; set; }
+
///
/// Gets or sets the render transform of the scene graph node.
///
diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs
index 699a5ba18b..e0c75b44e1 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs
@@ -350,5 +350,25 @@ namespace Avalonia.Direct2D1.Media
{
PopLayer();
}
+
+ public void PushOpacityMask(IBrush mask, Rect bounds)
+ {
+ var parameters = new LayerParameters
+ {
+ ContentBounds = PrimitiveExtensions.RectangleInfinite,
+ MaskTransform = PrimitiveExtensions.Matrix3x2Identity,
+ Opacity = 1,
+ OpacityBrush = CreateBrush(mask, bounds.Size).PlatformBrush
+ };
+ var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_renderTarget);
+ _renderTarget.PushLayer(ref parameters, layer);
+
+ _layers.Push(layer);
+ }
+
+ public void PopOpacityMask()
+ {
+ PopLayer();
+ }
}
}