Skip to content

Commit b4e311c

Browse files
committed
Bug 1800882 - Clean up rvfc a bit to match the spec closer. r=aosmond
Deal with throttled docs only once upfront, since ShouldThrottleFrameRequests is kind of expensive (doing a full IntersectionObserver check). Add proper spec quotes too, while at it. This also fixes the failure that got the previous patch backed out. Differential Revision: https://phabricator.services.mozilla.com/D217708
1 parent de8b344 commit b4e311c

File tree

2 files changed

+109
-69
lines changed

2 files changed

+109
-69
lines changed

layout/base/nsRefreshDriver.cpp

+103-69
Original file line numberDiff line numberDiff line change
@@ -2361,66 +2361,26 @@ void nsRefreshDriver::UpdateAnimationsAndSendEvents() {
23612361
}
23622362
}
23632363

2364-
void nsRefreshDriver::RunVideoAndFrameRequestCallbacks(TimeStamp aNowTime) {
2365-
if (!mNeedToRunFrameRequestCallbacks) {
2366-
return;
2367-
}
2368-
mNeedToRunFrameRequestCallbacks = false;
2369-
const bool tickThrottledFrameRequests = [&] {
2370-
if (mThrottled) {
2371-
// We always tick throttled frame requests if the entire refresh driver is
2372-
// throttled, because in that situation throttled frame requests tick at
2373-
// the same frequency as non-throttled frame requests.
2374-
return true;
2375-
}
2376-
if (aNowTime >= mNextThrottledFrameRequestTick) {
2377-
mNextThrottledFrameRequestTick =
2378-
aNowTime + mThrottledFrameRequestInterval;
2379-
return true;
2380-
}
2381-
return false;
2382-
}();
2383-
2384-
if (NS_WARN_IF(!mPresContext)) {
2385-
return;
2386-
}
2387-
// Grab all of our documents that can fire frame request callbacks up front.
2388-
AutoTArray<RefPtr<Document>, 8> docs;
2389-
auto ShouldCollect = [](const Document* aDoc) {
2390-
return aDoc->ShouldFireFrameRequestCallbacks();
2391-
};
2392-
if (ShouldCollect(mPresContext->Document())) {
2393-
docs.AppendElement(mPresContext->Document());
2394-
}
2395-
mPresContext->Document()->CollectDescendantDocuments(docs, ShouldCollect);
2396-
2397-
// First check for and run video frame callbacks. These can trigger new frame
2398-
// request callbacks that we need to handle in the following pass.
2364+
void nsRefreshDriver::RunVideoFrameCallbacks(
2365+
const nsTArray<RefPtr<Document>>& aDocs, TimeStamp aNowTime) {
2366+
// For each fully active Document in docs, for each associated video element
2367+
// for that Document, run the video frame request callbacks passing now as the
2368+
// timestamp.
23992369
Maybe<TimeStamp> nextTickHint;
2400-
for (Document* doc : docs) {
2401-
if (!tickThrottledFrameRequests && doc->ShouldThrottleFrameRequests()) {
2402-
// Skip throttled docs if it's not time to un-throttle them yet.
2403-
// FIXME(emilio): It's a bit subtle to just set this to true here, but
2404-
// matches pre-existing behavior for throttled docs. It seems at least we
2405-
// should EnsureTimerStarted too? But that kinda defeats the throttling, a
2406-
// little bit? For now, preserve behavior.
2407-
mNeedToRunFrameRequestCallbacks = true;
2408-
continue;
2409-
}
2370+
for (Document* doc : aDocs) {
24102371
nsTArray<RefPtr<HTMLVideoElement>> videoElms;
24112372
doc->TakeVideoFrameRequestCallbacks(videoElms);
24122373
if (videoElms.IsEmpty()) {
24132374
continue;
24142375
}
2415-
if (!nextTickHint) {
2416-
nextTickHint = GetNextTickHint();
2417-
}
2418-
AUTO_PROFILER_TRACING_MARKER_INNERWINDOWID(
2419-
"Paint", "requestVideoFrame callbacks", GRAPHICS, doc->InnerWindowID());
2376+
24202377
DOMHighResTimeStamp timeStamp = 0;
24212378
DOMHighResTimeStamp nextTickTimeStamp = 0;
2422-
if (nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow()) {
2379+
if (auto* innerWindow = doc->GetInnerWindow()) {
24232380
if (Performance* perf = innerWindow->GetPerformance()) {
2381+
if (!nextTickHint) {
2382+
nextTickHint = GetNextTickHint();
2383+
}
24242384
timeStamp = perf->TimeStampToDOMHighResForRendering(aNowTime);
24252385
nextTickTimeStamp =
24262386
nextTickHint
@@ -2429,6 +2389,9 @@ void nsRefreshDriver::RunVideoAndFrameRequestCallbacks(TimeStamp aNowTime) {
24292389
}
24302390
// else window is partially torn down already
24312391
}
2392+
2393+
AUTO_PROFILER_TRACING_MARKER_INNERWINDOWID(
2394+
"Paint", "requestVideoFrame callbacks", GRAPHICS, doc->InnerWindowID());
24322395
for (const auto& videoElm : videoElms) {
24332396
nsTArray<VideoFrameRequest> callbacks;
24342397
VideoFrameCallbackMetadata metadata;
@@ -2465,40 +2428,37 @@ void nsRefreshDriver::RunVideoAndFrameRequestCallbacks(TimeStamp aNowTime) {
24652428
}
24662429
}
24672430
}
2431+
}
24682432

2469-
// Next check for and run frame request callbacks.
2470-
for (Document* doc : docs) {
2471-
if (!tickThrottledFrameRequests && doc->ShouldThrottleFrameRequests()) {
2472-
// Skip throttled docs if it's not time to un-throttle them yet.
2473-
MOZ_ASSERT(mNeedToRunFrameRequestCallbacks);
2474-
continue;
2475-
}
2476-
AutoTArray<FrameRequest, 8> callbacks;
2433+
void nsRefreshDriver::RunFrameRequestCallbacks(
2434+
const nsTArray<RefPtr<Document>>& aDocs, TimeStamp aNowTime) {
2435+
for (Document* doc : aDocs) {
2436+
nsTArray<FrameRequest> callbacks;
24772437
doc->TakeFrameRequestCallbacks(callbacks);
24782438
if (callbacks.IsEmpty()) {
24792439
continue;
24802440
}
2481-
AUTO_PROFILER_TRACING_MARKER_INNERWINDOWID(
2482-
"Paint", "requestAnimationFrame callbacks", GRAPHICS,
2483-
doc->InnerWindowID());
2484-
TimeStamp startTime = TimeStamp::Now();
2485-
nsCOMPtr<nsIGlobalObject> global;
2441+
24862442
DOMHighResTimeStamp timeStamp = 0;
2487-
if (nsPIDOMWindowInner* innerWindow = doc->GetInnerWindow()) {
2443+
RefPtr innerWindow = nsGlobalWindowInner::Cast(doc->GetInnerWindow());
2444+
if (innerWindow) {
24882445
if (Performance* perf = innerWindow->GetPerformance()) {
24892446
timeStamp = perf->TimeStampToDOMHighResForRendering(aNowTime);
24902447
}
2491-
global = nsGlobalWindowInner::Cast(innerWindow);
24922448
// else window is partially torn down already
24932449
}
24942450

2451+
AUTO_PROFILER_TRACING_MARKER_INNERWINDOWID(
2452+
"Paint", "requestAnimationFrame callbacks", GRAPHICS,
2453+
doc->InnerWindowID());
2454+
const TimeStamp startTime = TimeStamp::Now();
24952455
for (const auto& callback : callbacks) {
24962456
if (doc->IsCanceledFrameRequestCallback(callback.mHandle)) {
24972457
continue;
24982458
}
24992459

25002460
CallbackDebuggerNotificationGuard guard(
2501-
global, DebuggerNotificationType::RequestAnimationFrameCallback);
2461+
innerWindow, DebuggerNotificationType::RequestAnimationFrameCallback);
25022462

25032463
// MOZ_KnownLive is OK, because the stack array frameRequestCallbacks
25042464
// keeps callback alive and the mCallback strong reference can't be
@@ -2517,6 +2477,67 @@ void nsRefreshDriver::RunVideoAndFrameRequestCallbacks(TimeStamp aNowTime) {
25172477
}
25182478
}
25192479

2480+
void nsRefreshDriver::RunVideoAndFrameRequestCallbacks(TimeStamp aNowTime) {
2481+
if (!mNeedToRunFrameRequestCallbacks) {
2482+
return;
2483+
}
2484+
mNeedToRunFrameRequestCallbacks = false;
2485+
const bool tickThrottledFrameRequests = [&] {
2486+
if (mThrottled) {
2487+
// We always tick throttled frame requests if the entire refresh driver is
2488+
// throttled, because in that situation throttled frame requests tick at
2489+
// the same frequency as non-throttled frame requests.
2490+
return true;
2491+
}
2492+
if (aNowTime >= mNextThrottledFrameRequestTick) {
2493+
mNextThrottledFrameRequestTick =
2494+
aNowTime + mThrottledFrameRequestInterval;
2495+
return true;
2496+
}
2497+
return false;
2498+
}();
2499+
2500+
if (NS_WARN_IF(!mPresContext)) {
2501+
return;
2502+
}
2503+
// Grab all of our documents that can fire frame request callbacks up front.
2504+
AutoTArray<RefPtr<Document>, 8> docs;
2505+
auto ShouldCollect = [](const Document* aDoc) {
2506+
// TODO(emilio): Consider removing HasFrameRequestCallbacks() to deal with
2507+
// callbacks posted from other documents more per spec?
2508+
//
2509+
// If we do that we also need to tweak the throttling code to not set
2510+
// mNeedToRunFrameRequestCallbacks unnecessarily... Check what other engines
2511+
// do too.
2512+
return aDoc->HasFrameRequestCallbacks() &&
2513+
aDoc->ShouldFireFrameRequestCallbacks();
2514+
};
2515+
if (ShouldCollect(mPresContext->Document())) {
2516+
docs.AppendElement(mPresContext->Document());
2517+
}
2518+
mPresContext->Document()->CollectDescendantDocuments(docs, ShouldCollect);
2519+
// Skip throttled docs if it's not time to un-throttle them yet.
2520+
if (!tickThrottledFrameRequests) {
2521+
const size_t sizeBefore = docs.Length();
2522+
docs.RemoveElementsBy(
2523+
[](Document* aDoc) { return aDoc->ShouldThrottleFrameRequests(); });
2524+
if (sizeBefore != docs.Length()) {
2525+
// FIXME(emilio): It's a bit subtle to just set this to true here, but
2526+
// matches pre-existing behavior for throttled docs. It seems at least we
2527+
// should EnsureTimerStarted too? But that kinda defeats the throttling, a
2528+
// little bit? For now, preserve behavior.
2529+
mNeedToRunFrameRequestCallbacks = true;
2530+
}
2531+
}
2532+
2533+
if (docs.IsEmpty()) {
2534+
return;
2535+
}
2536+
2537+
RunVideoFrameCallbacks(docs, aNowTime);
2538+
RunFrameRequestCallbacks(docs, aNowTime);
2539+
}
2540+
25202541
static StaticAutoPtr<AutoTArray<RefPtr<Task>, 8>> sPendingIdleTasks;
25212542

25222543
void nsRefreshDriver::DispatchIdleTaskAfterTickUnlessExists(Task* aTask) {
@@ -2734,9 +2755,22 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
27342755
// Step 12. For each doc of docs, run the fullscreen steps for doc.
27352756
RunFullscreenSteps();
27362757

2737-
// Step 14. For each doc of docs, run the video frame callbacks and animation
2738-
// frame callbacks for doc.
2758+
// TODO: Step 13. For each doc of docs, if the user agent detects that the
2759+
// backing storage associated with a CanvasRenderingContext2D or an
2760+
// OffscreenCanvasRenderingContext2D, context, has been lost, then it must run
2761+
// the context lost steps for each such context.
2762+
2763+
// Step 13.5. (https://wicg.github.io/video-rvfc/#video-rvfc-procedures):
2764+
//
2765+
// For each fully active Document in docs, for each associated video element
2766+
// for that Document, run the video frame request callbacks passing now as
2767+
// the timestamp.
2768+
//
2769+
// Step 14. For each doc of docs, run the animation frame callbacks for doc,
2770+
// passing in the relative high resolution time given frameTimestamp and doc's
2771+
// relevant global object as the timestamp.
27392772
RunVideoAndFrameRequestCallbacks(aNowTime);
2773+
27402774
MaybeIncreaseMeasuredTicksSinceLoading();
27412775

27422776
// Step 17. For each doc of docs, if the focused area of doc is not a

layout/base/nsRefreshDriver.h

+6
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,12 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
489489

490490
MOZ_CAN_RUN_SCRIPT
491491
void RunVideoAndFrameRequestCallbacks(mozilla::TimeStamp aNowTime);
492+
MOZ_CAN_RUN_SCRIPT
493+
void RunVideoFrameCallbacks(const nsTArray<RefPtr<mozilla::dom::Document>>&,
494+
mozilla::TimeStamp aNowTime);
495+
MOZ_CAN_RUN_SCRIPT
496+
void RunFrameRequestCallbacks(const nsTArray<RefPtr<mozilla::dom::Document>>&,
497+
mozilla::TimeStamp aNowTime);
492498
void UpdateIntersectionObservations(mozilla::TimeStamp aNowTime);
493499
void UpdateRelevancyOfContentVisibilityAutoFrames();
494500
MOZ_CAN_RUN_SCRIPT void

0 commit comments

Comments
 (0)