Bug 1895870 - Simplify refresh driver observer set-up. r=smaug

There's no call to AddRefreshObserver(FlushType::Layout), so we don't
need to track layout flushes. The only reason we need
mLayoutFlushObservers is so that reflows triggered from the style flush
get processed. But at that point, we can just flush layout directly.

There's no really good distinction between style flushes and layout
flushes with container queries anyways, so this makes the code simpler
to reason about.

Differential Revision: https://phabricator.services.mozilla.com/D209924
This commit is contained in:
Emilio Cobos Álvarez 2024-05-14 08:12:03 +00:00
parent 3609010342
commit 57df8917ac
13 changed files with 121 additions and 284 deletions

View file

@ -477,7 +477,7 @@ void NotificationController::ScheduleProcessing() {
// NotificationCollector: protected
bool NotificationController::IsUpdatePending() {
return mPresShell->IsLayoutFlushObserver() ||
return mPresShell->ObservingStyleFlushes() ||
mObservingState == eRefreshProcessingForUpdate || WaitingForParent() ||
mContentInsertions.Count() != 0 || mNotifications.Length() != 0 ||
!mTextArray.IsEmpty() ||

View file

@ -351,10 +351,10 @@ async function focusButtonAndPressKey(key, elem, modifiers) {
elem.setAttribute("tabindex", "-1");
elem.focus();
elem.removeAttribute("tabindex");
await focused;
EventUtils.synthesizeKey(key, modifiers);
elem.removeAttribute("tabindex");
elem.blur();
}

View file

@ -457,14 +457,13 @@ struct nsCallbackEventRequest {
#ifdef DEBUG
# define ASSERT_REFLOW_SCHEDULED_STATE() \
{ \
if (ObservingLayoutFlushes()) { \
if (ObservingStyleFlushes()) { \
MOZ_ASSERT( \
mDocument->GetBFCacheEntry() || \
mPresContext->RefreshDriver()->IsLayoutFlushObserver(this), \
mPresContext->RefreshDriver()->IsStyleFlushObserver(this), \
"Unexpected state"); \
} else { \
MOZ_ASSERT( \
!mPresContext->RefreshDriver()->IsLayoutFlushObserver(this), \
MOZ_ASSERT(!mPresContext->RefreshDriver()->IsStyleFlushObserver(this), \
"Unexpected state"); \
} \
}
@ -775,7 +774,6 @@ PresShell::PresShell(Document* aDocument)
nsISelectionDisplay::DISPLAY_IMAGES),
mChangeNestCount(0),
mRenderingStateFlags(RenderingStateFlags::None),
mInFlush(false),
mCaretEnabled(false),
mNeedLayoutFlush(true),
mNeedStyleFlush(true),
@ -798,7 +796,6 @@ PresShell::PresShell(Document* aDocument)
mObservesMutationsForPrint(false),
mWasLastReflowInterrupted(false),
mObservingStyleFlushes(false),
mObservingLayoutFlushes(false),
mResizeEventPending(false),
mFontSizeInflationForceEnabled(false),
mFontSizeInflationDisabledInMasterProcess(false),
@ -1355,6 +1352,7 @@ void PresShell::Destroy() {
// sometimes spins the event queue when plug-ins are involved(!).
// XXXmats is this still needed now that plugins are gone?
StopObservingRefreshDriver();
mObservingStyleFlushes = false;
if (rd->GetPresContext() == GetPresContext()) {
rd->RevokeViewManagerFlush();
@ -1402,9 +1400,6 @@ void PresShell::StopObservingRefreshDriver() {
if (mResizeEventPending) {
rd->RemoveResizeEventFlushObserver(this);
}
if (mObservingLayoutFlushes) {
rd->RemoveLayoutFlushObserver(this);
}
if (mObservingStyleFlushes) {
rd->RemoveStyleFlushObserver(this);
}
@ -1415,9 +1410,6 @@ void PresShell::StartObservingRefreshDriver() {
if (mResizeEventPending) {
rd->AddResizeEventFlushObserver(this);
}
if (mObservingLayoutFlushes) {
rd->AddLayoutFlushObserver(this);
}
if (mObservingStyleFlushes) {
rd->AddStyleFlushObserver(this);
}
@ -1500,7 +1492,7 @@ void PresShell::AddAuthorSheet(StyleSheet* aSheet) {
mDocument->ApplicableStylesChanged();
}
bool PresShell::FixUpFocus() {
bool PresShell::NeedsFocusFixUp() const {
if (NS_WARN_IF(!mDocument)) {
return false;
}
@ -1529,6 +1521,13 @@ bool PresShell::FixUpFocus() {
return false;
}
return true;
}
bool PresShell::FixUpFocus() {
if (!NeedsFocusFixUp()) {
return false;
}
RefPtr fm = nsFocusManager::GetFocusManager();
nsCOMPtr<nsPIDOMWindowOuter> window = mDocument->GetWindow();
if (NS_WARN_IF(!window)) {
@ -1829,7 +1828,7 @@ nsresult PresShell::Initialize() {
FrameNeedsReflow(rootFrame, IntrinsicDirty::None, NS_FRAME_IS_DIRTY);
NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
"Should be in mDirtyRoots now");
NS_ASSERTION(mObservingLayoutFlushes, "Why no reflow scheduled?");
NS_ASSERTION(mObservingStyleFlushes, "Why no reflow scheduled?");
}
// Restore our root scroll position now if we're getting here after EndLoad
@ -2552,10 +2551,6 @@ void PresShell::EndLoad(Document* aDocument) {
mDocumentLoading = false;
}
bool PresShell::IsLayoutFlushObserver() {
return GetPresContext()->RefreshDriver()->IsLayoutFlushObserver(this);
}
void PresShell::LoadComplete() {
gfxTextPerfMetrics* tp = nullptr;
if (mPresContext) {
@ -2833,7 +2828,7 @@ void PresShell::FrameNeedsReflow(nsIFrame* aFrame,
}
} while (subtrees.Length() != 0);
MaybeScheduleReflow();
EnsureLayoutFlush();
}
void PresShell::FrameNeedsToContinueReflow(nsIFrame* aFrame) {
@ -2901,12 +2896,6 @@ nsIScrollableFrame* PresShell::GetScrollableFrameToScroll(
void PresShell::CancelAllPendingReflows() {
mDirtyRoots.Clear();
if (mObservingLayoutFlushes) {
GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this);
mObservingLayoutFlushes = false;
}
ASSERT_REFLOW_SCHEDULED_STATE();
}
@ -4311,12 +4300,6 @@ void PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush) {
NS_ASSERTION(flushType >= FlushType::Style, "Why did we get called?");
mNeedStyleFlush = false;
mNeedThrottledAnimationFlush =
mNeedThrottledAnimationFlush && !aFlush.mFlushAnimations;
mNeedLayoutFlush =
mNeedLayoutFlush && (flushType < FlushType::InterruptibleLayout);
bool isSafeToFlush = IsSafeToFlush();
// If layout could possibly trigger scripts, then it's only safe to flush if
@ -4343,14 +4326,6 @@ void PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush) {
bool didStyleFlush = false;
bool didLayoutFlush = false;
if (isSafeToFlush) {
// Record that we are in a flush, so that our optimization in
// Document::FlushPendingNotifications doesn't skip any re-entrant
// calls to us. Otherwise, we might miss some needed flushes, since
// we clear mNeedStyleFlush / mNeedLayoutFlush here at the top of
// the function but we might not have done the work yet.
AutoRestore<bool> guard(mInFlush);
mInFlush = true;
// We need to make sure external resource documents are flushed too (for
// example, svg filters that reference a filter in an external document
// need the frames in the external document to be constructed for the
@ -4396,14 +4371,13 @@ void PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush) {
}
}
// The FlushResampleRequests() above flushed style changes.
if (MOZ_LIKELY(!mIsDestroying) && aFlush.mFlushAnimations &&
mPresContext->EffectCompositor()) {
// The FlushResampleRequests() above might have flushed style changes.
if (MOZ_LIKELY(!mIsDestroying)) {
if (aFlush.mFlushAnimations) {
mPresContext->EffectCompositor()->PostRestyleForThrottledAnimations();
mNeedThrottledAnimationFlush = false;
}
// The FlushResampleRequests() above flushed style changes.
if (MOZ_LIKELY(!mIsDestroying)) {
nsAutoScriptBlocker scriptBlocker;
Maybe<uint64_t> innerWindowID;
if (auto* window = mDocument->GetInnerWindow()) {
@ -4422,10 +4396,6 @@ void PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush) {
didStyleFlush = true;
// There might be more pending constructors now, but we're not going to
// worry about them. They can't be triggered during reflow, so we should
// be good.
if (flushType >= (SuppressInterruptibleReflows()
? FlushType::Layout
: FlushType::InterruptibleLayout) &&
@ -4440,6 +4410,11 @@ void PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush) {
}
}
}
// FIXME(emilio): Maybe we should assert here but it's not 100% sure it'd
// hold right now, UnsuppressAndInvalidate and so on can run script...
if (MOZ_LIKELY(mDirtyRoots.IsEmpty())) {
mNeedLayoutFlush = false;
}
}
FlushPendingScrollResnap();
@ -4462,21 +4437,6 @@ void PresShell::DoFlushPendingNotifications(mozilla::ChangesToFlush aFlush) {
}
}
if (!didStyleFlush && flushType >= FlushType::Style && !mIsDestroying) {
SetNeedStyleFlush();
if (aFlush.mFlushAnimations) {
SetNeedThrottledAnimationFlush();
}
}
if (!didLayoutFlush && flushType >= FlushType::InterruptibleLayout &&
!mIsDestroying) {
// We suppressed this flush either due to it not being safe to flush,
// or due to SuppressInterruptibleReflows(). Either way, the
// mNeedLayoutFlush flag needs to be re-set.
SetNeedLayoutFlush();
}
// Update flush counters
if (didStyleFlush) {
mLayoutTelemetry.IncReqsPerFlush(FlushType::Style);
@ -9698,25 +9658,6 @@ void PresShell::Thaw(bool aIncludeSubDocuments) {
// Start of protected and private methods on the PresShell
//--------------------------------------------------------
void PresShell::MaybeScheduleReflow() {
ASSERT_REFLOW_SCHEDULED_STATE();
if (mObservingLayoutFlushes || mIsDestroying || mIsReflowing ||
mDirtyRoots.IsEmpty())
return;
if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) {
ScheduleReflow();
}
ASSERT_REFLOW_SCHEDULED_STATE();
}
void PresShell::ScheduleReflow() {
ASSERT_REFLOW_SCHEDULED_STATE();
DoObserveLayoutFlushes();
ASSERT_REFLOW_SCHEDULED_STATE();
}
void PresShell::WillCauseReflow() {
nsContentUtils::AddScriptBlocker();
++mChangeNestCount;
@ -9795,9 +9736,7 @@ void PresShell::DidDoReflow(bool aInterruptible) {
// after DidDoReflow(), since that method can change whether there are
// dirty roots around by flushing, and there's no point in posting a
// reflow event just to have the flush revoke it.
MaybeScheduleReflow();
// And record that we might need flushing
SetNeedLayoutFlush();
EnsureLayoutFlush();
}
}
@ -9815,26 +9754,23 @@ DOMHighResTimeStamp PresShell::GetPerformanceNowUnclamped() {
return now;
}
void PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell) {
bool PresShell::ScheduleReflowOffTimer() {
MOZ_ASSERT(!mObservingStyleFlushes, "Shouldn't get here");
ASSERT_REFLOW_SCHEDULED_STATE();
if (mReflowContinueTimer) {
return true;
}
nsresult rv = NS_NewTimerWithFuncCallback(
getter_AddRefs(mReflowContinueTimer),
[](nsITimer* aTimer, void* aPresShell) {
RefPtr<PresShell> self = static_cast<PresShell*>(aPresShell);
MOZ_ASSERT(aTimer == self->mReflowContinueTimer, "Unexpected timer");
self->mReflowContinueTimer = nullptr;
self->ScheduleReflow();
}
bool PresShell::ScheduleReflowOffTimer() {
MOZ_ASSERT(!mObservingLayoutFlushes, "Shouldn't get here");
ASSERT_REFLOW_SCHEDULED_STATE();
if (!mReflowContinueTimer) {
nsresult rv = NS_NewTimerWithFuncCallback(
getter_AddRefs(mReflowContinueTimer), sReflowContinueCallback, this, 30,
nsITimer::TYPE_ONE_SHOT, "sReflowContinueCallback",
self->EnsureLayoutFlush();
},
this, 30, nsITimer::TYPE_ONE_SHOT, "ReflowContinueCallback",
GetMainThreadSerialEventTarget());
return NS_SUCCEEDED(rv);
}
return true;
}
bool PresShell::DoReflow(nsIFrame* target, bool aInterruptible,
@ -10048,7 +9984,7 @@ bool PresShell::DoReflow(nsIFrame* target, bool aInterruptible,
// should be suppressed now. We don't want to do extra reflow work
// before our reflow event happens.
mWasLastReflowInterrupted = true;
MaybeScheduleReflow();
EnsureLayoutFlush();
}
// dump text perf metrics for reflows with significant text processing
@ -10293,15 +10229,6 @@ void PresShell::DoObserveStyleFlushes() {
}
}
void PresShell::DoObserveLayoutFlushes() {
MOZ_ASSERT(!ObservingLayoutFlushes());
mObservingLayoutFlushes = true;
if (MOZ_LIKELY(!mDocument->GetBFCacheEntry())) {
mPresContext->RefreshDriver()->AddLayoutFlushObserver(this);
}
}
//------------------------------------------------------
// End of protected and private methods on the PresShell
//------------------------------------------------------

View file

@ -423,11 +423,6 @@ class PresShell final : public nsStubDocumentObserver,
*/
RefPtr<MobileViewportManager> GetMobileViewportManager() const;
/**
* Return true if the presshell expects layout flush.
*/
bool IsLayoutFlushObserver();
/**
* Called when document load completes.
*/
@ -551,8 +546,7 @@ class PresShell final : public nsStubDocumentObserver,
*/
void NotifyFontFaceSetOnRefresh();
// Removes ourself from the list of layout / style / and resize refresh driver
// observers.
// Removes ourself from the list of style and resize refresh driver observers.
//
// Right now this is only used for documents in the BFCache, so if you want to
// use this for anything else you need to ensure we don't end up in those
@ -560,7 +554,7 @@ class PresShell final : public nsStubDocumentObserver,
// again.
//
// That is handled by the mDocument->GetBFCacheEntry checks in
// DoObserve*Flushes functions, though that could conceivably become a boolean
// DoObserveStyleFlushes, though that could conceivably become a boolean
// member in the shell if needed.
//
// Callers are responsible of manually calling StartObservingRefreshDriver
@ -569,8 +563,6 @@ class PresShell final : public nsStubDocumentObserver,
void StartObservingRefreshDriver();
bool ObservingStyleFlushes() const { return mObservingStyleFlushes; }
bool ObservingLayoutFlushes() const { return mObservingLayoutFlushes; }
void ObserveStyleFlushes() {
if (!ObservingStyleFlushes()) {
DoObserveStyleFlushes();
@ -1243,12 +1235,8 @@ class PresShell final : public nsStubDocumentObserver,
mIsNeverPainting = aNeverPainting;
}
/**
* True if a reflow event has been scheduled, or is going to be scheduled
* to run in the future.
*/
bool HasPendingReflow() const {
return mObservingLayoutFlushes || mReflowContinueTimer;
bool MightHavePendingFontLoads() const {
return ObservingStyleFlushes() || mReflowContinueTimer;
}
void SyncWindowProperties(bool aSync);
@ -1288,6 +1276,7 @@ class PresShell final : public nsStubDocumentObserver,
// Implements the "focus fix-up rule". Returns true if the focus moved (in
// which case we might need to update layout again).
// See https://github.com/whatwg/html/issues/8225
bool NeedsFocusFixUp() const;
MOZ_CAN_RUN_SCRIPT bool FixUpFocus();
/**
@ -1413,6 +1402,7 @@ class PresShell final : public nsStubDocumentObserver,
// Inline methods defined in PresShellInlines.h
inline void EnsureStyleFlush();
inline void EnsureLayoutFlush();
inline void SetNeedStyleFlush();
inline void SetNeedLayoutFlush();
inline void SetNeedThrottledAnimationFlush();
@ -1427,15 +1417,10 @@ class PresShell final : public nsStubDocumentObserver,
* animation flush is required.
*/
bool NeedFlush(FlushType aType) const {
// We check mInFlush to handle re-entrant calls to FlushPendingNotifications
// by reporting that we always need a flush in that case. Otherwise,
// we could end up missing needed flushes, since we clear the mNeedXXXFlush
// flags at the top of FlushPendingNotifications.
MOZ_ASSERT(aType >= FlushType::Style);
return mNeedStyleFlush ||
(mNeedLayoutFlush && aType >= FlushType::InterruptibleLayout) ||
aType >= FlushType::Display || mNeedThrottledAnimationFlush ||
mInFlush;
aType >= FlushType::Display || mNeedThrottledAnimationFlush;
}
/**
@ -1801,7 +1786,6 @@ class PresShell final : public nsStubDocumentObserver,
* Refresh observer management.
*/
void DoObserveStyleFlushes();
void DoObserveLayoutFlushes();
/**
* Does the actual work of figuring out the current state of font size
@ -1870,17 +1854,7 @@ class PresShell final : public nsStubDocumentObserver,
DOMHighResTimeStamp GetPerformanceNowUnclamped();
// The callback for the mReflowContinueTimer timer.
static void sReflowContinueCallback(nsITimer* aTimer, void* aPresShell);
bool ScheduleReflowOffTimer();
// MaybeScheduleReflow checks if posting a reflow is needed, then checks if
// the last reflow was interrupted. In the interrupted case ScheduleReflow is
// called off a timer, otherwise it is called directly.
void MaybeScheduleReflow();
// Actually schedules a reflow. This should only be called by
// MaybeScheduleReflow and the reflow timer ScheduleReflowOffTimer
// sets up.
void ScheduleReflow();
friend class ::AutoPointerEventTargetUpdater;
@ -3159,12 +3133,6 @@ class PresShell final : public nsStubDocumentObserver,
// re-use old pixels.
RenderingStateFlags mRenderingStateFlags;
// Whether we're currently under a FlushPendingNotifications.
// This is used to handle flush reentry correctly.
// NOTE: This can't be a bitfield since AutoRestore has a reference to this
// variable.
bool mInFlush;
bool mCaretEnabled : 1;
// True if a layout flush might not be a no-op
@ -3217,12 +3185,6 @@ class PresShell final : public nsStubDocumentObserver,
// True if we're observing the refresh driver for style flushes.
bool mObservingStyleFlushes : 1;
// True if we're observing the refresh driver for layout flushes, that is, if
// we have a reflow scheduled.
//
// Guaranteed to be false if mReflowContinueTimer is non-null.
bool mObservingLayoutFlushes : 1;
bool mResizeEventPending : 1;
bool mFontSizeInflationForceEnabled : 1;

View file

@ -57,6 +57,11 @@ void PresShell::EnsureStyleFlush() {
ObserveStyleFlushes();
}
void PresShell::EnsureLayoutFlush() {
SetNeedLayoutFlush();
ObserveStyleFlushes();
}
void PresShell::SetNeedThrottledAnimationFlush() {
mNeedThrottledAnimationFlush = true;
if (dom::Document* doc = mDocument->GetDisplayDocument()) {

View file

@ -2644,11 +2644,6 @@ bool nsPresContext::HavePendingInputEvent() {
}
}
bool nsPresContext::HasPendingRestyleOrReflow() {
mozilla::PresShell* presShell = PresShell();
return presShell->NeedStyleFlush() || presShell->HasPendingReflow();
}
void nsPresContext::ReflowStarted(bool aInterruptible) {
#ifdef NOISY_INTERRUPTIBLE_REFLOW
if (!aInterruptible) {

View file

@ -941,11 +941,6 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
uint64_t GetRestyleGeneration() const;
uint64_t GetUndisplayedRestyleGeneration() const;
/**
* Returns whether there are any pending restyles or reflows.
*/
bool HasPendingRestyleOrReflow();
/**
* Notify the prescontext that the presshell is about to reflow a reflow root.
* The single argument indicates whether this reflow should be interruptible.

View file

@ -1914,7 +1914,6 @@ uint32_t nsRefreshDriver::ObserverCount() const {
sum += mAnimationEventFlushObservers.Length();
sum += mResizeEventFlushObservers.Length();
sum += mStyleFlushObservers.Length();
sum += mLayoutFlushObservers.Length();
sum += mPendingFullscreenEvents.Length();
sum += mFrameRequestCallbackDocs.Length();
sum += mThrottledFrameRequestCallbackDocs.Length();
@ -1936,7 +1935,7 @@ bool nsRefreshDriver::HasObservers() const {
// used to determine whether or not to stop the timer or re-start it and timer
// adjustment observers should not influence timer starting or stopping.
return (mViewManagerFlushIsPending && !mThrottled) ||
!mStyleFlushObservers.IsEmpty() || !mLayoutFlushObservers.IsEmpty() ||
!mStyleFlushObservers.IsEmpty() ||
!mAnimationEventFlushObservers.IsEmpty() ||
!mResizeEventFlushObservers.IsEmpty() ||
!mPendingFullscreenEvents.IsEmpty() ||
@ -1968,10 +1967,6 @@ void nsRefreshDriver::AppendObserverDescriptionsToString(
aStr.AppendPrintf("%zux Style flush observer, ",
mStyleFlushObservers.Length());
}
if (!mLayoutFlushObservers.IsEmpty()) {
aStr.AppendPrintf("%zux Layout flush observer, ",
mLayoutFlushObservers.Length());
}
if (!mPendingFullscreenEvents.IsEmpty()) {
aStr.AppendPrintf("%zux Pending fullscreen event, ",
mPendingFullscreenEvents.Length());
@ -2151,12 +2146,9 @@ nsRefreshDriver::ObserverArray& nsRefreshDriver::ArrayFor(
case FlushType::Event:
return mObservers[0];
case FlushType::Style:
case FlushType::Frames:
return mObservers[1];
case FlushType::Layout:
return mObservers[2];
case FlushType::Display:
return mObservers[3];
return mObservers[2];
default:
MOZ_CRASH("We don't track refresh observers for this flush type");
}
@ -2487,7 +2479,10 @@ bool nsRefreshDriver::TickObserverArray(uint32_t aIdx, TimeStamp aNowTime) {
RunFrameRequestCallbacks(aNowTime);
MaybeIncreaseMeasuredTicksSinceLoading();
if (mPresContext && mPresContext->GetPresShell()) {
if (!mPresContext || !mPresContext->GetPresShell()) {
return false;
}
AutoTArray<PresShell*, 16> observers;
observers.AppendElements(mStyleFlushObservers);
for (uint32_t j = observers.Length();
@ -2502,45 +2497,30 @@ bool nsRefreshDriver::TickObserverArray(uint32_t aIdx, TimeStamp aNowTime) {
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 ChangesToFlush ctf(FlushType::InterruptibleLayout, false);
presShell->FlushPendingNotifications(ctf);
if (presShell->FixUpFocus()) {
const bool fixedUpFocus = presShell->FixUpFocus();
if (fixedUpFocus) {
presShell->FlushPendingNotifications(ctf);
}
// This is a bit subtle: We intentionally mark the pres shell as not
// observing style flushes here, rather than above the flush, so that
// reflows scheduled from the style flush, but processed by the (same)
// layout flush, don't end up needlessly scheduling another tick.
// Instead, we re-observe only if after a flush we still need a style /
// layout flush / focus fix-up. These should generally never happen, but
// the later can for example if you have focus shifts during the focus
// fixup event listeners etc.
presShell->mObservingStyleFlushes = false;
if (NS_WARN_IF(presShell->NeedStyleFlush()) ||
NS_WARN_IF(presShell->NeedLayoutFlush()) ||
NS_WARN_IF(fixedUpFocus && presShell->NeedsFocusFixUp())) {
presShell->ObserveStyleFlushes();
}
// Inform the FontFaceSet that we ticked, so that it can resolve its
// ready promise if it needs to.
// Inform the FontFaceSet that we ticked, so that it can resolve its ready
// promise if it needs to.
presShell->NotifyFontFaceSetOnRefresh();
mNeedToRecomputeVisibility = true;
@ -2733,13 +2713,12 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime,
// have these calls separated out, so that we can figure out which
// observer-category is involved from the backtrace of crash reports.
bool keepGoing = true;
MOZ_ASSERT(ArrayLength(mObservers) == 4,
MOZ_ASSERT(ArrayLength(mObservers) == 3,
"if this changes, then we need to add or remove calls to "
"TickObserverArray below");
keepGoing = keepGoing && TickObserverArray(0, aNowTime);
keepGoing = keepGoing && TickObserverArray(1, aNowTime);
keepGoing = keepGoing && TickObserverArray(2, aNowTime);
keepGoing = keepGoing && TickObserverArray(3, aNowTime);
if (!keepGoing) {
StopTimer();
return;

View file

@ -91,7 +91,7 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
* doesn't require current position data or isn't currently
* painting, and, correspondingly, which get notified when there
* is a flush during such suppression
* and it must be FlushType::Style, FlushType::Layout, or FlushType::Display.
* and it must be FlushType::Style, or FlushType::Display.
*
* The refresh driver does NOT own a reference to these observers;
* they must remove themselves before they are destroyed.
@ -179,33 +179,18 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
mDelayedResizeEventFlushObservers.RemoveElement(aPresShell);
}
/**
* Add / remove presshells that we should flush style and layout on
*/
void AddStyleFlushObserver(mozilla::PresShell* aPresShell) {
MOZ_DIAGNOSTIC_ASSERT(!mStyleFlushObservers.Contains(aPresShell),
MOZ_DIAGNOSTIC_ASSERT(!IsStyleFlushObserver(aPresShell),
"Double-adding style flush observer");
LogPresShellObserver::LogDispatch(aPresShell, this);
mStyleFlushObservers.AppendElement(aPresShell);
EnsureTimerStarted();
}
void RemoveStyleFlushObserver(mozilla::PresShell* aPresShell) {
mStyleFlushObservers.RemoveElement(aPresShell);
}
void AddLayoutFlushObserver(mozilla::PresShell* aPresShell) {
MOZ_DIAGNOSTIC_ASSERT(!IsLayoutFlushObserver(aPresShell),
"Double-adding layout flush observer");
LogPresShellObserver::LogDispatch(aPresShell, this);
mLayoutFlushObservers.AppendElement(aPresShell);
EnsureTimerStarted();
}
void RemoveLayoutFlushObserver(mozilla::PresShell* aPresShell) {
mLayoutFlushObservers.RemoveElement(aPresShell);
}
bool IsLayoutFlushObserver(mozilla::PresShell* aPresShell) {
return mLayoutFlushObservers.Contains(aPresShell);
bool IsStyleFlushObserver(mozilla::PresShell* aPresShell) {
return mStyleFlushObservers.Contains(aPresShell);
}
/**
@ -684,7 +669,7 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
mozilla::TimeStamp mBeforeFirstContentfulPaintTimerRunningLimit;
// separate arrays for each flush type we support
ObserverArray mObservers[4];
ObserverArray mObservers[3];
// These observers should NOT be included in HasObservers() since that method
// is used to determine whether or not to stop the timer, or restore it when
// thawing the refresh driver. On the other hand these observers are intended
@ -707,7 +692,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
AutoTArray<mozilla::PresShell*, 16> mResizeEventFlushObservers;
AutoTArray<mozilla::PresShell*, 16> mDelayedResizeEventFlushObservers;
AutoTArray<mozilla::PresShell*, 16> mStyleFlushObservers;
AutoTArray<mozilla::PresShell*, 16> mLayoutFlushObservers;
// nsTArray on purpose, because we want to be able to swap.
nsTArray<Document*> mFrameRequestCallbackDocs;
nsTArray<Document*> mThrottledFrameRequestCallbackDocs;

View file

@ -692,14 +692,17 @@ bool FontFaceSetDocumentImpl::MightHavePendingFontLoads() {
return true;
}
if (!mDocument) {
return false;
}
// Check for pending restyles or reflows, as they might cause fonts to
// load as new styles apply and text runs are rebuilt.
nsPresContext* presContext = GetPresContext();
if (presContext && presContext->HasPendingRestyleOrReflow()) {
PresShell* ps = mDocument->GetPresShell();
if (ps && ps->MightHavePendingFontLoads()) {
return true;
}
if (mDocument) {
// We defer resolving mReady until the document as fully loaded.
if (!mDocument->DidFireDOMContentLoaded()) {
return true;
@ -710,7 +713,6 @@ bool FontFaceSetDocumentImpl::MightHavePendingFontLoads() {
if (mDocument->CSSLoader()->HasPendingLoads()) {
return true;
}
}
return false;
}

View file

@ -152,13 +152,9 @@ function setTimeoutZero() {
}
function awaitRefresh() {
function awaitOneRefresh() {
return new Promise(function(aResolve, aReject) {
requestAnimationFrame(aResolve);
return new Promise(r => {
requestAnimationFrame(() => requestAnimationFrame(r));
});
}
return awaitOneRefresh().then(awaitOneRefresh);
}
function flushStyles() {
@ -952,8 +948,7 @@ function runTest() {
});
return p;
}).then(function() {
}).then(async function() {
// (TEST 32) Test that pending restyles prevent document.fonts.status
// from becoming loaded.
var face = new FontFace("test", "url(neverending_font_load.sjs)");
@ -963,7 +958,11 @@ function runTest() {
is(document.fonts.status, "loading", "FontFaceSet.status after adding a loading FontFace (TEST 32)");
document.fonts.clear();
is(document.fonts.status, "loading", "FontFaceSet.status after clearing, but still waiting for styles (TEST 32)");
flushStyles();
await awaitRefresh();
is(document.fonts.status, "loaded", "FontFaceSet.status after clearing (TEST 32)");
@ -977,12 +976,10 @@ function runTest() {
document.fonts.clear();
is(document.fonts.status, "loading", "FontFaceSet.status after clearing but when there is a pending restyle (TEST 32)");
return awaitRefresh() // wait for a refresh driver tick
.then(function() {
is(document.fonts.status, "loaded", "FontFaceSet.status after clearing and the restyle has been flushed (TEST 32)");
return document.fonts.ready;
});
await awaitRefresh();
is(document.fonts.status, "loaded", "FontFaceSet.status after clearing and the restyle has been flushed (TEST 32)");
await document.fonts.ready;
}).then(function() {
// (TEST 33) Test that CSS-connected FontFace objects are created

View file

@ -1,8 +1,7 @@
[inert-iframe-tabbing.html]
[Sequential navigation can move within an inert iframe]
expected:
if (os == "win") and not debug and (processor == "x86_64"): [PASS, FAIL]
if (os == "mac") and not debug: [PASS, FAIL]
expected: [PASS,FAIL]
bug: 1793738
[Sequential navigation can leave an inert iframe]
expected:

View file

@ -1,8 +0,0 @@
[chrome-bug-333487749.html]
expected:
if (os == "linux") and not asan and not swgl and (version == "Ubuntu 18.04") and fission and tsan: [PASS, TIMEOUT]
if (os == "linux") and not asan and not swgl and (version == "Ubuntu 22.04") and not debug: [PASS, TIMEOUT]
if (os == "linux") and not asan and not swgl and (version == "Ubuntu 18.04") and not fission: [PASS, TIMEOUT]
if (os == "win") and debug and (processor == "x86_64") and not swgl: [PASS, TIMEOUT]
if (os == "linux") and not asan and swgl: [PASS, TIMEOUT]
if (os == "linux") and asan: [PASS, TIMEOUT]