--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -784,25 +784,26 @@ nsContentSink::ProcessStyleLinkFromHeade
mozilla::net::ReferrerPolicy referrerPolicy =
mozilla::net::AttributeReferrerPolicyFromString(aReferrerPolicy);
if (referrerPolicy == net::RP_Unset) {
referrerPolicy = mDocument->GetReferrerPolicy();
}
// If this is a fragment parser, we don't want to observe.
// We don't support CORS for processing instructions
- css::Loader::IsAlternate isAlternate;
- rv = mCSSLoader->LoadStyleLink(nullptr, url, nullptr, aTitle, aMedia, aAlternate,
- CORS_NONE, referrerPolicy,
- /* integrity = */ EmptyString(),
- mRunsToCompletion ? nullptr : this,
- &isAlternate);
- NS_ENSURE_SUCCESS(rv, rv);
+ auto loadResultOrErr =
+ mCSSLoader->LoadStyleLink(nullptr, url, nullptr, aTitle, aMedia, aAlternate,
+ CORS_NONE, referrerPolicy,
+ /* integrity = */ EmptyString(),
+ mRunsToCompletion ? nullptr : this);
+ if (loadResultOrErr.isErr()) {
+ return loadResultOrErr.unwrapErr();
+ }
- if (isAlternate == css::Loader::IsAlternate::No && !mRunsToCompletion) {
+ if (loadResultOrErr.unwrap().ShouldBlock() && !mRunsToCompletion) {
++mPendingSheetCount;
mScriptLoader->AddParserBlockingScriptExecutionBlocker();
}
return NS_OK;
}
--- a/dom/base/nsIStyleSheetLinkingElement.h
+++ b/dom/base/nsIStyleSheetLinkingElement.h
@@ -27,37 +27,36 @@ public:
};
enum class IsAlternate
{
Yes,
No,
};
- enum class WillNotify
+ enum class Completed
{
Yes,
No,
};
struct Update
{
private:
bool mWillNotify;
bool mIsAlternate;
public:
Update()
: mWillNotify(false)
, mIsAlternate(false)
- {
- }
+ { }
- Update(WillNotify aWillNotify, IsAlternate aIsAlternate)
- : mWillNotify(aWillNotify == WillNotify::Yes)
+ Update(Completed aCompleted, IsAlternate aIsAlternate)
+ : mWillNotify(aCompleted == Completed::No)
, mIsAlternate(aIsAlternate == IsAlternate::Yes)
{ }
bool WillNotify() const
{
return mWillNotify;
}
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -419,28 +419,26 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
nsAutoString title, type, media;
bool hasAlternateRel;
GetStyleSheetInfo(title, type, media, &hasAlternateRel);
if (!type.LowerCaseEqualsLiteral("text/css")) {
return Update { };
}
- bool doneLoading = false;
-
// Load the link's referrerpolicy attribute. If the link does not provide a
// referrerpolicy attribute, ignore this and use the document's referrer
// policy
net::ReferrerPolicy referrerPolicy = GetLinkReferrerPolicy();
if (referrerPolicy == net::RP_Unset) {
referrerPolicy = doc->GetReferrerPolicy();
}
- IsAlternate isAlternate = IsAlternate::No;
+ css::Loader::LoadSheetResult result;
if (isInline) {
nsAutoString text;
if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
return Err(NS_ERROR_OUT_OF_MEMORY);
}
MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
@@ -454,42 +452,42 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
mLineNumber, text, &rv)) {
if (NS_FAILED(rv)) {
return Err(rv);
}
return Update { };
}
// Parse the style sheet.
- rv = doc->CSSLoader()->
+ return doc->CSSLoader()->
LoadInlineStyle(thisContent, text, triggeringPrincipal, mLineNumber,
title, media, referrerPolicy,
- aObserver, &doneLoading, &isAlternate);
- if (NS_FAILED(rv)) {
- return Err(rv);
- }
- } else {
- nsAutoString integrity;
- if (thisContent->IsElement()) {
- thisContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
- integrity);
- }
- if (!integrity.IsEmpty()) {
- MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
- ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
- NS_ConvertUTF16toUTF8(integrity).get()));
- }
-
- nsresult rv = doc->CSSLoader()->
- LoadStyleLink(thisContent, uri, triggeringPrincipal, title, media,
- hasAlternateRel, GetCORSMode(), referrerPolicy, integrity,
- aObserver, &isAlternate);
- if (NS_FAILED(rv)) {
- // Don't propagate LoadStyleLink() errors further than this, since some
- // consumers (e.g. nsXMLContentSink) will completely abort on innocuous
- // things like a stylesheet load being blocked by the security system.
- return Update { };
- }
+ aObserver);
+ }
+ nsAutoString integrity;
+ if (thisContent->IsElement()) {
+ thisContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::integrity,
+ integrity);
+ }
+ if (!integrity.IsEmpty()) {
+ MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
+ ("nsStyleLinkElement::DoUpdateStyleSheet, integrity=%s",
+ NS_ConvertUTF16toUTF8(integrity).get()));
}
-
- auto willNotify = doneLoading ? WillNotify::No : WillNotify::Yes;
- return Update { willNotify, isAlternate };
+ auto resultOrError =
+ doc->CSSLoader()->LoadStyleLink(thisContent,
+ uri,
+ triggeringPrincipal,
+ title,
+ media,
+ hasAlternateRel,
+ GetCORSMode(),
+ referrerPolicy,
+ integrity,
+ aObserver);
+ if (resultOrError.isErr()) {
+ // Don't propagate LoadStyleLink() errors further than this, since some
+ // consumers (e.g. nsXMLContentSink) will completely abort on innocuous
+ // things like a stylesheet load being blocked by the security system.
+ return Update { };
+ }
+ return resultOrError;
}
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1867,131 +1867,140 @@ Loader::MarkLoadTreeFailed(SheetLoadData
if (aLoadData->mParentData) {
MarkLoadTreeFailed(aLoadData->mParentData);
}
aLoadData = aLoadData->mNext;
} while (aLoadData);
}
-nsresult
+Result<Loader::LoadSheetResult, nsresult>
Loader::LoadInlineStyle(nsIContent* aElement,
const nsAString& aBuffer,
nsIPrincipal* aTriggeringPrincipal,
uint32_t aLineNumber,
const nsAString& aTitle,
const nsAString& aMedia,
ReferrerPolicy aReferrerPolicy,
- nsICSSLoaderObserver* aObserver,
- bool* aCompleted,
- IsAlternate* aIsAlternate)
+ nsICSSLoaderObserver* aObserver)
{
LOG(("css::Loader::LoadInlineStyle"));
- *aCompleted = true;
-
if (!mEnabled) {
LOG_WARN((" Not enabled"));
- return NS_ERROR_NOT_AVAILABLE;
+ return Err(NS_ERROR_NOT_AVAILABLE);
}
- NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
+ if (!mDocument) {
+ return Err(NS_ERROR_NOT_INITIALIZED);
+ }
nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
NS_ASSERTION(owningElement, "Element is not a style linking element!");
// Since we're not planning to load a URI, no need to hand a principal to the
// load data or to CreateSheet(). Also, OK to use CORS_NONE for the CORS
// mode.
StyleSheetState state;
RefPtr<StyleSheet> sheet;
+ IsAlternate isAlternate;
nsresult rv = CreateSheet(nullptr, aElement, nullptr, eAuthorSheetFeatures,
CORS_NONE, aReferrerPolicy,
EmptyString(), // no inline integrity checks
- false, false, aTitle, state, aIsAlternate,
+ false, false, aTitle, state, &isAlternate,
&sheet);
- NS_ENSURE_SUCCESS(rv, rv);
+ 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>(*aIsAlternate)));
+ LOG((" Sheet is alternate: %d", static_cast<int>(isAlternate)));
- PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate);
+ 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);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_FAILED(rv)) {
+ return Err(rv);
+ }
}
nsIPrincipal* principal = aElement->NodePrincipal();
if (aTriggeringPrincipal) {
// The triggering principal may be an expanded principal, which is safe to
// use for URL security checks, but not as the loader principal for a
// 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,
- *aIsAlternate == IsAlternate::Yes,
+ isAlternate == IsAlternate::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;
+ bool completed = true;
// Parse completion releases the load data.
//
// Note that we need to parse synchronously, since the web expects that the
// effects of inline stylesheets are visible immediately (aside from @imports).
rv = ParseSheet(aBuffer, EmptyCString(),
- data, /* aAllowAsync = */ false, *aCompleted);
- NS_ENSURE_SUCCESS(rv, rv);
+ data,
+ /* aAllowAsync = */ false,
+ completed);
+ if (NS_FAILED(rv)) {
+ return Err(rv);
+ }
- // If aCompleted is true, |data| may well be deleted by now.
- if (!*aCompleted) {
+ // If completed is true, |data| may well be deleted by now.
+ if (!completed) {
data->mMustNotify = true;
}
- return rv;
+ return LoadSheetResult { completed ? Completed::Yes : Completed::No, isAlternate };
}
-nsresult
+Result<Loader::LoadSheetResult, nsresult>
Loader::LoadStyleLink(nsIContent* aElement,
nsIURI* aURL,
nsIPrincipal* aTriggeringPrincipal,
const nsAString& aTitle,
const nsAString& aMedia,
bool aHasAlternateRel,
CORSMode aCORSMode,
ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity,
- nsICSSLoaderObserver* aObserver,
- IsAlternate* aIsAlternate)
+ nsICSSLoaderObserver* aObserver)
{
NS_PRECONDITION(aURL, "Must have URL to load");
LOG(("css::Loader::LoadStyleLink"));
LOG_URI(" Link uri: '%s'", aURL);
LOG((" Link title: '%s'", NS_ConvertUTF16toUTF8(aTitle).get()));
LOG((" Link media: '%s'", NS_ConvertUTF16toUTF8(aMedia).get()));
LOG((" Link alternate rel: %d", aHasAlternateRel));
if (!mEnabled) {
LOG_WARN((" Not enabled"));
- return NS_ERROR_NOT_AVAILABLE;
+ return Err(NS_ERROR_NOT_AVAILABLE);
}
- NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
+ if (!mDocument) {
+ return Err(NS_ERROR_NOT_INITIALIZED);
+ }
nsIPrincipal* loadingPrincipal = aElement ? aElement->NodePrincipal()
: mDocument->NodePrincipal();
nsIPrincipal* principal = aTriggeringPrincipal ? aTriggeringPrincipal
: loadingPrincipal;
nsISupports* context = aElement;
@@ -2009,75 +2018,87 @@ Loader::LoadStyleLink(nsIContent* aEleme
if (aElement && !mDocument->IsLoadedAsData()) {
// Fire an async error event on it.
RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
new LoadBlockingAsyncEventDispatcher(aElement,
NS_LITERAL_STRING("error"),
false, false);
loadBlockingAsyncDispatcher->PostDOMEvent();
}
- return rv;
+ return Err(rv);
}
StyleSheetState state;
RefPtr<StyleSheet> sheet;
+ IsAlternate isAlternate;
rv = CreateSheet(aURL, aElement, principal, eAuthorSheetFeatures,
aCORSMode, aReferrerPolicy, aIntegrity, false,
- aHasAlternateRel, aTitle, state, aIsAlternate,
+ aHasAlternateRel, aTitle, state, &isAlternate,
&sheet);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_FAILED(rv)) {
+ return Err(rv);
+ }
+
+ LOG((" Sheet is alternate: %d", static_cast<int>(isAlternate)));
- LOG((" Sheet is alternate: %d", static_cast<int>(*aIsAlternate)));
+ PrepareSheet(sheet, aTitle, aMedia, nullptr, isAlternate);
- PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate);
-
+ // FIXME(emilio, bug 1410578): Shadow DOM should be handled here too.
rv = InsertSheetInDoc(sheet, aElement, mDocument);
- NS_ENSURE_SUCCESS(rv, rv);
+ 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, *aIsAlternate,
- owningElement);
- return rv;
+ rv = PostLoadEvent(aURL, sheet, aObserver, isAlternate, owningElement);
+ if (NS_FAILED(rv)) {
+ return Err(rv);
+ }
}
- return NS_OK;
+ // The load hasn't been completed yet, will be done in PostLoadEvent.
+ return LoadSheetResult { Completed::No, isAlternate };
}
// Now we need to actually load it
nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
SheetLoadData* data = new SheetLoadData(this, aTitle, aURL, sheet,
owningElement,
- *aIsAlternate == IsAlternate::Yes,
+ isAlternate == IsAlternate::Yes,
aObserver, principal, requestingNode);
NS_ADDREF(data);
// If we have to parse and it's an alternate non-inline, defer it
- if (aURL && state == eSheetNeedsParser && mSheets->mLoadingDatas.Count() != 0 &&
- *aIsAlternate == IsAlternate::Yes) {
+ if (aURL &&
+ state == eSheetNeedsParser &&
+ mSheets->mLoadingDatas.Count() != 0 &&
+ isAlternate == IsAlternate::Yes) {
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 NS_OK;
+ return LoadSheetResult { Completed::No, isAlternate };
}
// Load completion will free the data
rv = LoadSheet(data, state, false);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_FAILED(rv)) {
+ return Err(rv);
+ }
data->mMustNotify = true;
- return rv;
+ return LoadSheetResult { Completed::No, isAlternate };
}
static bool
HaveAncestorDataWithURI(SheetLoadData *aData, nsIURI *aURI)
{
if (!aData->mURI) {
// Inline style; this won't have any ancestors
MOZ_ASSERT(!aData->mParentData,
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -187,16 +187,18 @@ enum StyleSheetState {
eSheetComplete
};
class Loader final {
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
public:
typedef nsIStyleSheetLinkingElement::IsAlternate IsAlternate;
+ typedef nsIStyleSheetLinkingElement::Completed Completed;
+ typedef nsIStyleSheetLinkingElement::Update LoadSheetResult;
Loader();
// aDocGroup is used for dispatching SheetLoadData in PostLoadEvent(). It
// can be null if you want to use this constructor, and there's no
// document when the Loader is constructed.
explicit Loader(mozilla::dom::DocGroup*);
explicit Loader(nsIDocument*);
@@ -214,83 +216,77 @@ public:
{ mCompatMode = aCompatMode; }
nsCompatibility GetCompatibilityMode() { return mCompatMode; }
nsresult SetPreferredSheet(const nsAString& aTitle);
// XXXbz sort out what the deal is with events! When should they fire?
/**
* Load an inline style sheet. If a successful result is returned and
- * *aCompleted is false, then aObserver is guaranteed to be notified
+ * result.WillNotify() is true, then aObserver is guaranteed to be notified
* asynchronously once the sheet is marked complete. If an error is
- * returned, or if *aCompleted is true, aObserver will not be notified. In
- * addition to parsing the sheet, this method will insert it into the
- * stylesheet list of this CSSLoader's document.
+ * returned, or if result.WillNotify() is false, aObserver will not be
+ * notified. In addition to parsing the sheet, this method will insert it
+ * into the stylesheet list of this CSSLoader's document.
*
* @param aElement the element linking to the stylesheet. This must not be
* null and must implement nsIStyleSheetLinkingElement.
* @param aBuffer the stylesheet data
* @param aTriggeringPrincipal The principal of the scripted caller that
* initiated the load, if available. Otherwise
* null.
* @param aLineNumber the line number at which the stylesheet data started.
* @param aTitle the title of the sheet.
* @param aMedia the media string for the sheet.
* @param aReferrerPolicy the referrer policy for loading the sheet.
* @param aObserver the observer to notify when the load completes.
* May be null.
- * @param [out] aCompleted whether parsing of the sheet completed.
- * @param [out] aIsAlternate whether the stylesheet ended up being an
- * alternate sheet.
*/
- nsresult LoadInlineStyle(nsIContent* aElement,
- const nsAString& aBuffer,
- nsIPrincipal* aTriggeringPrincipal,
- uint32_t aLineNumber,
- const nsAString& aTitle,
- const nsAString& aMedia,
- ReferrerPolicy aReferrerPolicy,
- nsICSSLoaderObserver* aObserver,
- bool* aCompleted,
- IsAlternate* aIsAlternate);
+ Result<LoadSheetResult, nsresult>
+ LoadInlineStyle(nsIContent* aElement,
+ const nsAString& aBuffer,
+ nsIPrincipal* aTriggeringPrincipal,
+ uint32_t aLineNumber,
+ const nsAString& aTitle,
+ const nsAString& aMedia,
+ ReferrerPolicy aReferrerPolicy,
+ nsICSSLoaderObserver* aObserver);
/**
* Load a linked (document) stylesheet. If a successful result is returned,
* aObserver is guaranteed to be notified asynchronously once the sheet is
- * loaded and marked complete. If an error is returned, aObserver will not
- * be notified. In addition to loading the sheet, this method will insert it
- * into the stylesheet list of this CSSLoader's document.
+ * loaded and marked complete, i.e., result.WillNotify() will always return
+ * true. If an error is returned, aObserver will not be notified. In
+ * addition to loading the sheet, this method will insert it into the
+ * stylesheet list of this CSSLoader's document.
*
* @param aElement the element linking to the the stylesheet. May be null.
* @param aURL the URL of the sheet.
* @param aTriggeringPrincipal the triggering principal for the load. May be
* null, in which case the NodePrincipal() of the element (or
* document if aElement is null) should be used.
* @param aTitle the title of the sheet.
* @param aMedia the media string for the sheet.
* @param aHasAlternateRel whether the rel for this link included
* "alternate".
* @param aCORSMode the CORS mode for this load.
* @param aObserver the observer to notify when the load completes.
* May be null.
- * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
- * an alternate sheet. Note that this need not match
- * aHasAlternateRel.
*/
- nsresult LoadStyleLink(nsIContent* aElement,
- nsIURI* aURL,
- nsIPrincipal* aTriggeringPrincipal,
- const nsAString& aTitle,
- const nsAString& aMedia,
- bool aHasAlternateRel,
- CORSMode aCORSMode,
- ReferrerPolicy aReferrerPolicy,
- const nsAString& aIntegrity,
- nsICSSLoaderObserver* aObserver,
- IsAlternate* aIsAlternate);
+ Result<LoadSheetResult, nsresult>
+ LoadStyleLink(nsIContent* aElement,
+ nsIURI* aURL,
+ nsIPrincipal* aTriggeringPrincipal,
+ const nsAString& aTitle,
+ const nsAString& aMedia,
+ bool aHasAlternateRel,
+ CORSMode aCORSMode,
+ ReferrerPolicy aReferrerPolicy,
+ const nsAString& aIntegrity,
+ nsICSSLoaderObserver* aObserver);
/**
* Load a child (@import-ed) style sheet. In addition to loading the sheet,
* this method will insert it into the child sheet list of aParentSheet. If
* there is no sheet currently being parsed and the child sheet is not
* complete when this method returns, then when the child sheet becomes
* complete aParentSheet will be QIed to nsICSSLoaderObserver and
* asynchronously notified, just like for LoadStyleLink. Note that if the