XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Buffers.Binary;
using System.IO.Compression;
using XFESystem.Desktop;
using Xunit;

namespace XFESystem.Core.Tests;

public sealed class CursorRasterTests
{
    private const uint Accent = 0x3B77D9;

    private sealed class BitmapCanvas(int width, int height, int scale, uint background) : IDesktopCoverageCanvas
    {
        public int Width => width;
        public int Height => height;
        public int NativeWidth => width * scale;
        public int NativeHeight => height * scale;
        public int ScalePercent => scale * 100;
        public readonly uint[] Pixels = Enumerable.Repeat(background, width * height * scale * scale).ToArray();
        public readonly List<(uint Rgb, int X, int Y, int Width, int Height, byte[] Alpha)> Calls = [];
        public void Fill(uint rgb, int x, int y, int w, int h)
        {
            for (int row = Math.Max(0, y * scale); row < Math.Min(NativeHeight, (y + h) * scale); row++)
                for (int col = Math.Max(0, x * scale); col < Math.Min(NativeWidth, (x + w) * scale); col++)
                    Pixels[row * NativeWidth + col] = rgb;
        }
        public void Line(uint rgb, int x1, int y1, int x2, int y2) { }
        public void Text(string text, uint rgb, int x, int y) { }
        public void Present() { }
        public void BlendCoverage(uint rgb, int nativeX, int nativeY, int w, int h, ReadOnlySpan<byte> coverage)
        {
            Assert.Equal(w * h, coverage.Length);
            Calls.Add((rgb, nativeX, nativeY, w, h, coverage.ToArray()));
            for (int row = Math.Max(0, nativeY); row < Math.Min(NativeHeight, nativeY + h); row++)
                for (int col = Math.Max(0, nativeX); col < Math.Min(NativeWidth, nativeX + w); col++)
                {
                    byte alpha = coverage[(row - nativeY) * w + col - nativeX];
                    if (alpha != 0) Pixels[row * NativeWidth + col] = Mix(Pixels[row * NativeWidth + col], rgb, alpha);
                }
        }
    }

    private static uint Mix(uint background, uint accent, byte alpha)
    {
        uint result = 0;
        for (int shift = 0; shift <= 16; shift += 8)
            result |= ((((accent >> shift) & 255) * alpha + ((background >> shift) & 255) * (255u - alpha) + 127) / 255) << shift;
        return result;
    }

    [Theory]
    [InlineData(DesktopPointerShape.Arrow, 1)]
    [InlineData(DesktopPointerShape.Arrow, 2)]
    [InlineData(DesktopPointerShape.Text, 1)]
    [InlineData(DesktopPointerShape.Text, 2)]
    [InlineData(DesktopPointerShape.Resize, 1)]
    [InlineData(DesktopPointerShape.Resize, 2)]
    public void NativeCoverageIsBoundedAndHasThinCorePlusLowAlphaHalo(DesktopPointerShape shape, int scale)
    {
        var bitmap = new BitmapCanvas(96, 96, scale, 0x09121B);
        DesktopPointerRenderer.Draw(bitmap, 40, 40, shape, Accent);
        Assert.Equal(2, bitmap.Calls.Count);
        var halo = bitmap.Calls[0]; var core = bitmap.Calls[1];
        Assert.All(bitmap.Calls, call => Assert.Equal(Accent, call.Rgb));
        Assert.All(halo.Alpha, value => Assert.InRange(value, (byte)0, (byte)38));
        Assert.Contains(core.Alpha, value => value is > 0 and < 255);
        Assert.Contains(core.Alpha, value => value == 255);
        int coreArea = core.Alpha.Count(value => value >= 128);
        Assert.True(coreArea < core.Alpha.Length / 8);
        Assert.True(halo.Alpha.Count(value => value > 0) > coreArea * 4);
        var bounds = DesktopPointerRenderer.GetBounds(40, 40, shape);
        Assert.Equal(bounds.X * scale, core.X); Assert.Equal(bounds.Y * scale, core.Y);
        Assert.Equal(bounds.Width * scale, core.Width); Assert.Equal(bounds.Height * scale, core.Height);
        for (int row = 0; row < bitmap.NativeHeight; row++)
            for (int col = 0; col < bitmap.NativeWidth; col++)
                if (bitmap.Pixels[row * bitmap.NativeWidth + col] != 0x09121B)
                    Assert.True(col >= bounds.X * scale && col < (bounds.X + bounds.Width) * scale &&
                                row >= bounds.Y * scale && row < (bounds.Y + bounds.Height) * scale);
    }

