Browse Source

Fix PushOpacity when ClipToBounds is false

pull/11394/head
Benedikt Stebner 3 years ago
parent
commit
101cdc5257
  1. 7
      src/Avalonia.Base/Media/DrawingContext.cs
  2. 22
      src/Avalonia.Base/Media/DrawingGroup.cs
  3. 4
      src/Avalonia.Base/Media/PlatformDrawingContext.cs
  4. 2
      src/Avalonia.Base/Platform/IDrawingContextImpl.cs
  5. 5
      src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs
  6. 7
      src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs
  7. 2
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
  8. 2
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
  9. 2
      src/Avalonia.Base/Rendering/ImmediateRenderer.cs
  10. 2
      src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  11. 14
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  12. 15
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  13. 2
      tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs

7
src/Avalonia.Base/Media/DrawingContext.cs

@ -360,16 +360,15 @@ namespace Avalonia.Media
/// Pushes an opacity value.
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <param name="bounds">The bounds.</param>
/// <returns>A disposable used to undo the opacity.</returns>
public PushedState PushOpacity(double opacity, Rect bounds)
public PushedState PushOpacity(double opacity)
{
PushOpacityCore(opacity, bounds);
PushOpacityCore(opacity);
_states ??= StateStackPool.Get();
_states.Push(new RestoreState(this, RestoreState.PushedStateType.Opacity));
return new PushedState(this);
}
protected abstract void PushOpacityCore(double opacity, Rect bounds);
protected abstract void PushOpacityCore(double opacity);
/// <summary>
/// Pushes an opacity mask.

22
src/Avalonia.Base/Media/DrawingGroup.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Avalonia.Media.Imaging;
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
@ -72,9 +71,8 @@ namespace Avalonia.Media
internal override void DrawCore(DrawingContext context)
{
var bounds = GetBounds();
using (context.PushTransform(Transform?.Value ?? Matrix.Identity))
using (context.PushOpacity(Opacity, bounds))
using (context.PushOpacity(Opacity))
using (ClipGeometry != null ? context.PushGeometryClip(ClipGeometry) : default)
using (OpacityMask != null ? context.PushOpacityMask(OpacityMask, bounds) : default)
{
@ -178,22 +176,30 @@ namespace Avalonia.Media
protected override void PushClipCore(Rect rect)
{
throw new NotImplementedException();
var drawingGroup = PushNewDrawingGroup();
drawingGroup.ClipGeometry = new RectangleGeometry(rect);
}
protected override void PushGeometryClipCore(Geometry clip)
{
throw new NotImplementedException();
var drawingGroup = PushNewDrawingGroup();
drawingGroup.ClipGeometry = clip;
}
protected override void PushOpacityCore(double opacity, Rect bounds)
protected override void PushOpacityCore(double opacity)
{
throw new NotImplementedException();
var drawingGroup = PushNewDrawingGroup();
drawingGroup.Opacity = opacity;
}
protected override void PushOpacityMaskCore(IBrush mask, Rect bounds)
{
throw new NotImplementedException();
var drawingGroup = PushNewDrawingGroup();
drawingGroup.OpacityMask = mask;
}
internal override void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)

4
src/Avalonia.Base/Media/PlatformDrawingContext.cs

@ -76,8 +76,8 @@ internal sealed class PlatformDrawingContext : DrawingContext
protected override void PushGeometryClipCore(Geometry clip) =>
_impl.PushGeometryClip(clip.PlatformImpl ?? throw new ArgumentException());
protected override void PushOpacityCore(double opacity, Rect bounds) =>
_impl.PushOpacity(opacity, bounds);
protected override void PushOpacityCore(double opacity) =>
_impl.PushOpacity(opacity, null);
protected override void PushOpacityMaskCore(IBrush mask, Rect bounds) =>
_impl.PushOpacityMask(mask, bounds);

2
src/Avalonia.Base/Platform/IDrawingContextImpl.cs

@ -132,7 +132,7 @@ namespace Avalonia.Platform
/// </summary>
/// <param name="opacity">The opacity.</param>
/// <param name="bounds">where to apply the opacity.</param>
void PushOpacity(double opacity, Rect bounds);
void PushOpacity(double opacity, Rect? bounds);
/// <summary>
/// Pops the latest pushed opacity value.

5
src/Avalonia.Base/Rendering/Composition/Drawing/Nodes/RenderDataNodes.cs

@ -182,11 +182,10 @@ class RenderDataGeometryClipNode : RenderDataPushNode
class RenderDataOpacityNode : RenderDataPushNode
{
public double Opacity { get; set; }
public Rect BoundsRect { get; set; }
public override void Push(ref RenderDataNodeRenderContext context)
{
if (Opacity != 1)
context.Context.PushOpacity(Opacity, BoundsRect);
context.Context.PushOpacity(Opacity, null);
}
public override void Pop(ref RenderDataNodeRenderContext context)
@ -211,4 +210,4 @@ abstract class RenderDataBrushAndPenNode : IRenderDataItemWithServerResources
public abstract void Invoke(ref RenderDataNodeRenderContext context);
public abstract Rect? Bounds { get; }
public abstract bool HitTest(Point p);
}
}

