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

XFESystem

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

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

using XFESystem.Browser;
namespace XfePaintBaseline;

/// <summary>Coverage clipping for rounded overflow, independent of a platform graphics API.</summary>
internal sealed class BaselineClipCanvas(IDesktopCanvas canvas) : IDesktopCoverageCanvas
{
    private readonly List<BrowserRoundedClip> shapes=[];
    private readonly Stack<int> checkpoints=[];
    private byte[] rowBuffer=[];
    public int Width=>canvas.Width;
    public int Height=>canvas.Height;
    public int NativeWidth=>canvas.NativeWidth;
    public int NativeHeight=>canvas.NativeHeight;
    public int ScalePercent=>canvas.ScalePercent;
    public bool Active=>shapes.Count>0;
    public void Push(BrowserRoundedClip? shape,double dx,double dy)
    {
        checkpoints.Push(shapes.Count);
        if(shape is null)return;
        double scale=ScalePercent/100d;var r=shape.Bounds.Translate(dx,dy);var radius=shape.Radius;
        shapes.Add(new(new(r.X*scale,r.Y*scale,r.Width*scale,r.Height*scale),new(radius.Top*scale,radius.Right*scale,radius.Bottom*scale,radius.Left*scale)));
    }
    public void Pop(){if(checkpoints.TryPop(out int count)&&count<shapes.Count)shapes.RemoveRange(count,shapes.Count-count);}
    public void BlendCoverage(uint rgb,int x,int y,int width,int height,ReadOnlySpan<byte> source)
    {
        if(canvas is not IDesktopCoverageCanvas coverage)return;
        if(!Active){coverage.BlendCoverage(rgb,x,y,width,height,source);return;}
        if(width<=0||height<=0||(long)width*height!=source.Length)throw new ArgumentException("Coverage dimensions do not match.");
        // Clip before allocating. A page may have enormous offscreen geometry;
        // only pixels inside the actual framebuffer need mask work.
        int left=Math.Max(0,x),right=(int)Math.Min((long)NativeWidth,(long)x+width),top=Math.Max(0,y),bottom=(int)Math.Min((long)NativeHeight,(long)y+height);
        if(right<=left||bottom<=top)return;
        int rowWidth=right-left;
        if(rowBuffer.Length<rowWidth)rowBuffer=new byte[rowWidth];
        var row=rowBuffer;
        for(int py=top;py<bottom;py++)
        {
            bool any=false;
            for(int px=left;px<right;px++)
            {
                double alpha=source[(py-y)*width+px-x];
                foreach(var shape in shapes){alpha*=BaselineBoxPainter.Coverage(shape.Bounds,shape.Radius,px+.5,py+.5);if(alpha==0)break;}
                row[px-left]=(byte)Math.Clamp(Math.Round(alpha),0,255);any|=row[px-left]>0;
            }
            if(any)coverage.BlendCoverage(rgb,left,py,rowWidth,1,row.AsSpan(0,rowWidth));
        }
    }
    public void Fill(uint rgb,int x,int y,int width,int height)
    {
        if(!Active){canvas.Fill(rgb,x,y,width,height);return;}
        double scale=ScalePercent/100d;int left=(int)Math.Round(x*scale),top=(int)Math.Round(y*scale),right=(int)Math.Round((x+(double)width)*scale),bottom=(int)Math.Round((y+(double)height)*scale);
        left=Math.Max(0,left);top=Math.Max(0,top);right=Math.Min(NativeWidth,right);bottom=Math.Min(NativeHeight,bottom);
        if(right<=left||bottom<=top)return;
        var row=new byte[right-left];Array.Fill(row,(byte)255);
        for(int py=top;py<bottom;py++)BlendCoverage(rgb,left,py,row.Length,1,row);
    }
    public void WebText(IDesktopWebCanvas web,BrowserDrawCommand command,BrowserRect bounds)
    {
        double scale=ScalePercent/100d;
        var mask=web.RasterizeWebText(command.Text,command.Font.Size*scale,command.Font.Family,command.Font.Weight);
        int left=(int)Math.Round(bounds.X*scale),top=(int)Math.Round(bounds.Y*scale);
        if(command.Opacity>=1)BlendCoverage(command.Color,left,top,mask.Width,mask.Height,mask.Alpha);
        else
        { for(int i=0;i<mask.Alpha.Length;i++)mask.Alpha[i]=(byte)Math.Clamp(Math.Round(mask.Alpha[i]*command.Opacity),0,255);BlendCoverage(command.Color,left,top,mask.Width,mask.Height,mask.Alpha); }
    }
    public void Line(uint rgb,int x1,int y1,int x2,int y2)=>canvas.Line(rgb,x1,y1,x2,y2);
    public void Text(string text,uint rgb,int x,int y)=>canvas.Text(text,rgb,x,y);
    public void Present()=>canvas.Present();
}