From 5e0f12235f5cf36afcec54562719df4beb737454 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 27 May 2016 22:24:46 -0400 Subject: [PATCH] Added the platform independent interface and the Direct2D1 implementation of opacity masks. --- .../Media/DrawingContext.cs | 16 ++++++++++++++- .../Media/IDrawingContext.cs | 4 ++++ .../Rendering/RendererMixin.cs | 1 + src/Avalonia.SceneGraph/Visual.cs | 16 +++++++++++++++ src/Avalonia.SceneGraph/VisualTree/IVisual.cs | 5 +++++ .../Media/DrawingContext.cs | 20 +++++++++++++++++++ 6 files changed, 61 insertions(+), 1 deletion(-) 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(); + } } }