7
src/Avalonia.Base/Rendering/Composition/Drawing/RenderDataDrawingContext.cs

@ -212,15 +212,14 @@ internal class RenderDataDrawingContext : DrawingContext
});
}
protected override void PushOpacityCore(double opacity, Rect bounds)
protected override void PushOpacityCore(double opacity)
{
if (opacity == 1)
Push();
else
Push(new RenderDataOpacityNode
{
Opacity = opacity,
BoundsRect = bounds
Opacity = opacity
});
}
@ -346,4 +345,4 @@ internal class RenderDataDrawingContext : DrawingContext
if (_resourcesHashSet != null)
s_hashSetPool.ReturnAndSetNull(ref _resourcesHashSet);
}
}
}

2
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@ -109,7 +109,7 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
_impl.PopClip();
}
public void PushOpacity(double opacity, Rect bounds)
public void PushOpacity(double opacity, Rect? bounds)
{
_impl.PushOpacity(opacity, bounds);
}

2
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs

@ -58,7 +58,7 @@ namespace Avalonia.Rendering.Composition.Server
canvas.PushEffect(Effect);
if (Opacity != 1)
canvas.PushOpacity(Opacity, boundsRect);
canvas.PushOpacity(Opacity, ClipToBounds ? boundsRect : null);
if (ClipToBounds && !HandlesClipToBounds)
canvas.PushClip(Root!.SnapToDevicePixels(boundsRect));
if (Clip != null)

2
src/Avalonia.Base/Rendering/ImmediateRenderer.cs

@ -96,7 +96,7 @@ namespace Avalonia.Rendering
}
using (context.PushTransform(m))
using (context.PushOpacity(opacity, bounds))
using (context.PushOpacity(opacity))
using (clipToBounds
#pragma warning disable CS0618 // Type or member is obsolete
? visual is IVisualWithRoundRectClip roundClipVisual

2
src/Headless/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -457,7 +457,7 @@ namespace Avalonia.Headless
}
public void PushOpacity(double opacity, Rect rect)
public void PushOpacity(double opacity, Rect? rect)
{
}

14
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -7,7 +7,6 @@ using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering.Utilities;
using Avalonia.Utilities;
using Avalonia.Media.Imaging;
using SkiaSharp;
using ISceneBrush = Avalonia.Media.ISceneBrush;
@ -573,14 +572,21 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void PushOpacity(double opacity, Rect bounds)
public void PushOpacity(double opacity, Rect? bounds)
{
CheckLease();
if(_useOpacitySaveLayer)
{
var rect = bounds.ToSKRect();
Canvas.SaveLayer(rect, new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity)});
if (bounds.HasValue)
{
var rect = bounds.Value.ToSKRect();
Canvas.SaveLayer(rect, new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity) });
}
else
{
Canvas.SaveLayer(new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity) });
}
}
else
{

15
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -454,17 +454,26 @@ namespace Avalonia.Direct2D1.Media
/// <param name="opacity">The opacity.</param>
/// <param name="bounds">The bounds.</param>
/// <returns>A disposable used to undo the opacity.</returns>
public void PushOpacity(double opacity, Rect bounds)
public void PushOpacity(double opacity, Rect? bounds)
{
if (opacity < 1)
{
if(bounds == null || bounds == default(Rect))
{
bounds = new Rect(0, 0, _renderTarget.PixelSize.Width, _renderTarget.PixelSize.Height);
}
var parameters = new LayerParameters
{
ContentBounds = bounds.ToDirect2D(),
MaskTransform = PrimitiveExtensions.Matrix3x2Identity,
Opacity = (float)opacity,
Opacity = (float)opacity
};
if(bounds.HasValue)
{
parameters.ContentBounds = bounds.Value.ToDirect2D();
}
var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext);
_deviceContext.PushLayer(ref parameters, layer);

2
tests/Avalonia.RenderTests/Controls/CustomRenderTests.cs

@ -141,7 +141,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
new Rect(control.Bounds.Size),
4);
using (context.PushOpacity(0.5, control.Bounds))
using (context.PushOpacity(0.5))
{
context.FillRectangle(
Brushes.Blue,

Loading…
Cancel
Save