    [Fact]
    public void TwoHundredPercentRasterDoesNotReplicateLogicalPixelSquares()
    {
        var bitmap = new BitmapCanvas(96, 96, 2, 0x09121B);
        DesktopPointerRenderer.Draw(bitmap, 40, 40, DesktopPointerShape.Arrow, Accent);
        var core = bitmap.Calls[1];
        int variedBlocks = 0;
        for (int row = 0; row + 1 < core.Height; row += 2)
            for (int col = 0; col + 1 < core.Width; col += 2)
            {
                byte value = core.Alpha[row * core.Width + col];
                if (value != core.Alpha[row * core.Width + col + 1] ||
                    value != core.Alpha[(row + 1) * core.Width + col] ||
                    value != core.Alpha[(row + 1) * core.Width + col + 1]) variedBlocks++;
            }
        Assert.True(variedBlocks > 12);
    }

    [Theory]
    [InlineData(0x09121Bu)]
    [InlineData(0xF7F8FBu)]
    public void HaloBlendsRealBackgroundAndCannotIntroduceWhiteFringe(uint background)
    {
        var bitmap = new BitmapCanvas(96, 96, 2, background);
        DesktopPointerRenderer.Draw(bitmap, 40, 40, DesktopPointerShape.Arrow, Accent);
        var halo = bitmap.Calls[0]; var core = bitmap.Calls[1];
        bool checkedHalo = false;
        for (int index = 0; index < halo.Alpha.Length; index++)
        {
            int x = halo.X + index % halo.Width, y = halo.Y + index / halo.Width;
            uint actual = bitmap.Pixels[y * bitmap.NativeWidth + x];
            for (int shift = 0; shift <= 16; shift += 8)
                Assert.InRange((actual >> shift) & 255, Math.Min((background >> shift) & 255, (Accent >> shift) & 255),
                               Math.Max((background >> shift) & 255, (Accent >> shift) & 255));
            if (halo.Alpha[index] is > 0 and < 38 && core.Alpha[index] == 0)
            {
                Assert.Equal(Mix(background, Accent, halo.Alpha[index]), actual);
                Assert.NotEqual(Accent, actual);
                checkedHalo = true;
            }
        }
        Assert.True(checkedHalo);
        Assert.Equal(background, bitmap.Pixels[0]);
    }

    [Fact]
    public void SameTranslucentHaloRetainsDifferentDarkAndLightBackgrounds()
    {
        var dark = new BitmapCanvas(96, 96, 2, 0x09121B);
        var light = new BitmapCanvas(96, 96, 2, 0xF7F8FB);
        DesktopPointerRenderer.Draw(dark, 40, 40, DesktopPointerShape.Text, Accent);
        DesktopPointerRenderer.Draw(light, 40, 40, DesktopPointerShape.Text, Accent);
        var halo = dark.Calls[0]; var core = dark.Calls[1];
        int sample = Array.FindIndex(halo.Alpha, value => value is > 4 and < 20);
        Assert.True(sample >= 0); Assert.Equal(0, core.Alpha[sample]);
        int destination = (halo.Y + sample / halo.Width) * dark.NativeWidth + halo.X + sample % halo.Width;
        Assert.NotEqual(dark.Pixels[destination], light.Pixels[destination]);
    }

    [Fact]
    public void ArrowIntersectionIsThickerThanItsArmEndpoint()
    {
        var bitmap = new BitmapCanvas(96, 96, 2, 0x09121B);
        DesktopPointerRenderer.Draw(bitmap, 40, 40, DesktopPointerShape.Arrow, Accent);
        var mask = bitmap.Calls[1];
        int Mass(int logicalX)
        {
            int sum = 0;
            for (int row = 76 - mask.Y; row < 84 - mask.Y; row++)
                for (int col = (40 + logicalX) * 2 - mask.X; col < (41 + logicalX) * 2 - mask.X; col++)
                    sum += mask.Alpha[row * mask.Width + col];
            return sum;
        }
        Assert.True(Mass(0) > Mass(7) * 2);
    }

