diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index 48bba84da7..5659bda1d9 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -208,7 +208,16 @@ namespace Avalonia.Rendering.SceneGraph /// public void PopOpacity() { - // TODO: Implement + var next = NextDrawAs(); + + if (next == null || !next.Equals(null)) + { + Add(new OpacityNode()); + } + else + { + ++_drawOperationindex; + } } /// @@ -232,7 +241,16 @@ namespace Avalonia.Rendering.SceneGraph /// public void PushOpacity(double opacity) { - // TODO: Implement + var next = NextDrawAs(); + + if (next == null || !next.Equals(opacity)) + { + Add(new OpacityNode(opacity)); + } + else + { + ++_drawOperationindex; + } } /// diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/OpacityNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/OpacityNode.cs new file mode 100644 index 0000000000..097bf15828 --- /dev/null +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/OpacityNode.cs @@ -0,0 +1,64 @@ +using System; +using Avalonia.Platform; + +namespace Avalonia.Rendering.SceneGraph +{ + /// + /// A node in the scene graph which represents an opacity push or pop. + /// + internal class OpacityNode : IDrawOperation + { + /// + /// Initializes a new instance of the class that represents an + /// opacity push. + /// + /// The opacity to push. + public OpacityNode(double opacity) + { + Opacity = opacity; + } + + /// + /// Initializes a new instance of the class that represents an + /// opacity pop. + /// + public OpacityNode() + { + } + + /// + public Rect Bounds => Rect.Empty; + + /// + /// Gets the opacity to be pushed or null if the operation represents a pop. + /// + public double? Opacity { get; } + + /// + public bool HitTest(Point p) => false; + + /// + /// Determines if this draw operation equals another. + /// + /// The opacity of the other draw operation. + /// True if the draw operations are the same, otherwise false. + /// + /// The properties of the other draw operation are passed in as arguments to prevent + /// allocation of a not-yet-constructed draw operation object. + /// + public bool Equals(double? opacity) => Opacity == opacity; + + /// + public void Render(IDrawingContextImpl context) + { + if (Opacity.HasValue) + { + context.PushOpacity(Opacity.Value); + } + else + { + context.PopOpacity(); + } + } + } +} diff --git a/tests/TestFiles/Cairo/Controls/CustomRender/Opacity.expected.png b/tests/TestFiles/Cairo/Controls/CustomRender/Opacity.expected.png new file mode 100644 index 0000000000..159f428344 Binary files /dev/null and b/tests/TestFiles/Cairo/Controls/CustomRender/Opacity.expected.png differ diff --git a/tests/TestFiles/Skia/Controls/CustomRender/Opacity.expected.png b/tests/TestFiles/Skia/Controls/CustomRender/Opacity.expected.png new file mode 100644 index 0000000000..399d502a56 Binary files /dev/null and b/tests/TestFiles/Skia/Controls/CustomRender/Opacity.expected.png differ