Browse Source

Opacity masks on Skia now work correctly. Implemented via skia layers.

pull/553/head
Jeremy Koritzinsky 10 years ago
parent
commit
6feb0f7d88
  1. 56
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  2. 4
      tests/Avalonia.RenderTests/OpacityMaskTests.cs
  3. BIN
      tests/TestFiles/Skia/OpacityMask/Opacity_Mask_Masks_Element.expected.png

56
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -10,16 +10,14 @@ namespace Avalonia.Skia
{
internal class DrawingContextImpl : IDrawingContextImpl
{
private Stack<SKSurface> surfaceStack = new Stack<SKSurface>();
private Stack<MaskWrapper> maskStack = new Stack<MaskWrapper>();
private SKCanvas initialCanvas;
public SKCanvas CurrentCanvas => surfaceStack.Count == 0 ? initialCanvas : surfaceStack.Peek().Canvas;
private Stack<PaintWrapper> maskStack = new Stack<PaintWrapper>();
public SKCanvas CurrentCanvas { get; private set; }
public DrawingContextImpl(SKCanvas canvas)
{
initialCanvas = canvas;
initialCanvas.Clear();
CurrentCanvas = canvas;
CurrentCanvas.Clear();
}
public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect)
@ -57,18 +55,6 @@ namespace Avalonia.Skia
}
}
struct MaskWrapper : IDisposable
{
public PaintWrapper Mask { get; set; }
public Rect Bounds { get; set; }
public void Dispose()
{
Mask.Dispose();
}
}
struct PaintWrapper : IDisposable
{
//We are saving memory allocations there
@ -317,37 +303,19 @@ namespace Avalonia.Skia
public void PushOpacityMask(IBrush mask, Rect bounds)
{
surfaceStack.Push(SKSurface.Create((int)bounds.Width, (int)bounds.Height, SKColorType.N_32, SKAlphaType.Premul));
surfaceStack.Peek().Canvas.Clear();
var paint = new MaskWrapper { Mask = CreatePaint(mask, bounds.Size), Bounds = bounds };
maskStack.Push(paint);
CurrentCanvas.SaveLayer(new SKPaint());
maskStack.Push(CreatePaint(mask, bounds.Size));
}
public void PopOpacityMask()
{
using (var surface = surfaceStack.Pop())
using (var mask = maskStack.Pop())
using (var combindingPaint = new SKPaint())
using (var surfaceImage = surface.Snapshot())
CurrentCanvas.SaveLayer(new SKPaint { XferMode = SKXferMode.DstIn });
using (var paintWrapper = maskStack.Pop())
{
using (var maskSurface = SKSurface.Create((int)mask.Bounds.Width, (int)mask.Bounds.Height, SKColorType.N_32, SKAlphaType.Premul))
{
maskSurface.Canvas.Clear(SKColors.Transparent);
maskSurface.Canvas.DrawRect(SKRect.Create((float)mask.Bounds.Width, (float)mask.Bounds.Height), mask.Mask.Paint);
using (var maskImage = maskSurface.Snapshot())
using (var combindingSurface = SKSurface.Create((int)mask.Bounds.Width, (int)mask.Bounds.Height, SKColorType.N_32, SKAlphaType.Premul))
{
combindingSurface.Canvas.Clear(SKColors.Transparent);
combindingSurface.Canvas.DrawImage(surfaceImage, 0, 0, combindingPaint);
combindingPaint.XferMode = SKXferMode.DstIn;
combindingSurface.Canvas.DrawImage(maskImage, 0, 0, combindingPaint);
using (var maskedImage = combindingSurface.Snapshot())
{
CurrentCanvas.DrawImage(maskedImage, mask.Bounds.ToSKRect());
}
}
}
CurrentCanvas.DrawPaint(paintWrapper.Paint);
}
CurrentCanvas.Restore();
CurrentCanvas.Restore();
}
private Matrix _currentTransform = Matrix.Identity;

4
tests/Avalonia.RenderTests/OpacityMaskTests.cs

@ -21,11 +21,7 @@ namespace Avalonia.Direct2D1.RenderTests
{
}
#if AVALONIA_SKIA
[Fact(Skip = "Opacity Masks on Skia are currently bugged.")]
#else
[Fact]
#endif
public void Opacity_Mask_Masks_Element()
{
var target = new Canvas

BIN
tests/TestFiles/Skia/OpacityMask/Opacity_Mask_Masks_Element.expected.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 846 B

After

Width:  |  Height:  |  Size: 732 B

Loading…
Cancel
Save