From 8f4ef7fab01d9227d6d6ea72a86f02170f1bdac6 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 17 Feb 2017 23:59:08 +0100 Subject: [PATCH] Make a bunch of skia render tests pass. --- .../RenderHelpers/TileBrushImplHelper.cs | 12 +-- src/Skia/Avalonia.Skia/BitmapImpl.cs | 14 +++- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 72 +++++++++++++++--- .../Avalonia.Skia/FramebufferRenderTarget.cs | 3 +- .../Geometry_Clip_Clips_Path.expected.png | Bin 373 -> 728 bytes 5 files changed, 78 insertions(+), 23 deletions(-) diff --git a/src/Shared/RenderHelpers/TileBrushImplHelper.cs b/src/Shared/RenderHelpers/TileBrushImplHelper.cs index fc0057f01b..d1d3073be6 100644 --- a/src/Shared/RenderHelpers/TileBrushImplHelper.cs +++ b/src/Shared/RenderHelpers/TileBrushImplHelper.cs @@ -17,17 +17,17 @@ namespace Avalonia.RenderHelpers private readonly Vector _scale; private readonly Vector _translate; private readonly Size _imageSize; - private readonly VisualBrush _visualBrush; - private readonly ImageBrush _imageBrush; + private readonly IVisualBrush _visualBrush; + private readonly IImageBrush _imageBrush; private readonly Matrix _transform; private readonly Rect _drawRect; public bool IsValid { get; } - public TileBrushImplHelper(TileBrush brush, Size targetSize) + public TileBrushImplHelper(ITileBrush brush, Size targetSize) { - _imageBrush = brush as ImageBrush; - _visualBrush = brush as VisualBrush; + _imageBrush = brush as IImageBrush; + _visualBrush = brush as IVisualBrush; if (_imageBrush != null) { if (_imageBrush.Source == null) @@ -115,7 +115,7 @@ namespace Avalonia.RenderHelpers /// A vector with the X and Y _translate. public static Vector CalculateTranslate( - TileBrush brush, + ITileBrush brush, Rect sourceRect, Rect destinationRect, Vector scale) diff --git a/src/Skia/Avalonia.Skia/BitmapImpl.cs b/src/Skia/Avalonia.Skia/BitmapImpl.cs index 4d6b106fc6..7926a62a50 100644 --- a/src/Skia/Avalonia.Skia/BitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/BitmapImpl.cs @@ -30,6 +30,11 @@ namespace Avalonia.Skia if (runtime?.IsDesktop == true && runtime?.OperatingSystem == OperatingSystemType.Linux) colorType = SKColorType.Bgra8888; Bitmap = new SKBitmap(width, height, colorType, SKAlphaType.Premul); + + using (var context = new BitmapDrawingContext(Bitmap, null)) + { + context.Clear(Colors.Transparent); + } } public void Dispose() @@ -56,7 +61,8 @@ namespace Avalonia.Skia { private readonly SKSurface _surface; - public BitmapDrawingContext(SKBitmap bitmap) : this(CreateSurface(bitmap)) + public BitmapDrawingContext(SKBitmap bitmap, IVisualBrushRenderer visualBrushRenderer) + : this(CreateSurface(bitmap), visualBrushRenderer) { } @@ -70,7 +76,8 @@ namespace Avalonia.Skia return rv; } - public BitmapDrawingContext(SKSurface surface) : base(surface.Canvas) + public BitmapDrawingContext(SKSurface surface, IVisualBrushRenderer visualBrushRenderer) + : base(surface.Canvas, visualBrushRenderer) { _surface = surface; } @@ -84,8 +91,7 @@ namespace Avalonia.Skia public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) { - - return new BitmapDrawingContext(Bitmap); + return new BitmapDrawingContext(Bitmap, visualBrushRenderer); } public void Save(Stream stream) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index eacf64e550..4be8662a18 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -6,6 +6,8 @@ using System; using System.Collections.Generic; using System.Linq; using Avalonia.Platform; +using Avalonia.Rendering.Utilities; +using Avalonia.Rendering; namespace Avalonia.Skia { @@ -13,14 +15,20 @@ namespace Avalonia.Skia { private readonly Matrix? _postTransform; private readonly IDisposable[] _disposables; + private readonly IVisualBrushRenderer _visualBrushRenderer; private Stack maskStack = new Stack(); public SKCanvas Canvas { get; private set; } - public DrawingContextImpl(SKCanvas canvas, Matrix? postTransform = null, params IDisposable[] disposables) + public DrawingContextImpl( + SKCanvas canvas, + IVisualBrushRenderer visualBrushRenderer, + Matrix? postTransform = null, + params IDisposable[] disposables) { if (postTransform.HasValue && !postTransform.Value.IsIdentity) _postTransform = postTransform; + _visualBrushRenderer = visualBrushRenderer; _disposables = disposables; Canvas = canvas; Transform = Matrix.Identity; @@ -160,14 +168,14 @@ namespace Avalonia.Skia return rv; } - var gradient = brush as GradientBrush; + var gradient = brush as IGradientBrush; if (gradient != null) { var tileMode = gradient.SpreadMethod.ToSKShaderTileMode(); var stopColors = gradient.GradientStops.Select(s => s.Color.ToSKColor()).ToArray(); var stopOffsets = gradient.GradientStops.Select(s => (float)s.Offset).ToArray(); - var linearGradient = brush as LinearGradientBrush; + var linearGradient = brush as ILinearGradientBrush; if (linearGradient != null) { var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint(); @@ -180,7 +188,7 @@ namespace Avalonia.Skia } else { - var radialGradient = brush as RadialGradientBrush; + var radialGradient = brush as IRadialGradientBrush; if (radialGradient != null) { var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint(); @@ -199,15 +207,57 @@ namespace Avalonia.Skia return rv; } - var tileBrush = brush as TileBrush; - if (tileBrush != null) + var tileBrush = brush as ITileBrush; + var visualBrush = brush as IVisualBrush; + var tileBrushImage = default(BitmapImpl); + + if (visualBrush != null) { - var helper = new TileBrushImplHelper(tileBrush, targetSize); - var bitmap = new BitmapImpl((int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height); + if (_visualBrushRenderer != null) + { + var intermediateSize = _visualBrushRenderer.GetRenderTargetSize(visualBrush); + + if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1) + { + var intermediate = new BitmapImpl((int)intermediateSize.Width, (int)intermediateSize.Height); + + using (var ctx = intermediate.CreateDrawingContext(_visualBrushRenderer)) + { + ctx.Clear(Colors.Transparent); + _visualBrushRenderer.RenderVisualBrush(ctx, visualBrush); + } + + rv.AddDisposable(tileBrushImage); + tileBrushImage = intermediate; + } + } + else + { + throw new NotSupportedException("No IVisualBrushRenderer was supplied to DrawingContextImpl."); + } + } + else + { + tileBrushImage = (BitmapImpl)((tileBrush as IImageBrush)?.Source?.PlatformImpl); + } + + if (tileBrush != null && tileBrushImage != null) + { + var calc = new TileBrushCalculator(tileBrush, new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); + var bitmap = new BitmapImpl((int)calc.IntermediateSize.Width, (int)calc.IntermediateSize.Height); rv.AddDisposable(bitmap); - using (var ctx = bitmap.CreateDrawingContext(null)) - helper.DrawIntermediate(new DrawingContext(ctx)); - SKMatrix translation = SKMatrix.MakeTranslation(-(float)helper.DestinationRect.X, -(float)helper.DestinationRect.Y); + using (var context = bitmap.CreateDrawingContext(null)) + { + var rect = new Rect(0, 0, tileBrushImage.PixelWidth, tileBrushImage.PixelHeight); + + context.Clear(Colors.Transparent); + context.PushClip(calc.IntermediateClip); + context.Transform = calc.IntermediateTransform; + context.DrawImage(tileBrushImage, 1, rect, rect); + context.PopClip(); + } + + SKMatrix translation = SKMatrix.MakeTranslation(-(float)calc.DestinationRect.X, -(float)calc.DestinationRect.Y); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 7eaa8cf172..287c056cc9 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -88,10 +88,9 @@ namespace Avalonia.Skia canvas.RestoreToCount(0); canvas.Save(); - canvas.Clear(SKColors.Red); canvas.ResetMatrix(); var scale = Matrix.CreateScale(fb.Dpi.Width / 96, fb.Dpi.Height / 96); - return new DrawingContextImpl(canvas, scale, canvas, surface, shim, fb); + return new DrawingContextImpl(canvas, visualBrushRenderer, scale, canvas, surface, shim, fb); } } } diff --git a/tests/TestFiles/Skia/GeometryClipping/Geometry_Clip_Clips_Path.expected.png b/tests/TestFiles/Skia/GeometryClipping/Geometry_Clip_Clips_Path.expected.png index 892899507b7d71439ee220baf272495473ad7394..5993088a33d10a1711671a615c43acd1dda2ce0c 100644 GIT binary patch delta 655 zcmV;A0&xBH0@wwRReu6)NklBXbvG#ED1W-EycMRfA9k&%>kfO+{VS^ag+1#2ikkky9(M1dA`5%m zT_{XpA4C_`JcoT0S=6!&`!K4gM1K-Bq`?M75f!AvhD8wT z=fMWHE>_Qn4Q*Mhy$v?FRk8AR*zgv`x@BMilb@frup;U#mf@k~mxYC>udjCTTy+-9 z@KEy0^B7X{x+eF!GRdyPJf!4xP40DNl3foCsBvABdt901)}_XEP401JlIwz5wv^si zCYf%SWlQLNWq*?CidndXo>wM$?wEzQ>Um|7=g-^QFkUWp@hy5?nPlz5*Viz9d<^5u zi(NiPuPc+R{m@_F{oO8~tH+f|&hD7SbM?3~$vFgO`CMyXnPeOWvwV)VuS_xyg()D% znpYWE{A|9-aHRAJ_ zutNS5pT>oivLrr>4J+oE_@u+iVd8m5VFf*kr=1B_(p)_2%wa`M;z{QbR+fq%cNo2} p40>T1^ujXeg=NqSOJ*3p0Ypr1xES5N`~Uy|00>D%PDHLkV1if!MIZnG delta 297 zcmV+^0oMN51@!`uReu2rNkl_enzH7pww z4%q)m|B4iAfCT^m000000Pu&7)^k$+S?OIZ_4r8sS*gujS1a|(X0EH1c4faXo^Jb+Yc3I>2b@ zSJs>@b%03eSLW2iqm@~idVI7JD|71ck;<&hsRKkRvofa+Fj}dVIdz25O0CSPBaBpT zWlkMpZ#SzXb&Nfg`%3oILAENpuAVx~yGpOCr;f9Zb*-o)^|3BN9m-=}8`QyA*9ZNv vSl3RhD}Z$Y03rYY000000001h`IhAc^T+F3nCMlP00000NkvXXu0mjf`QwY$