    [Theory]
    [InlineData(DesktopPointerShape.Arrow)]
    [InlineData(DesktopPointerShape.Text)]
    [InlineData(DesktopPointerShape.Resize)]
    public void PartiallyOffscreenCursorIsClippedWithoutChangingRemotePixels(DesktopPointerShape shape)
    {
        var bitmap = new BitmapCanvas(32, 32, 2, 0x09121B);
        DesktopPointerRenderer.Draw(bitmap, 0, 0, shape, Accent);
        Assert.Contains(bitmap.Pixels, value => value != 0x09121B);
        Assert.Equal(0x09121Bu, bitmap.Pixels[^1]);
    }

    private sealed class LegacyCanvas : IDesktopCanvas
    {
        public int Width => 96;
        public int Height => 96;
        public List<uint> Colors { get; } = [];
        public void Fill(uint rgb, int x, int y, int width, int height) => Colors.Add(rgb);
        public void Line(uint rgb, int x1, int y1, int x2, int y2) { }
        public void Text(string text, uint rgb, int x, int y) { }
        public void Present() { }
    }

    [Fact]
    public void LegacyCanvasDrawsCoreWithoutInventingOpaqueGlowBackground()
    {
        var legacy = new LegacyCanvas();
        DesktopPointerRenderer.Draw(legacy, 40, 40, DesktopPointerShape.Arrow, Accent);
        Assert.NotEmpty(legacy.Colors); Assert.All(legacy.Colors, color => Assert.Equal(Accent, color));
    }

    [Fact]
    public void SettingsKeepsExistingApplicationOrdinalContract()
    {
        Assert.Equal(0, (int)DesktopApplication.Files); Assert.Equal(3, (int)DesktopApplication.Terminal);
        Assert.Equal(4, (int)DesktopApplication.Settings);
        Assert.Equal(8, (int)DesktopIcon.ApplicationFile);
        Assert.Equal(9, (int)DesktopIcon.Settings); // A code-native symbol, outside the nine-entry PNG atlas.
    }

    private sealed class AllocationProbe(int scalePercent = 200) : IDesktopCoverageCanvas
    {
        public int Width => 96;
        public int Height => 96;
        public int ScalePercent => scalePercent;
        public int Calls;
        public void Fill(uint rgb, int x, int y, int width, int height) { }
        public void Line(uint rgb, int x1, int y1, int x2, int y2) { }
        public void Text(string text, uint rgb, int x, int y) { }
        public void Present() { }
        public void BlendCoverage(uint rgb, int x, int y, int width, int height, ReadOnlySpan<byte> coverage) => Calls++;
    }

    [Fact]
    public void WarmNativeMotionReusesMasksWithoutPerFrameAllocation()
    {
        var canvas = new AllocationProbe();
        for (int index = 0; index < 100; index++)
            DesktopPointerRenderer.Draw(canvas, 40, 40, DesktopPointerShape.Arrow, Accent);
        long before = GC.GetAllocatedBytesForCurrentThread();
        for (int index = 0; index < 500; index++)
            DesktopPointerRenderer.Draw(canvas, 40 + index % 4, 40, DesktopPointerShape.Arrow, Accent);
        long allocated = GC.GetAllocatedBytesForCurrentThread() - before;
        Assert.Equal(0, allocated);
        Assert.Equal(1200, canvas.Calls);
    }

    [Fact]
    public void NewHotFamilyAfterCacheSaturationStillWarmsToZeroAllocation()
    {
        // Fill more than the entire 24-family cache using distinct scales.
        // These entries are unrelated to the new family we subsequently use.
        for (int scale = 50; scale < 80; scale++)
            DesktopPointerRenderer.Draw(new AllocationProbe(scale), 40, 40, DesktopPointerShape.Text, Accent);

        var hot = new AllocationProbe(375);
        for (int index = 0; index < 100; index++)
            DesktopPointerRenderer.Draw(hot, 40, 40, DesktopPointerShape.Resize, Accent);

        long before = GC.GetAllocatedBytesForCurrentThread();
        for (int index = 0; index < 500; index++)
            DesktopPointerRenderer.Draw(hot, 40 + index % 4, 40, DesktopPointerShape.Resize, Accent);
        long allocated = GC.GetAllocatedBytesForCurrentThread() - before;
        Assert.Equal(0, allocated);
        Assert.Equal(1200, hot.Calls);
    }

