--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -140,16 +140,17 @@ NS_IMPL_ISUPPORTS(SheetLoadData, nsIRunn
nsIThreadObserver)
SheetLoadData::SheetLoadData(Loader* aLoader,
const nsAString& aTitle,
nsIURI* aURI,
StyleSheet* aSheet,
nsIStyleSheetLinkingElement* aOwningElement,
bool aIsAlternate,
+ bool aMediaMatches,
nsICSSLoaderObserver* aObserver,
nsIPrincipal* aLoaderPrincipal,
nsINode* aRequestingNode)
: mLoader(aLoader)
, mTitle(aTitle)
, mEncoding(nullptr)
, mURI(aURI)
, mLineNumber(1)
@@ -158,16 +159,17 @@ SheetLoadData::SheetLoadData(Loader* aLo
, mPendingChildren(0)
, mSyncLoad(false)
, mIsNonDocumentSheet(false)
, mIsLoading(false)
, mIsBeingParsed(false)
, mIsCancelled(false)
, mMustNotify(false)
, mWasAlternate(aIsAlternate)
+ , mMediaMatched(aMediaMatches)
, mUseSystemPrincipal(false)
, mSheetAlreadyComplete(false)
, mIsCrossOriginNoCORS(false)
, mBlockResourceTiming(false)
, mLoadFailed(false)
, mOwningElement(aOwningElement)
, mObserver(aObserver)
, mLoaderPrincipal(aLoaderPrincipal)
@@ -412,17 +414,17 @@ Loader::~Loader()
void
Loader::DropDocumentReference(void)
{
mDocument = nullptr;
// Flush out pending datas just so we don't leak by accident. These
// loads should short-circuit through the mDocument check in
// LoadSheet and just end up in SheetComplete immediately
if (mSheets) {
- StartAlternateLoads();
+ StartDeferredLoads();
}
}
nsresult
Loader::SetPreferredSheet(const nsAString& aTitle)
{
#ifdef DEBUG
if (mDocument) {
@@ -1112,22 +1114,42 @@ Loader::CreateSheet(nsIURI* aURI,
NS_ASSERTION(*aSheet, "We should have a sheet by now!");
NS_ASSERTION(aSheetState != eSheetStateUnknown, "Have to set a state!");
LOG((" State: %s", gStateStrings[aSheetState]));
return NS_OK;
}
+static Loader::MediaMatched
+MediaListMatches(const MediaList* aMediaList, const nsIDocument* aDocument)
+{
+ if (!aMediaList || !aDocument) {
+ return Loader::MediaMatched::Yes;
+ }
+
+ nsPresContext* pc = aDocument->GetPresContext();
+ if (!pc) {
+ // Conservatively assume a match.
+ return Loader::MediaMatched::Yes;
+ }
+
+ if (aMediaList->Matches(pc)) {
+ return Loader::MediaMatched::Yes;
+ }
+
+ return Loader::MediaMatched::No;
+}
+
/**
* PrepareSheet() handles setting the media and title on the sheet, as
* well as setting the enabled state based on the title and whether
* the sheet had "alternate" in its rel.
*/
-void
+Loader::MediaMatched
Loader::PrepareSheet(StyleSheet* aSheet,
const nsAString& aTitle,
const nsAString& aMediaString,
MediaList* aMediaList,
IsAlternate aIsAlternate)
{
NS_PRECONDITION(aSheet, "Must have a sheet!");
@@ -1138,16 +1160,17 @@ Loader::PrepareSheet(StyleSheet* aSheet,
"must not provide both aMediaString and aMediaList");
mediaList = MediaList::Create(aMediaString);
}
aSheet->SetMedia(mediaList);
aSheet->SetTitle(aTitle);
aSheet->SetEnabled(aIsAlternate == IsAlternate::No);
+ return MediaListMatches(mediaList, mDocument);
}
/**
* InsertSheetInDoc handles ordering of sheets in the document. Here
* we have two types of sheets -- those with linking elements and
* those without. The latter are loaded by Link: headers.
* The following constraints are observed:
* 1) Any sheet with a linking element comes after all sheets without
@@ -1400,17 +1423,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
if (existingData) {
LOG((" Glomming on to existing load"));
SheetLoadData* data = existingData;
while (data->mNext) {
data = data->mNext;
}
data->mNext = aLoadData; // transfer ownership
- if (aSheetState == eSheetPending && !aLoadData->mWasAlternate) {
+ if (aSheetState == eSheetPending && !aLoadData->ShouldDefer()) {
// Kick the load off; someone cares about it right away
#ifdef DEBUG
SheetLoadData* removedData;
NS_ASSERTION(mSheets->mPendingDatas.Get(&key, &removedData) &&
removedData == existingData,
"Bad pending table.");
#endif
@@ -1495,17 +1518,17 @@ Loader::LoadSheet(SheetLoadData* aLoadDa
#ifdef DEBUG
mSyncCallback = false;
#endif
LOG_ERROR((" Failed to create channel"));
SheetComplete(aLoadData, rv);
return rv;
}
- if (!aLoadData->mWasAlternate) {
+ if (!aLoadData->ShouldDefer()) {
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {
cos->AddClassFlags(nsIClassOfService::Leader);
}
}
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
@@ -1712,33 +1735,33 @@ Loader::SheetComplete(SheetLoadData* aLo
for (uint32_t i = 0; i < count; ++i) {
--mDatasToNotifyOn;
SheetLoadData* data = datasToNotify[i];
NS_ASSERTION(data && data->mMustNotify, "How did this data get here?");
if (data->mObserver) {
LOG((" Notifying observer %p for data %p. wasAlternate: %d",
data->mObserver.get(), data, data->mWasAlternate));
- data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
+ data->mObserver->StyleSheetLoaded(data->mSheet, data->ShouldDefer(),
aStatus);
}
nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> >::ForwardIterator iter(mObservers);
nsCOMPtr<nsICSSLoaderObserver> obs;
while (iter.HasMore()) {
obs = iter.GetNext();
LOG((" Notifying global observer %p for data %p. wasAlternate: %d",
obs.get(), data, data->mWasAlternate));
obs->StyleSheetLoaded(data->mSheet, data->mWasAlternate, aStatus);
}
}
if (mSheets->mLoadingDatas.Count() == 0 && mSheets->mPendingDatas.Count() > 0) {
- LOG((" No more loading sheets; starting alternates"));
- StartAlternateLoads();
+ LOG((" No more loading sheets; starting deferred loads"));
+ StartDeferredLoads();
}
}
void
Loader::DoSheetComplete(SheetLoadData* aLoadData, LoadDataArray& aDatasToNotify)
{
LOG(("css::Loader::DoSheetComplete"));
NS_PRECONDITION(aLoadData, "Must have a load data!");
@@ -1910,17 +1933,17 @@ Loader::LoadInlineStyle(nsIContent* aEle
if (NS_FAILED(rv)) {
return Err(rv);
}
NS_ASSERTION(state == eSheetNeedsParser,
"Inline sheets should not be cached");
LOG((" Sheet is alternate: %d", static_cast<int>(isAlternate)));
- PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
+ auto matched = PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
ShadowRoot* containingShadow = aElement->GetContainingShadow();
MOZ_ASSERT(containingShadow);
containingShadow->InsertSheet(sheet, aElement);
} else {
rv = InsertSheetInDoc(sheet, aElement, mDocument);
if (NS_FAILED(rv)) {
@@ -1935,16 +1958,17 @@ Loader::LoadInlineStyle(nsIContent* aEle
// stylesheet. So treat this as principal inheritance, and downgrade if
// necessary.
principal = BasePrincipal::Cast(aTriggeringPrincipal)->PrincipalToInherit();
}
SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
owningElement,
isAlternate == IsAlternate::Yes,
+ matched == MediaMatched::Yes,
aObserver, nullptr,
static_cast<nsINode*>(aElement));
// We never actually load this, so just set its principal directly
sheet->SetPrincipal(principal);
NS_ADDREF(data);
data->mLineNumber = aLineNumber;
@@ -1960,17 +1984,17 @@ Loader::LoadInlineStyle(nsIContent* aEle
if (NS_FAILED(rv)) {
return Err(rv);
}
// If completed is true, |data| may well be deleted by now.
if (!completed) {
data->mMustNotify = true;
}
- return LoadSheetResult { completed ? Completed::Yes : Completed::No, isAlternate };
+ return LoadSheetResult { completed ? Completed::Yes : Completed::No, isAlternate, matched };
}
Result<Loader::LoadSheetResult, nsresult>
Loader::LoadStyleLink(nsIContent* aElement,
nsIURI* aURL,
nsIPrincipal* aTriggeringPrincipal,
const nsAString& aTitle,
const nsAString& aMedia,
@@ -2033,71 +2057,82 @@ Loader::LoadStyleLink(nsIContent* aEleme
aHasAlternateRel, aTitle, state, &isAlternate,
&sheet);
if (NS_FAILED(rv)) {
return Err(rv);
}
LOG((" Sheet is alternate: %d", static_cast<int>(isAlternate)));
- PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
+ auto matched = PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
// FIXME(emilio, bug 1410578): Shadow DOM should be handled here too.
rv = InsertSheetInDoc(sheet, aElement, mDocument);
if (NS_FAILED(rv)) {
return Err(rv);
}
nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
if (state == eSheetComplete) {
LOG((" Sheet already complete: 0x%p", sheet.get()));
if (aObserver || !mObservers.IsEmpty() || owningElement) {
- rv = PostLoadEvent(aURL, sheet, aObserver, isAlternate, owningElement);
+ rv = PostLoadEvent(aURL,
+ sheet,
+ aObserver,
+ isAlternate,
+ matched,
+ owningElement);
if (NS_FAILED(rv)) {
return Err(rv);
}
}
// The load hasn't been completed yet, will be done in PostLoadEvent.
- return LoadSheetResult { Completed::No, isAlternate };
+ return LoadSheetResult { Completed::No, isAlternate, matched };
}
// Now we need to actually load it
nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
SheetLoadData* data = new SheetLoadData(this, aTitle, aURL, sheet,
owningElement,
isAlternate == IsAlternate::Yes,
+ matched == MediaMatched::Yes,
aObserver, principal, requestingNode);
NS_ADDREF(data);
- // If we have to parse and it's an alternate non-inline, defer it
+ auto result = LoadSheetResult { Completed::No, isAlternate, matched };
+
+ MOZ_ASSERT(!result.ShouldBlock() == data->ShouldDefer(),
+ "These should better match!");
+
+ // If we have to parse and it's a non-blocking non-inline sheet, defer it.
if (aURL &&
state == eSheetNeedsParser &&
mSheets->mLoadingDatas.Count() != 0 &&
- isAlternate == IsAlternate::Yes) {
+ !result.ShouldBlock()) {
LOG((" Deferring alternate sheet load"));
URIPrincipalReferrerPolicyAndCORSModeHashKey key(data->mURI,
data->mLoaderPrincipal,
data->mSheet->GetCORSMode(),
data->mSheet->GetReferrerPolicy());
mSheets->mPendingDatas.Put(&key, data);
data->mMustNotify = true;
- return LoadSheetResult { Completed::No, isAlternate };
+ return result;
}
// Load completion will free the data
rv = LoadSheet(data, state, false);
if (NS_FAILED(rv)) {
return Err(rv);
}
data->mMustNotify = true;
- return LoadSheetResult { Completed::No, isAlternate };
+ return result;
}
static bool
HaveAncestorDataWithURI(SheetLoadData *aData, nsIURI *aURI)
{
if (!aData->mURI) {
// Inline style; this won't have any ancestors
MOZ_ASSERT(!aData->mParentData,
@@ -2369,17 +2404,22 @@ Loader::InternalLoadNonDocumentSheet(nsI
false, empty, state, &isAlternate, &sheet);
NS_ENSURE_SUCCESS(rv, rv);
PrepareSheet(sheet, empty, empty, nullptr, isAlternate);
if (state == eSheetComplete) {
LOG((" Sheet already complete"));
if (aObserver || !mObservers.IsEmpty()) {
- rv = PostLoadEvent(aURL, sheet, aObserver, IsAlternate::No, nullptr);
+ rv = PostLoadEvent(aURL,
+ sheet,
+ aObserver,
+ IsAlternate::No,
+ MediaMatched::Yes,
+ nullptr);
}
if (aSheet) {
sheet.swap(*aSheet);
}
return rv;
}
SheetLoadData* data = new SheetLoadData(this,
@@ -2406,29 +2446,31 @@ Loader::InternalLoadNonDocumentSheet(nsI
return rv;
}
nsresult
Loader::PostLoadEvent(nsIURI* aURI,
StyleSheet* aSheet,
nsICSSLoaderObserver* aObserver,
IsAlternate aWasAlternate,
+ MediaMatched aMediaMatched,
nsIStyleSheetLinkingElement* aElement)
{
LOG(("css::Loader::PostLoadEvent"));
NS_PRECONDITION(aSheet, "Must have sheet");
NS_PRECONDITION(aObserver || !mObservers.IsEmpty() || aElement,
"Must have observer or element");
RefPtr<SheetLoadData> evt =
new SheetLoadData(this, EmptyString(), // title doesn't matter here
aURI,
aSheet,
aElement,
aWasAlternate == IsAlternate::Yes,
+ aMediaMatched == MediaMatched::Yes,
aObserver,
nullptr,
mDocument);
if (!mPostedEvents.AppendElement(evt)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -2568,17 +2610,17 @@ Loader::AddObserver(nsICSSLoaderObserver
void
Loader::RemoveObserver(nsICSSLoaderObserver* aObserver)
{
mObservers.RemoveElement(aObserver);
}
void
-Loader::StartAlternateLoads()
+Loader::StartDeferredLoads()
{
NS_PRECONDITION(mSheets, "Don't call me!");
LoadDataArray arr(mSheets->mPendingDatas.Count());
for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
arr.AppendElement(iter.Data());
iter.Remove();
}