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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
using XFESystem.Browser;
using XFESystem.Desktop;

namespace XFESystem.Browser.Tests;

public sealed class RasterCoveragePerformanceTests
{
    [Fact]
    public void SolidSpansPreserveRoundedFractionalClippedPixelsAtBothScales()
    {
        var random=new Random(240617);
        foreach(int scale in new[]{1,2})
        for(int sample=0;sample<120;sample++)
        {
            var bounds=new BrowserRect(3+random.NextDouble(),4+random.NextDouble(),2+random.NextDouble()*45,2+random.NextDouble()*40);
            double maximum=Math.Min(bounds.Width,bounds.Height)/2;
            var radii=new BrowserEdges(random.NextDouble()*maximum,random.NextDouble()*maximum,random.NextDouble()*maximum,random.NextDouble()*maximum);
            double alpha=sample%3==0?1:random.NextDouble(),opacity=sample%4==0?1:random.NextDouble();
            var decoration=new BrowserBoxDecoration(radii,default,new(0x123456,alpha),default,default,default,default,[],bounds,[]);
            var command=new BrowserDrawCommand(BrowserDrawKind.Fill,bounds,0,null,0x123456,Opacity:opacity,Decoration:decoration);
            var clip=sample%2==0?new BrowserRect(0,0,70,70):new BrowserRect(8.25,10.75,26.5,23.25);
            var canvas=new CoveragePixels(scale);
            BrowserBoxRasterPainter.Paint(canvas,command,bounds,clip);
            var area=bounds.Intersect(clip);var native=new BrowserRect(bounds.X*scale,bounds.Y*scale,bounds.Width*scale,bounds.Height*scale);
            var nativeRadii=new BrowserEdges(radii.Top*scale,radii.Right*scale,radii.Bottom*scale,radii.Left*scale);
            for(int y=0;y<140;y++)for(int x=0;x<140;x++)
            {
                bool touched=x>=Math.Floor(area.X*scale)&&x<Math.Ceiling(area.Right*scale)&&y>=Math.Floor(area.Y*scale)&&y<Math.Ceiling(area.Bottom*scale);
                byte expected=touched?(byte)Math.Clamp(Math.Round(BrowserBoxRasterPainter.Coverage(native,nativeRadii,x+.5,y+.5)*alpha*opacity*255),0,255):(byte)0;
                Assert.Equal(expected,canvas.Alpha[y*140+x]);
            }
        }
    }
    private sealed class CoveragePixels(int scale):IDesktopCoverageCanvas
    {
        public int Width=>70;public int Height=>70;public int ScalePercent=>scale*100;
        public byte[] Alpha=new byte[140*140];
        public void BlendCoverage(uint rgb,int x,int y,int width,int height,ReadOnlySpan<byte> source)
        {for(int row=0;row<height;row++)source.Slice(row*width,width).CopyTo(Alpha.AsSpan((y+row)*140+x,width));}
        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(){}
    }
    [Fact]
    public void RoundedCoverageFastPathsKeepOriginalDevicePixelAlpha()
    {
        var random = new Random(617071);
        for (int sample = 0; sample < 20000; sample++)
        {
            double width = 1 + random.NextDouble() * 1000, height = 1 + random.NextDouble() * 1000;
            var bounds = new BrowserRect(random.NextDouble() * 30, random.NextDouble() * 30, width, height);
            double maximum = Math.Min(width, height) / 2;
            var radii = new BrowserEdges(random.NextDouble() * maximum, random.NextDouble() * maximum,
                random.NextDouble() * maximum, random.NextDouble() * maximum);
            double x = bounds.X - 1 + random.NextDouble() * (width + 2);
            double y = bounds.Y - 1 + random.NextDouble() * (height + 2);
            double expected = Original(bounds, radii, x, y), actual = BrowserBoxRasterPainter.Coverage(bounds, radii, x, y);
            Assert.InRange(Math.Abs(actual - expected), 0, 1e-12);
            Assert.Equal(Math.Round(expected * 255), Math.Round(actual * 255));
        }
        foreach (double radius in new[] { 0d, .125, .5, 1, 4.25, 8.5, 16, 20 })
            for (double y = -.5; y <= 40.5; y += .125)
                for (double x = -.5; x <= 40.5; x += .125)
                {
                    var bounds = new BrowserRect(0, 0, 40, 40); var radii = new BrowserEdges(radius, radius, radius, radius);
                    Assert.Equal(Math.Round(Original(bounds, radii, x, y) * 255), Math.Round(BrowserBoxRasterPainter.Coverage(bounds, radii, x, y) * 255));
                }
    }

    private static double Original(BrowserRect rect, BrowserEdges radii, double x, double y)
    {
        if (rect.Width <= 0 || rect.Height <= 0) return 0;
        double radius = x < rect.X + rect.Width / 2 ? y < rect.Y + rect.Height / 2 ? radii.Top : radii.Left : y < rect.Y + rect.Height / 2 ? radii.Right : radii.Bottom;
        double qx = Math.Abs(x - rect.X - rect.Width / 2) - rect.Width / 2 + radius;
        double qy = Math.Abs(y - rect.Y - rect.Height / 2) - rect.Height / 2 + radius;
        double distance = Math.Sqrt(Math.Max(0, qx) * Math.Max(0, qx) + Math.Max(0, qy) * Math.Max(0, qy)) + Math.Min(Math.Max(qx, qy), 0) - radius;
        return Math.Clamp(.5 - distance, 0, 1);
    }
}