    [Fact]
    public void ConcurrentFirstUseOfSameMaskFamilyIsSafe()
    {
        Parallel.For(0, 48, index =>
        {
            var canvas = new AllocationProbe(125 + index % 3 * 25);
            for (int iteration = 0; iteration < 8; iteration++)
                DesktopPointerRenderer.Draw(canvas, 40, 40, (DesktopPointerShape)(index % 3), Accent);
            Assert.Equal(16, canvas.Calls);
        });
    }

    [Fact]
    public void TransparentOuterGuardKeepsAllRasterCoverageInsideDamageBounds()
    {
        foreach (var shape in Enum.GetValues<DesktopPointerShape>())
        {
            var bitmap = new BitmapCanvas(96, 96, 2, 0x09121B);
            DesktopPointerRenderer.Draw(bitmap, 40, 40, shape, Accent);
            foreach (var call in bitmap.Calls)
            {
                for (int col = 0; col < call.Width; col++)
                {
                    Assert.Equal(0, call.Alpha[col]);
                    Assert.Equal(0, call.Alpha[(call.Height - 1) * call.Width + col]);
                }
                for (int row = 0; row < call.Height; row++)
                {
                    Assert.Equal(0, call.Alpha[row * call.Width]);
                    Assert.Equal(0, call.Alpha[row * call.Width + call.Width - 1]);
                }
            }
        }
    }

    [Fact]
    public void OptionalInspectionSheetsUseTheSameNativeCoveragePath()
    {
        string? destination = Environment.GetEnvironmentVariable("XFE_CURSOR_PROOF_PATH");
        foreach (int scale in new[] { 1, 2 })
        {
            var bitmap = new BitmapCanvas(384, 160, scale, 0x09121B);
            bitmap.Fill(0xF7F8FB, 0, 80, 384, 80);
            for (int row = 0; row < 2; row++)
                for (int shape = 0; shape < 3; shape++)
                    DesktopPointerRenderer.Draw(bitmap, 64 + shape * 128, 40 + row * 80, (DesktopPointerShape)shape, Accent);
            Assert.Equal(12, bitmap.Calls.Count);
            if (destination is null) continue;
            Assert.True(Path.IsPathFullyQualified(destination));
            Directory.CreateDirectory(destination);
            WritePng(Path.Combine(destination, $"Pointer{scale}x.png"), bitmap.NativeWidth, bitmap.NativeHeight, bitmap.Pixels);
        }
    }

    private static void WritePng(string path, int width, int height, uint[] pixels)
    {
        using var output = File.Create(path);
        output.Write(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 });
        Span<byte> header = stackalloc byte[13]; header.Clear();
        BinaryPrimitives.WriteUInt32BigEndian(header, (uint)width);
        BinaryPrimitives.WriteUInt32BigEndian(header[4..], (uint)height); header[8] = 8; header[9] = 2;
        Chunk(output, "IHDR"u8, header);
        using var compressed = new MemoryStream();
        using (var zlib = new ZLibStream(compressed, CompressionLevel.Fastest, true))
            for (int row = 0; row < height; row++)
            {
                zlib.WriteByte(0);
                for (int col = 0; col < width; col++)
                {
                    uint rgb = pixels[row * width + col];
                    zlib.WriteByte((byte)(rgb >> 16)); zlib.WriteByte((byte)(rgb >> 8)); zlib.WriteByte((byte)rgb);
                }
            }
        Chunk(output, "IDAT"u8, compressed.ToArray()); Chunk(output, "IEND"u8, []);
    }

    private static void Chunk(Stream output, ReadOnlySpan<byte> name, ReadOnlySpan<byte> data)
    {
        Span<byte> word = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(word, (uint)data.Length);
        output.Write(word); output.Write(name); output.Write(data);
        uint crc = uint.MaxValue;
        foreach (byte value in name) crc = Crc(crc, value);
        foreach (byte value in data) crc = Crc(crc, value);
        BinaryPrimitives.WriteUInt32BigEndian(word, ~crc); output.Write(word);
    }
    private static uint Crc(uint crc, byte value)
    {
        crc ^= value;
        for (int bit = 0; bit < 8; bit++) crc = (crc >> 1) ^ ((crc & 1) == 0 ? 0 : 0xEDB88320u);
        return crc;
    }
}