using XFESystem.Desktop; using XFESystem.Browser; namespace XfePaintBaseline; /// Coverage clipping for rounded overflow, independent of a platform graphics API. internal sealed class BaselineClipCanvas(IDesktopCanvas canvas) : IDesktopCoverageCanvas { private readonly List shapes=[]; private readonly Stack 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 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.Length0; } 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=1)BlendCoverage(command.Color,left,top,mask.Width,mask.Height,mask.Alpha); else { for(int i=0;icanvas.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(); }