using XFESystem.Browser; using XFESystem.Core; using XFESystem.Desktop; using Xunit; namespace XFESystem.Desktop.Tests; public sealed class DesktopRenderYieldTests { [Fact] public void PreviewSkipsStartPageAndCannotRunScriptsFromAnAbortedFirstFrame() { var canvas = new YieldCanvas { YieldOnWebPainting = false }; var storage = new MemoryWorkspace(seed: false); string path = SystemPaths.Combine(SystemPaths.Documents, "First.md"); storage.WriteText(path, "# Actual preview heading\n\nThis paragraph comes from the file."); var trace = new List(); var desktop = new DesktopSession(canvas, storage, new BrowserService { Trace = trace.Add }); desktop.Open(DesktopApplication.Editor, path); desktop.Key(DesktopKey.Run); var preview = Assert.IsType(desktop.ActiveWindow!.PreviewSession); Assert.DoesNotContain(trace, line => line.StartsWith("XFE_BROWSER_SCRIPT_BEGIN", StringComparison.Ordinal)); Assert.DoesNotContain(trace, line => line.Contains("JavaScript ready", StringComparison.Ordinal)); canvas.YieldOnWebPainting = true; desktop.Render(); Assert.False(desktop.LastFrameCompleted); Assert.False(preview.DocumentFirstFramePresented); desktop.AdvanceFeedback(20); Assert.DoesNotContain(preview.LoadedResources, resource => resource.Kind == "script"); canvas.YieldOnWebPainting = canvas.YieldPending = false; desktop.Render(); Assert.True(desktop.LastFrameCompleted); Assert.True(preview.DocumentFirstFramePresented); Assert.Contains(canvas.Texts, value => value.Contains("Actual", StringComparison.Ordinal)); desktop.AdvanceFeedback(40); // Construct Jint after physical presentation. desktop.AdvanceFeedback(60); // Run the first original script. Assert.Single(preview.LoadedResources, resource => resource.Kind == "script"); } [Fact] public void WebViewportResizeRepaintsItsReflowButPureWindowTranslationStillReusesBody() { var canvas=new YieldCanvas{YieldOnWebPainting=false};var desktop=new DesktopSession(canvas,new MemoryWorkspace(),new BrowserService(new Transport())); var window=desktop.Open(DesktopApplication.Browser,"http://yield.test/Index.html");desktop.Render(); var bounds=window.Bounds;int x=bounds.X+bounds.Width-5,y=bounds.Y+bounds.Height-5; desktop.Pointer(x,y,true,timestampMs:1000);desktop.Render(); desktop.Pointer(x+20,y+20,true,timestampMs:1020);desktop.Render(); Assert.NotEqual(bounds,window.Bounds);Assert.Equal(0,canvas.PreservedRegions); desktop.Pointer(x+20,y+20,false,timestampMs:1040);desktop.Render(); bounds=window.Bounds;x=bounds.X+bounds.Width/2;y=bounds.Y+14; desktop.Pointer(x,y,true,timestampMs:2000);desktop.Render(); desktop.Pointer(x+20,y+8,true,timestampMs:2020);desktop.Render(); Assert.True(canvas.PreservedRegions>0);Assert.Equal(bounds.Width,window.Bounds.Width);Assert.Equal(bounds.Height,window.Bounds.Height); } [Fact] public void CancelledWebFrameIsNotCachedOrPresentedAndDirtyFrameRetriesSuccessfully() { var canvas=new YieldCanvas();var browser=new BrowserService(new Transport());var desktop=new DesktopSession(canvas,new MemoryWorkspace(),browser); var window=desktop.Open(DesktopApplication.Browser,"http://yield.test/Index.html"); desktop.Render(); Assert.False(desktop.LastFrameCompleted);Assert.True(desktop.NeedsRender);Assert.Equal(1,desktop.RenderYieldCount); Assert.Equal(0,canvas.Presents);Assert.Equal(0,canvas.StoredFrames);Assert.Equal(0,canvas.SavedScenes); Assert.True(canvas.YieldPending);Assert.True(canvas.EndedPreservation>0);Assert.Equal(new DesktopBounds(0,0,canvas.Width,canvas.Height),canvas.LastScene); Assert.Equal(1,canvas.AbortedPreservation);Assert.False(canvas.PendingScanoutSkip); Assert.Same(window,desktop.ActiveWindow);Assert.DoesNotContain("Rendering failed",canvas.Texts); canvas.YieldOnWebPainting=false;canvas.YieldPending=false; desktop.Render(); Assert.True(desktop.LastFrameCompleted);Assert.False(desktop.NeedsRender);Assert.Equal(1,desktop.RenderYieldCount); Assert.Equal(1,canvas.Presents);Assert.Equal(1,canvas.StoredFrames);Assert.Equal(1,canvas.SavedScenes); Assert.Same(window,desktop.ActiveWindow);Assert.DoesNotContain("Rendering failed",canvas.Texts); desktop.Render();Assert.False(desktop.LastFrameCompleted);Assert.Equal(1,canvas.Presents); } private sealed class Transport:IWebTransport { public WebResponse Get(Uri address,BrowserLimits limits)=>new(address,200,"text/html", "
Actual web paint
"); } private sealed class YieldCanvas:IDesktopCoverageCanvas,IDesktopWebFrameCache,IDesktopSceneMotionCanvas,IDesktopRenderYieldCanvas,IDesktopWebCanvas { public int Width=>1280;public int Height=>800;public bool SupportsSceneCache=>true; public bool YieldPending, YieldOnWebPainting=true,PendingScanoutSkip;public int Presents,StoredFrames,SavedScenes,EndedPreservation,AbortedPreservation,PreservedRegions; public DesktopBounds LastScene;public List Texts=[]; public bool RenderYieldRequested=>YieldPending; public DesktopBounds WebPaintClip{get{if(YieldOnWebPainting){YieldPending=true;PendingScanoutSkip=true;}return LastScene;}} public void BeginScene(DesktopBounds bounds){LastScene=bounds;} public void BlendCoverage(uint rgb,int x,int y,int width,int height,ReadOnlySpan source) {if(YieldPending)throw new DesktopRenderYieldException();} public bool TryRestoreWebFrame(long pageId,long revision,long layoutVersion,DesktopBounds bounds,double scrollX,double scrollY)=>false; public void StoreWebFrame(long pageId,long revision,long layoutVersion,DesktopBounds bounds,double scrollX,double scrollY){StoredFrames++;} public void SaveScene(DesktopBounds bounds){SavedScenes++;} public void EndScenePreservation(){EndedPreservation++;} public void AbortScenePreservation(){AbortedPreservation++;PendingScanoutSkip=false;EndScenePreservation();} public void PreserveTranslatedSceneRegion(DesktopBounds source,int x,int y){PreservedRegions++;} 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){Texts.Add(text);} public void PushClip(DesktopBounds bounds) { } public void PopClip() { } public double MeasureWebText(string text, double size, string family, int weight) => text.Length * size * .6; public (int Width, int Height, byte[] Alpha) RasterizeWebText(string text, double size, string family, int weight) { Texts.Add(text); return (1, 1, [255]); } public void WebText(string text, uint color, double x, double y, double size, string family, int weight, double opacity = 1) { if (YieldPending) throw new DesktopRenderYieldException(); Texts.Add(text); } public void Present(){Presents++;} } }