Bug 249684

Summary: Run WindowEventLoop tasks in at post-rendering update time
Product: WebKit Reporter: Simon Fraser (smfr) <simon.fraser>
Component: DOMAssignee: Simon Fraser (smfr) <simon.fraser>
Status: NEW ---    
Severity: Normal CC: cdumez, rniwa, simon.fraser, webkit-bug-importer, wenson_hsieh
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=249807

Description Simon Fraser (smfr) 2022-12-20 16:26:11 PST
I was trying to implement `testRunner.renderingUpdate()` so you could write a test like:

        window.addEventListener('load', async () => {
            await testRunner.renderingUpdate();
            debug('rendering update complete');
            // do stuff
        }, false);


However, that turned out have flakey behavior with respect to the ordering of rAF callbacks:

        window.addEventListener('load', async () => {
            requestAnimationFrame(() => {
                debug('requestAnimationFrame callback');

                requestAnimationFrame(() => {
                    debug('second requestAnimationFrame callback, which should always come after the "rendering update complete"');
                });
            });

            await testRunner.renderingUpdate();
            debug('rendering update complete');
        }, false);

Sometimes the second rAF callback happened before "rendering update complete" and sometimes after. This depended on the timing of the microtask callbacks fired from WindowEventLoop, which I believe handles the resume of the load function when the `renderingUpdate` Promise is resolved.

The source of unpredictability which I identified was the timing of the zero-delay timer in WindowEventLoop. The incorrect behavior happened when the WindowEventLoop timer fired between `TiledCoreAnimationDrawingArea::scheduleRenderingUpdateRunLoopObserver()` and `TiledCoreAnimationDrawingArea::updateRenderingRunLoopCallback()`. There's already code that tries to avoid timing firing delaying the runloop observer for long periods of time (`breakToAllowRenderingUpdate()`), so we can piggyback off that to avoid this timer firing between the scheduling and the fire of the CFRunLoopObserver that controls the rendering update.
Comment 1 Radar WebKit Bug Importer 2022-12-20 16:26:44 PST
<rdar://problem/103575958>
Comment 2 Simon Fraser (smfr) 2022-12-20 16:34:13 PST
Pull request: https://github.com/WebKit/WebKit/pull/7944
Comment 3 Simon Fraser (smfr) 2022-12-21 10:46:24 PST
Turns out that this affects test behavior, I think largely because at Document::finishedParsing() time we call WebPage::unfreezeLayerTree() which triggers a rendering update, so the first WindowEventLoop opportunity is postponed. This means that a test with a zero-delay JS timer ends up running that timer logic before the WindowEventLoop task, instead of after.
Comment 4 Simon Fraser (smfr) 2023-01-03 16:57:35 PST Comment hidden (obsolete)
Comment 5 Simon Fraser (smfr) 2023-06-07 08:17:17 PDT
Not pursuing this any more.