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();
}