// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System; using System.Buffers; namespace SixLabors.ImageSharp.Drawing.Processing.Backends { internal static partial class DefaultRasterizer { /// /// Flush-scoped retained row-local raster payload for one prepared fill geometry. /// internal sealed class RasterizableGeometry : IDisposable { private readonly RasterizableBandInfo[] bandInfos; private readonly LineArrayX16Y16Block?[]? linesX16; private readonly LineArrayX32Y16Block?[]? linesX32; private readonly int[] firstBlockLineCounts; private readonly IMemoryOwner?[] startCoverTable; /// /// Initializes a new instance of the class. /// /// The first absolute row-band index touched by the geometry. /// The number of retained local row bands owned by the geometry. /// The geometry-local visible band width in pixels. /// The bit-vector width in machine words required by the geometry. /// The scanner cover/area stride required by the geometry. /// The retained row-band height in pixels. /// Indicates whether the geometry uses the narrow X16Y16 line encoding. /// The retained metadata for each local row band. /// The retained narrow line chains for each local row band. /// The retained wide line chains for each local row band. /// The valid line count in each front retained block. /// The retained start-cover table for each local row band. public RasterizableGeometry( int firstRowBandIndex, int rowBandCount, int width, int wordsPerRow, int coverStride, int bandHeight, bool isX16, RasterizableBandInfo[] bandInfos, LineArrayX16Y16Block?[]? linesX16, LineArrayX32Y16Block?[]? linesX32, int[] firstBlockLineCounts, IMemoryOwner?[] startCoverTable) { this.FirstRowBandIndex = firstRowBandIndex; this.RowBandCount = rowBandCount; this.Width = width; this.WordsPerRow = wordsPerRow; this.CoverStride = coverStride; this.BandHeight = bandHeight; this.IsX16 = isX16; this.bandInfos = bandInfos; this.linesX16 = linesX16; this.linesX32 = linesX32; this.firstBlockLineCounts = firstBlockLineCounts; this.startCoverTable = startCoverTable; } /// /// Gets the first absolute row-band index touched by this geometry. /// public int FirstRowBandIndex { get; } /// /// Gets the number of retained local row bands owned by this geometry. /// public int RowBandCount { get; } /// /// Gets the geometry-local visible band width in pixels. /// public int Width { get; } /// /// Gets the bit-vector width in machine words required by this geometry. /// public int WordsPerRow { get; } /// /// Gets the scanner cover/area stride required by this geometry. /// public int CoverStride { get; } /// /// Gets the retained row-band height in pixels. /// public int BandHeight { get; } /// /// Gets a value indicating whether this geometry uses Blaze's narrow X16Y16 line arrays. /// public bool IsX16 { get; } /// /// Returns when the given local row band has retained coverage payload. /// /// The local row band index. /// when the row band has retained coverage; otherwise . public bool HasCoverage(int localRowIndex) => this.bandInfos[localRowIndex].HasCoverage; /// /// Gets the retained narrow line block chain for one local row. /// /// The local row band index. /// The retained narrow line chain for the row. public LineArrayX16Y16Block? GetLinesX16ForRow(int localRowIndex) => this.linesX16![localRowIndex]; /// /// Gets the retained wide line block chain for one local row. /// /// The local row band index. /// The retained wide line chain for the row. public LineArrayX32Y16Block? GetLinesX32ForRow(int localRowIndex) => this.linesX32![localRowIndex]; /// /// Gets the number of valid lines in the first retained block for a local row. /// /// The local row band index. /// The valid line count in the front retained block. public int GetFirstBlockLineCountForRow(int localRowIndex) => this.firstBlockLineCounts[localRowIndex]; /// /// Gets the retained start-cover table entry for a local row, if one exists. /// /// The local row band index. /// The retained start-cover span for the row. public ReadOnlySpan GetCoversForRow(int localRowIndex) { IMemoryOwner? covers = this.startCoverTable[localRowIndex]; return covers is null ? ReadOnlySpan.Empty : covers.Memory.Span[..this.BandHeight]; } /// /// Gets the retained start-cover row payload without further interpretation, matching Blaze naming. /// /// The local row band index. /// The retained start-cover span for the row. public ReadOnlySpan GetActualCoversForRow(int localRowIndex) => this.GetCoversForRow(localRowIndex); /// /// Gets retained metadata for one local row band. /// /// The local row band index. /// The retained band metadata. public RasterizableBandInfo GetBandInfo(int localRowIndex) => this.bandInfos[localRowIndex]; /// /// Releases the retained line blocks and start-cover storage. /// public void Dispose() { if (this.linesX16 is not null) { Array.Clear(this.linesX16); } if (this.linesX32 is not null) { Array.Clear(this.linesX32); } for (int i = 0; i < this.startCoverTable.Length; i++) { this.startCoverTable[i]?.Dispose(); } } } } }