Bug 1861259 part 1: Refactor out a helper function for loop body in nsRefreshDriver::Tick. r=tnikkel

This doesn't affect behavior; it's just a pure refactoring, moving code from
being inline to being in a helper function.

Differential Revision: https://phabricator.services.mozilla.com/D191908
This commit is contained in:
Daniel Holbert 2023-10-25 23:50:04 +00:00
parent 4f15c940fa
commit 640f2e283d
2 changed files with 128 additions and 111 deletions

View File

@ -2408,6 +2408,121 @@ static CallState ReduceAnimations(Document& aDocument) {
return CallState::Continue;
}
bool nsRefreshDriver::TickObserverArray(uint32_t aIdx, TimeStamp aNowTime) {
for (RefPtr<nsARefreshObserver> obs : mObservers[aIdx].EndLimitedRange()) {
obs->WillRefresh(aNowTime);
if (!mPresContext || !mPresContext->GetPresShell()) {
return false;
}
}
// Any animation timelines updated above may cause animations to queue
// Promise resolution microtasks. We shouldn't run these, however, until we
// have fully updated the animation state.
//
// As per the "update animations and send events" procedure[1], we should
// remove replaced animations and then run these microtasks before
// dispatching the corresponding animation events.
//
// [1]
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events
if (aIdx == 1) {
nsAutoMicroTask mt;
ReduceAnimations(*mPresContext->Document());
}
// Check if running the microtask checkpoint caused the pres context to
// be destroyed.
if (aIdx == 1 && (!mPresContext || !mPresContext->GetPresShell())) {
return false;
}
if (aIdx == 1) {
// This is the FlushType::Style case.
FlushAutoFocusDocuments();
DispatchScrollEvents();
DispatchVisualViewportScrollEvents();
EvaluateMediaQueriesAndReportChanges();
DispatchAnimationEvents();
RunFullscreenSteps();
RunFrameRequestCallbacks(aNowTime);
MaybeIncreaseMeasuredTicksSinceLoading();
if (mPresContext && mPresContext->GetPresShell()) {
AutoTArray<PresShell*, 16> observers;
observers.AppendElements(mStyleFlushObservers);
for (uint32_t j = observers.Length();
j && mPresContext && mPresContext->GetPresShell(); --j) {
// Make sure to not process observers which might have been removed
// during previous iterations.
PresShell* rawPresShell = observers[j - 1];
if (!mStyleFlushObservers.RemoveElement(rawPresShell)) {
continue;
}
LogPresShellObserver::Run run(rawPresShell, this);
RefPtr<PresShell> presShell = rawPresShell;
presShell->mObservingStyleFlushes = false;
presShell->FlushPendingNotifications(
ChangesToFlush(FlushType::Style, false));
// Inform the FontFaceSet that we ticked, so that it can resolve its
// ready promise if it needs to (though it might still be waiting on
// a layout flush).
presShell->NotifyFontFaceSetOnRefresh();
mNeedToRecomputeVisibility = true;
// Record the telemetry for events that occurred between ticks.
presShell->PingPerTickTelemetry(FlushType::Style);
}
}
} else if (aIdx == 2) {
// This is the FlushType::Layout case.
AutoTArray<PresShell*, 16> observers;
observers.AppendElements(mLayoutFlushObservers);
for (uint32_t j = observers.Length();
j && mPresContext && mPresContext->GetPresShell(); --j) {
// Make sure to not process observers which might have been removed
// during previous iterations.
PresShell* rawPresShell = observers[j - 1];
if (!mLayoutFlushObservers.RemoveElement(rawPresShell)) {
continue;
}
LogPresShellObserver::Run run(rawPresShell, this);
RefPtr<PresShell> presShell = rawPresShell;
presShell->mObservingLayoutFlushes = false;
presShell->mWasLastReflowInterrupted = false;
const auto flushType = HasPendingAnimations(presShell)
? FlushType::Layout
: FlushType::InterruptibleLayout;
const ChangesToFlush ctf(flushType, false);
presShell->FlushPendingNotifications(ctf);
if (presShell->FixUpFocus()) {
presShell->FlushPendingNotifications(ctf);
}
// Inform the FontFaceSet that we ticked, so that it can resolve its
// ready promise if it needs to.
presShell->NotifyFontFaceSetOnRefresh();
mNeedToRecomputeVisibility = true;
// Record the telemetry for events that occurred between ticks.
presShell->PingPerTickTelemetry(FlushType::Layout);
}
}
// The pres context may be destroyed during we do the flushing.
if (!mPresContext || !mPresContext->GetPresShell()) {
return false;
}
return true;
}
void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
IsExtraTick aIsExtraTick /* = No */) {
MOZ_ASSERT(!nsContentUtils::GetCurrentJSContext(),
@ -2577,119 +2692,11 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
* The timer holds a reference to |this| while calling |Notify|.
* However, implementations of |WillRefresh| are permitted to destroy
* the pres context, which will cause our |mPresContext| to become
* null. If this happens, we must stop notifying observers.
* null. If this happens, TickObserverArray will tell us by returning
* false, and we must stop notifying observers.
*/
for (uint32_t i = 0; i < ArrayLength(mObservers); ++i) {
for (RefPtr<nsARefreshObserver> obs : mObservers[i].EndLimitedRange()) {
obs->WillRefresh(aNowTime);
if (!mPresContext || !mPresContext->GetPresShell()) {
StopTimer();
return;
}
}
// Any animation timelines updated above may cause animations to queue
// Promise resolution microtasks. We shouldn't run these, however, until we
// have fully updated the animation state.
//
// As per the "update animations and send events" procedure[1], we should
// remove replaced animations and then run these microtasks before
// dispatching the corresponding animation events.
//
// [1]
// https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events
if (i == 1) {
nsAutoMicroTask mt;
ReduceAnimations(*mPresContext->Document());
}
// Check if running the microtask checkpoint caused the pres context to
// be destroyed.
if (i == 1 && (!mPresContext || !mPresContext->GetPresShell())) {
StopTimer();
return;
}
if (i == 1) {
// This is the FlushType::Style case.
FlushAutoFocusDocuments();
DispatchScrollEvents();
DispatchVisualViewportScrollEvents();
EvaluateMediaQueriesAndReportChanges();
DispatchAnimationEvents();
RunFullscreenSteps();
RunFrameRequestCallbacks(aNowTime);
MaybeIncreaseMeasuredTicksSinceLoading();
if (mPresContext && mPresContext->GetPresShell()) {
AutoTArray<PresShell*, 16> observers;
observers.AppendElements(mStyleFlushObservers);
for (uint32_t j = observers.Length();
j && mPresContext && mPresContext->GetPresShell(); --j) {
// Make sure to not process observers which might have been removed
// during previous iterations.
PresShell* rawPresShell = observers[j - 1];
if (!mStyleFlushObservers.RemoveElement(rawPresShell)) {
continue;
}
LogPresShellObserver::Run run(rawPresShell, this);
RefPtr<PresShell> presShell = rawPresShell;
presShell->mObservingStyleFlushes = false;
presShell->FlushPendingNotifications(
ChangesToFlush(FlushType::Style, false));
// Inform the FontFaceSet that we ticked, so that it can resolve its
// ready promise if it needs to (though it might still be waiting on
// a layout flush).
presShell->NotifyFontFaceSetOnRefresh();
mNeedToRecomputeVisibility = true;
// Record the telemetry for events that occurred between ticks.
presShell->PingPerTickTelemetry(FlushType::Style);
}
}
} else if (i == 2) {
// This is the FlushType::Layout case.
AutoTArray<PresShell*, 16> observers;
observers.AppendElements(mLayoutFlushObservers);
for (uint32_t j = observers.Length();
j && mPresContext && mPresContext->GetPresShell(); --j) {
// Make sure to not process observers which might have been removed
// during previous iterations.
PresShell* rawPresShell = observers[j - 1];
if (!mLayoutFlushObservers.RemoveElement(rawPresShell)) {
continue;
}
LogPresShellObserver::Run run(rawPresShell, this);
RefPtr<PresShell> presShell = rawPresShell;
presShell->mObservingLayoutFlushes = false;
presShell->mWasLastReflowInterrupted = false;
const auto flushType = HasPendingAnimations(presShell)
? FlushType::Layout
: FlushType::InterruptibleLayout;
const ChangesToFlush ctf(flushType, false);
presShell->FlushPendingNotifications(ctf);
if (presShell->FixUpFocus()) {
presShell->FlushPendingNotifications(ctf);
}
// Inform the FontFaceSet that we ticked, so that it can resolve its
// ready promise if it needs to.
presShell->NotifyFontFaceSetOnRefresh();
mNeedToRecomputeVisibility = true;
// Record the telemetry for events that occurred between ticks.
presShell->PingPerTickTelemetry(FlushType::Layout);
}
}
// The pres context may be destroyed during we do the flushing.
if (!mPresContext || !mPresContext->GetPresShell()) {
if (!TickObserverArray(i, aNowTime)) {
StopTimer();
return;
}

View File

@ -507,6 +507,16 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
No,
Yes,
};
// Helper for Tick, to call WillRefresh(aNowTime) on each entry in
// mObservers[aIdx] and then potentially do some additional post-notification
// work that's associated with the FlushType corresponding to aIdx.
//
// Returns true on success, or false if one of our calls has destroyed our
// pres context (in which case our callsite Tick() should immediately bail).
MOZ_CAN_RUN_SCRIPT
bool TickObserverArray(uint32_t aIdx, mozilla::TimeStamp aNowTime);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
void Tick(mozilla::VsyncId aId, mozilla::TimeStamp aNowTime,
IsExtraTick aIsExtraTick = IsExtraTick::No);