Files
sousa-gecko/testing/web-platform/tests/requestidlecallback/callback-iframe-different-origin.html
T
Scott Haseley 651cc861b7 Bug 1956357 [wpt PR 51587] - requestIdleCallback: Fix idle period brittleness, a=testonly
Automatic update from web-platform-tests
requestIdleCallback: Fix idle period brittleness

This CL fixes a few issues with idle periods not starting when they
should due to not requesting the `BeginMainFrameNotExpected` signals
from the compositor.

Idle periods, which requestIdleCallback tasks are confined to run in,
are triggered by:
 1. Frame production (`BeginMainFrame` from any source). We can start a
    short idle period after every `BeginMainFrame` (if there are idle
    tasks and time remaining).
 2. `BeginMainFrameNotExpected` signals from the compositor. These are
    requested through `LayerTreeHost` via `PageSchedulerImpl` --> `Page`
    --> `ChromeClient` --> ... These signals are necessary to start
    idle periods after frame production stops.

There are a couple scenarios where we receive `BeginMainFrame`s signals
from a `WidgetScheduler`, but not `BeginMainFrameNotExpected` signals,
which causes us to stop running idle tasks.

First, idle tasks might not run in OOPIFs. There's an early return in
`Page::RequestBeginMainFrameNotExpected()`  if the main frame is not
local, which means if a render process holds a single OOPIF, the idle period-starting signals from the compositor are never sent, and idle
tasks might never run. Note: rendering will temporarily unblock idle
tasks, because of (1) above, e.g. mousemove in the frame (see
crbug.com/40785325).

Second, idle tasks might not run if a popup is showing (e.g. date
picker). See crbug.com/378738907 for an example. The root cause here is
that the `WebPagePopupImpl`'s `ChromeClient` doesn't implement `RequestBeginFrameNotExpected()`.

This CL fixes these issues by refactoring how the signals are requested from the compositor, and by ensuring we always request the signals from any `BeginMainFrame` source:
 - Add `WidgetScheduler::Delegate`, through which the signals are
   requested. The signals are received via `WidgetScheduler`, so this
   simplifies the existing plumbing. `WidgetBase`, which is the
   creator/owner of `WidgetScheduler`, implements the `Delegate`
   interface.
 - `WidgetScheduler` stores a raw_ptr to the `Delegate`, which is
   cleared in `WillShutdown()` (newly added, called from `WidgetBase`)
 - `MainThreadSchedulerImpl` tracks the non-shutdown widget schedulers
   (entries are removed on `WillShutdown()`). The MTSI requests the
   signals from each `WidgetScheduler`.
 - If we're already receiving the signals from a `WidgetScheduler` and
   a new `WidgetScheduler` is created, immediately request the signals
   to keep things in sync. This also handles the case where idle tasks
   are posted prior to any `WidgetScheduler` being created (unlikely,
   but possible since idle tasks can be queued outside of rIC).
 - On `Shutdown()`, make sure the we don't stall idle periods because
   the page being closed was in a short idle period.

Additionally:
 - This is behind a kill switch, just in case this breaks something
 - This adds a wpt test for the OOPIF case, which times out locally
   without the fix

Fixed: 40785325, 378738907
Change-Id: I616c3fbf672202aa5bb3b4ebf26c011ac5f26a24
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6006337
Reviewed-by: Stefan Zager <szager@chromium.org>
Commit-Queue: Scott Haseley <shaseley@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1437839}

--

wpt-commits: f082d92f1da8860a13d0b57cc777ef1ef89d64d4
wpt-pr: 51587
2025-03-28 08:19:38 +00:00

20 lines
619 B
HTML

<!doctype html>
<title>window.requestIdleCallback in a cross-origin iframe.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
async_test(t => {
onload = function() {
const iframe = document.createElement('iframe');
iframe.src = location.href.replace('://', '://www1.')
.replace('callback-iframe-different-origin', 'resources/child');
document.body.appendChild(iframe);
};
onmessage = function(e) {
assert_equals(e.data, 'done');
t.done();
}
}, 'Check that idle tasks run in a cross-origin iframe');
</script>