Browse Source

Merge pull request #11394 from Gillibald/fixOpacityClip

Fix PushOpacity when ClipToBounds is false
pull/11572/head
Max Katz 3 years ago
committed by GitHub
parent
commit
cd6415c8de
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  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. 13
      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. /// Pushes an opacity value.
/// </summary> /// </summary>
/// <param name="opacity">The opacity.</param> /// <param name="opacity">The opacity.</param>
/// <param name="bounds">The bounds.</param>
/// <returns>A disposable used to undo the opacity.</returns> /// <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 ??= StateStackPool.Get();
_states.Push(new RestoreState(this, RestoreState.PushedStateType.Opacity)); _states.Push(new RestoreState(this, RestoreState.PushedStateType.Opacity));
return new PushedState(this); return new PushedState(this);
} }
protected abstract void PushOpacityCore(double opacity, Rect bounds); protected abstract void PushOpacityCore(double opacity);
/// <summary> /// <summary>
/// Pushes an opacity mask. /// Pushes an opacity mask.

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

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

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

@ -132,7 +132,7 @@ namespace Avalonia.Platform
/// </summary> /// </summary>
/// <param name="opacity">The opacity.</param> /// <param name="opacity">The opacity.</param>
/// <param name="bounds">where to apply 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> /// <summary>
/// Pops the latest pushed opacity value. /// 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 class RenderDataOpacityNode : RenderDataPushNode
{ {
public double Opacity { get; set; } public double Opacity { get; set; }
public Rect BoundsRect { get; set; }
public override void Push(ref RenderDataNodeRenderContext context) public override void Push(ref RenderDataNodeRenderContext context)
{ {
if (Opacity != 1) if (Opacity != 1)
context.Context.PushOpacity(Opacity, BoundsRect); context.Context.PushOpacity(Opacity, null);
} }
public override void Pop(ref RenderDataNodeRenderContext context) public override void Pop(ref RenderDataNodeRenderContext context)
@ -211,4 +210,4 @@ abstract class RenderDataBrushAndPenNode : IRenderDataItemWithServerResources
public abstract void Invoke(ref RenderDataNodeRenderContext context); public abstract void Invoke(ref RenderDataNodeRenderContext context);
public abstract Rect? Bounds { get; } public abstract Rect? Bounds { get; }
public abstract bool HitTest(Point p); public abstract bool HitTest(Point p);
} }

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

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

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

@ -109,7 +109,7 @@ internal class CompositorDrawingContextProxy : IDrawingContextImpl,
_impl.PopClip(); _impl.PopClip();
} }
public void PushOpacity(double opacity, Rect bounds) public void PushOpacity(double opacity, Rect? bounds)
{ {
_impl.PushOpacity(opacity, 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); canvas.PushEffect(Effect);
if (Opacity != 1) if (Opacity != 1)
canvas.PushOpacity(Opacity, boundsRect); canvas.PushOpacity(Opacity, ClipToBounds ? boundsRect : null);
if (ClipToBounds && !HandlesClipToBounds) if (ClipToBounds && !HandlesClipToBounds)
canvas.PushClip(Root!.SnapToDevicePixels(boundsRect)); canvas.PushClip(Root!.SnapToDevicePixels(boundsRect));
if (Clip != null) if (Clip != null)

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

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

13
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -588,14 +588,21 @@ namespace Avalonia.Skia
} }
/// <inheritdoc /> /// <inheritdoc />
public void PushOpacity(double opacity, Rect bounds) public void PushOpacity(double opacity, Rect? bounds)
{ {
CheckLease(); CheckLease();
if(_useOpacitySaveLayer) if(_useOpacitySaveLayer)
{ {
var rect = bounds.ToSKRect(); if (bounds.HasValue)
Canvas.SaveLayer(rect, new SKPaint { ColorF = new SKColorF(0, 0, 0, (float)opacity)}); {
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 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="opacity">The opacity.</param>
/// <param name="bounds">The bounds.</param> /// <param name="bounds">The bounds.</param>
/// <returns>A disposable used to undo the opacity.</returns> /// <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 (opacity < 1)
{ {
if(bounds == null || bounds == default(Rect))
{
bounds = new Rect(0, 0, _renderTarget.PixelSize.Width, _renderTarget.PixelSize.Height);
}
var parameters = new LayerParameters var parameters = new LayerParameters
{ {
ContentBounds = bounds.ToDirect2D(),
MaskTransform = PrimitiveExtensions.Matrix3x2Identity, 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); var layer = _layerPool.Count != 0 ? _layerPool.Pop() : new Layer(_deviceContext);
_deviceContext.PushLayer(ref parameters, layer); _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), new Rect(control.Bounds.Size),
4); 4);
using (context.PushOpacity(0.5, control.Bounds)) using (context.PushOpacity(0.5))
{ {
context.FillRectangle( context.FillRectangle(
Brushes.Blue, Brushes.Blue,

Loading…
Cancel
Save