diff --git a/src/ImageSharp.Drawing/Primitives/Region.cs b/src/ImageSharp.Drawing/Primitives/Region.cs index c85e373fb3..27f039f122 100644 --- a/src/ImageSharp.Drawing/Primitives/Region.cs +++ b/src/ImageSharp.Drawing/Primitives/Region.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Primitives @@ -19,7 +20,7 @@ namespace SixLabors.ImageSharp.Primitives /// Gets the bounding box that entirely surrounds this region. /// /// - /// This should always contains all possible points returned from . + /// This should always contains all possible points returned from . /// public abstract Rectangle Bounds { get; } @@ -28,8 +29,8 @@ namespace SixLabors.ImageSharp.Primitives /// /// The position along the y axis to find intersections. /// The buffer. - /// The point in the buffer to start setting offset. + /// A instance in the context of the caller. /// The number of intersections found. - public abstract int Scan(float y, float[] buffer, int offset); + public abstract int Scan(float y, Span buffer, Configuration configuration); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs b/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs index cfd1945d08..4c446189e1 100644 --- a/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs +++ b/src/ImageSharp.Drawing/Primitives/ShapeRegion.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using SixLabors.ImageSharp.Memory; using SixLabors.Primitives; using SixLabors.Shapes; @@ -39,21 +40,23 @@ namespace SixLabors.ImageSharp.Primitives public override Rectangle Bounds { get; } /// - public override int Scan(float y, float[] buffer, int offset) + public override int Scan(float y, Span buffer, Configuration configuration) { var start = new PointF(this.Bounds.Left - 1, y); var end = new PointF(this.Bounds.Right + 1, y); - // TODO: This is a temporary workaround because of the lack of Span API-s on IPath. We should use MemoryManager.Allocate() here! - var innerBuffer = new PointF[buffer.Length]; - int count = this.Shape.FindIntersections(start, end, innerBuffer, 0); - - for (int i = 0; i < count; i++) + using (IBuffer tempBuffer = configuration.MemoryManager.Allocate(buffer.Length)) { - buffer[i + offset] = innerBuffer[i].X; - } + Span innerBuffer = tempBuffer.GetSpan(); + int count = this.Shape.FindIntersections(start, end, innerBuffer); - return count; + for (int i = 0; i < count; i++) + { + buffer[i] = innerBuffer[i].X; + } + + return count; + } } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs index 0bb3abc504..571ca5d3f2 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors float yPlusOne = y + 1; for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction) { - int pointsFound = region.Scan(subPixel + offset, buffer.Array, 0); + int pointsFound = region.Scan(subPixel + offset, buffer.GetSpan(), configuration); if (pointsFound == 0) { // nothing on this line skip diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs index 8c619c8175..017fee8563 100644 --- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs @@ -4,7 +4,8 @@ using System.Numerics; using Moq; - +using System; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing; @@ -13,13 +14,15 @@ using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Drawing.Processors; using SixLabors.Primitives; - using Xunit; namespace SixLabors.ImageSharp.Tests.Drawing { + + public class FillRegionProcessorTests { + [Theory] [InlineData(true, 1, 4)] [InlineData(true, 2, 4)] @@ -29,21 +32,20 @@ namespace SixLabors.ImageSharp.Tests.Drawing [InlineData(false, 16, 4)] // we always do 4 sub=pixels when antialising is off. public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelDepth, int expectedAntialiasSubpixelDepth) { - var bounds = new SixLabors.Primitives.Rectangle(0, 0, 1, 1); + var bounds = new Rectangle(0, 0, 1, 1); var brush = new Mock>(); - var region = new Mock(); - region.Setup(x => x.Bounds).Returns(bounds); + var region = new MockRegion2(bounds); var options = new GraphicsOptions(antialias) { AntialiasSubpixelDepth = 1 }; - var processor = new FillRegionProcessor(brush.Object, region.Object, options); + var processor = new FillRegionProcessor(brush.Object, region, options); var img = new Image(1, 1); processor.Apply(img, bounds); - region.Verify(x => x.Scan(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(4)); + Assert.Equal(4, region.ScanInvocationCounter); } [Fact] @@ -52,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var bounds = new Rectangle(-100, -10, 10, 10); var brush = new Mock>(); var options = new GraphicsOptions(true); - var processor = new FillRegionProcessor(brush.Object, new MockRegion(), options); + var processor = new FillRegionProcessor(brush.Object, new MockRegion1(), options); var img = new Image(10, 10); processor.Apply(img, bounds); } @@ -71,13 +73,11 @@ namespace SixLabors.ImageSharp.Tests.Drawing } // Mocking the region throws an error in netcore2.0 - private class MockRegion : Region + private class MockRegion1 : Region { public override Rectangle Bounds => new Rectangle(-100, -10, 10, 10); - public override int MaxIntersections => 10; - - public override int Scan(float y, float[] buffer, int offset) + public override int Scan(float y, Span buffer, Configuration configuration) { if (y < 5) { @@ -87,6 +87,28 @@ namespace SixLabors.ImageSharp.Tests.Drawing } return 0; } + + public override int MaxIntersections => 10; + } + + private class MockRegion2 : Region + { + public MockRegion2(Rectangle bounds) + { + this.Bounds = bounds; + } + + public override int MaxIntersections => 100; + + public override Rectangle Bounds { get; } + + public int ScanInvocationCounter { get; private set; } + + public override int Scan(float y, Span buffer, Configuration configuration) + { + this.ScanInvocationCounter++; + return 0; + } } } } diff --git a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs index 2a9ab3412e..08eef5597d 100644 --- a/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Paths/ShapeRegionTests.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths Assert.True(e.X > this.bounds.Right); }).Returns(0); - int i = region.Scan(yToScan, new float[0], 0); + int i = region.Scan(yToScan, new float[0], Configuration.Default); this.pathMock.Verify( x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths Assert.True(e.X > this.bounds.Right); }).Returns(0); - int i = region.Scan(yToScan, new float[0], 0); + int i = region.Scan(yToScan, new float[0], Configuration.Default); this.pathMock.Verify( x => x.FindIntersections(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()),