Bug 1839580 - For async-parsed stylesheets, fire the load event sooner. r=smaug

This avoids one extra task hop when we finish parsing the stylesheet.

Differential Revision: https://phabricator.services.mozilla.com/D181613
This commit is contained in:
Emilio Cobos Álvarez 2023-06-21 20:36:58 +00:00
parent 9ec5da7fcc
commit f4a4f38cc0
4 changed files with 25 additions and 15 deletions

View File

@ -190,6 +190,11 @@ class LoadBlockingAsyncEventDispatcher final : public AsyncEventDispatcher {
}
}
// The static version of AsyncEventDispatcher::RunDOMEventWhenSafe should be
// preferred when possible, but for LoadBlockingAsyncEventDispatcher it makes
// sense to expose the helper so that the load event is blocked appropriately.
using AsyncEventDispatcher::RunDOMEventWhenSafe;
LoadBlockingAsyncEventDispatcher(nsINode* aEventNode, dom::Event* aEvent)
: AsyncEventDispatcher(aEventNode, aEvent),
mBlockedDoc(aEventNode->OwnerDoc()) {

View File

@ -421,17 +421,16 @@ void SheetLoadData::StartPendingLoad() {
Loader::PendingLoad::Yes);
}
void SheetLoadData::ScheduleLoadEventIfNeeded() {
already_AddRefed<LoadBlockingAsyncEventDispatcher>
SheetLoadData::PrepareLoadEventIfNeeded() {
if (!mOwningNodeBeforeLoadEvent) {
return;
return nullptr;
}
MOZ_ASSERT(BlocksLoadEvent(), "The rel=preload load event happens elsewhere");
nsCOMPtr<nsINode> node = std::move(mOwningNodeBeforeLoadEvent);
auto* dispatcher = new LoadBlockingAsyncEventDispatcher(
return do_AddRef(new LoadBlockingAsyncEventDispatcher(
node, mLoadFailed ? u"error"_ns : u"load"_ns, CanBubble::eNo,
ChromeOnlyDispatch::eNo);
dispatcher->PostDOMEvent();
ChromeOnlyDispatch::eNo));
}
nsINode* SheetLoadData::GetRequestingNode() const {
@ -1557,6 +1556,7 @@ Loader::Completed Loader::ParseSheet(const nsACString& aBytes,
void Loader::NotifyObservers(SheetLoadData& aData, nsresult aStatus) {
RecordUseCountersIfNeeded(mDocument, aData.mSheet->GetStyleUseCounters());
RefPtr loadDispatcher = aData.PrepareLoadEventIfNeeded();
if (aData.mURI) {
mLoadsPerformed.PutEntry(SheetLoadDataHashKey(aData));
aData.NotifyStop(aStatus);
@ -1565,6 +1565,10 @@ void Loader::NotifyObservers(SheetLoadData& aData, nsresult aStatus) {
// StyleSheetLoaded callback.
if (aData.BlocksLoadEvent()) {
DecrementOngoingLoadCount();
if (mPendingLoadCount && mPendingLoadCount == mOngoingLoadCount) {
LOG((" No more loading sheets; starting deferred loads"));
StartDeferredLoads();
}
}
}
if (!aData.mTitle.IsEmpty() && NS_SUCCEEDED(aStatus)) {
@ -1579,7 +1583,6 @@ void Loader::NotifyObservers(SheetLoadData& aData, nsresult aStatus) {
Unused << pageStyleActor;
}));
}
if (aData.mMustNotify) {
if (nsCOMPtr<nsICSSLoaderObserver> observer = std::move(aData.mObserver)) {
LOG((" Notifying observer %p for data %p. deferred: %d", observer.get(),
@ -1592,11 +1595,12 @@ void Loader::NotifyObservers(SheetLoadData& aData, nsresult aStatus) {
obs.get(), &aData, aData.ShouldDefer()));
obs->StyleSheetLoaded(aData.mSheet, aData.ShouldDefer(), aStatus);
}
}
if (mPendingLoadCount && mPendingLoadCount == mOngoingLoadCount) {
LOG((" No more loading sheets; starting deferred loads"));
StartDeferredLoads();
if (loadDispatcher) {
loadDispatcher->RunDOMEventWhenSafe();
}
} else if (loadDispatcher) {
loadDispatcher->PostDOMEvent();
}
}

View File

@ -164,7 +164,6 @@ void SharedStyleSheetCache::LoadCompletedInternal(
doc->PostStyleSheetApplicableStateChangeEvent(*data->mSheet);
}
}
data->ScheduleLoadEventIfNeeded();
aDatasToNotify.AppendElement(data);
NS_ASSERTION(!data->mParentData || data->mParentData->mPendingChildren != 0,

View File

@ -18,8 +18,9 @@
#include "nsProxyRelease.h"
namespace mozilla {
class LoadBlockingAsyncEventDispatcher;
class StyleSheet;
}
} // namespace mozilla
class nsICSSLoaderObserver;
class nsINode;
class nsIPrincipal;
@ -79,7 +80,7 @@ class SheetLoadData final
nsIReferrerInfo* ReferrerInfo() const { return mReferrerInfo; }
void ScheduleLoadEventIfNeeded();
already_AddRefed<LoadBlockingAsyncEventDispatcher> PrepareLoadEventIfNeeded();
NotNull<const Encoding*> DetermineNonBOMEncoding(const nsACString& aSegment,
nsIChannel*) const;
@ -159,7 +160,8 @@ class SheetLoadData final
// the original function call that started the load has returned.
// This applies only to observer notifications; load/error events
// are fired for any SheetLoadData that has a non-null
// mOwningNodeBeforeLoadEvent.
// mOwningNodeBeforeLoadEvent (though mMustNotify is used to avoid an event
// loop round-trip in that case).
bool mMustNotify : 1;
// mWasAlternate is true if the sheet was an alternate when the load data was