Bug 1799200 - Sync-load <link rel=stylesheet> on chrome documents' shadow trees. r=smaug

This reuses the same codepath that we use for video controls, so that
the browser chrome can load external styles without FOUC.

Loading external styles as compared to internal styles is preferable,
because they can be shared across documents easily.

In the future, I think the idea is that the front-end would use CSS
modules, but meanwhile this should allow them to get along without
adding hacks to their code.

Differential Revision: https://phabricator.services.mozilla.com/D164245
This commit is contained in:
Emilio Cobos Álvarez 2022-12-09 15:22:14 +00:00
parent 1ff9a98f17
commit b9125674ca
3 changed files with 34 additions and 9 deletions

View File

@ -1840,8 +1840,23 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
nsINode* requestingNode =
aInfo.mContent ? static_cast<nsINode*>(aInfo.mContent) : mDocument;
const bool syncLoad = aInfo.mContent && aInfo.mContent->IsInUAWidget() &&
IsPrivilegedURI(aInfo.mURI);
const bool syncLoad = [&] {
if (!aInfo.mContent) {
return false;
}
const bool privilegedShadowTree = aInfo.mContent->IsInUAWidget() ||
(aInfo.mContent->IsInShadowTree() &&
aInfo.mContent->IsInChromeDocument());
if (!privilegedShadowTree) {
return false;
}
if (!IsPrivilegedURI(aInfo.mURI)) {
return false;
}
// We're loading a chrome/resource URI in a chrome doc shadow tree or UA
// widget. Load synchronously to avoid FOUC.
return true;
}();
LOG((" Link sync load: '%s'", syncLoad ? "true" : "false"));
MOZ_ASSERT_IF(syncLoad, !aObserver);

View File

@ -52,6 +52,7 @@ struct SharedSubResourceCacheLoadingValueBase {
virtual bool IsLoading() const = 0;
virtual bool IsCancelled() const = 0;
virtual bool IsSyncLoad() const = 0;
virtual void StartLoading() = 0;
virtual void SetLoadCompleted() = 0;
@ -161,8 +162,9 @@ class SharedSubResourceCache {
}
struct CompleteSubResource {
uint32_t mExpirationTime = 0;
RefPtr<Value> mResource;
uint32_t mExpirationTime = 0;
bool mWasSyncLoad = false;
inline bool Expired() const;
};
@ -360,19 +362,26 @@ void SharedSubResourceCache<Traits, Derived>::StartPendingLoadsForLoader(
template <typename Traits, typename Derived>
void SharedSubResourceCache<Traits, Derived>::Insert(LoadingValue& aValue) {
auto key = KeyFromLoadingValue(aValue);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
#ifdef DEBUG
// We only expect a complete entry to be overriding when:
// * It's expired.
// * We're explicitly bypassing the cache.
// * Our entry is a sync load that was completed after aValue started loading
// async.
for (const auto& entry : mComplete) {
if (key.KeyEquals(entry.GetKey())) {
MOZ_ASSERT(
entry.GetData().Expired() || aValue.Loader().ShouldBypassCache(),
"Overriding existing complete entry?");
MOZ_ASSERT(entry.GetData().Expired() ||
aValue.Loader().ShouldBypassCache() ||
(entry.GetData().mWasSyncLoad && !aValue.IsSyncLoad()),
"Overriding existing complete entry?");
}
}
#endif
// TODO(emilio): Use counters!
mComplete.InsertOrUpdate(key, CompleteSubResource{aValue.ExpirationTime(),
aValue.ValueForCache()});
mComplete.InsertOrUpdate(
key, CompleteSubResource{aValue.ValueForCache(), aValue.ExpirationTime(),
aValue.IsSyncLoad()});
}
template <typename Traits, typename Derived>

View File

@ -260,6 +260,7 @@ class SheetLoadData final
bool BlocksLoadEvent() const { return !RootLoadData().IsLinkRelPreload(); }
bool IsSyncLoad() const override { return mSyncLoad; }
bool IsLoading() const override { return mIsLoading; }
bool IsCancelled() const override { return mIsCancelled; }