Bug 1456435: Make UpdateStyleSheet less bool-happy. r?heycam draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 24 Apr 2018 12:50:35 +0200
changeset 787383 0c9734460dce8afe0fd0d7a9d8f47947215bba8e
parent 787185 6c74f3ac89c6fddda59f807eeeea605060ea4918
child 787384 14919da1104c81321f7fea9db85e5be2ba4f511e
push id107715
push userbmo:emilio@crisal.io
push dateTue, 24 Apr 2018 19:35:34 +0000
reviewersheycam
bugs1456435
milestone61.0a1
Bug 1456435: Make UpdateStyleSheet less bool-happy. r?heycam MozReview-Commit-ID: FlTD390lMhg
dom/base/nsIStyleSheetLinkingElement.h
dom/base/nsStyleLinkElement.cpp
dom/base/nsStyleLinkElement.h
dom/html/HTMLLinkElement.cpp
dom/html/HTMLStyleElement.cpp
dom/svg/SVGStyleElement.cpp
dom/xml/XMLStylesheetProcessingInstruction.cpp
dom/xml/XMLStylesheetProcessingInstruction.h
dom/xml/nsXMLContentSink.cpp
dom/xslt/xslt/txMozillaXMLOutput.cpp
dom/xul/XULDocument.cpp
layout/style/Loader.cpp
parser/html/nsHtml5DocumentBuilder.cpp
--- a/dom/base/nsIStyleSheetLinkingElement.h
+++ b/dom/base/nsIStyleSheetLinkingElement.h
@@ -4,26 +4,78 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsIStyleSheetLinkingElement_h__
 #define nsIStyleSheetLinkingElement_h__
 
 
 #include "nsISupports.h"
 #include "mozilla/StyleSheet.h"
+#include "mozilla/Result.h"
 
 class nsICSSLoaderObserver;
 class nsIURI;
 
 #define NS_ISTYLESHEETLINKINGELEMENT_IID          \
 { 0xa8b79f3b, 0x9d18, 0x4f9c, \
   { 0xb1, 0xaa, 0x8c, 0x9b, 0x1b, 0xaa, 0xac, 0xad } }
 
 class nsIStyleSheetLinkingElement : public nsISupports {
 public:
+  enum class ForceUpdate
+  {
+    Yes,
+    No,
+  };
+
+  enum class IsAlternate
+  {
+    Yes,
+    No,
+  };
+
+  enum class WillNotify
+  {
+    Yes,
+    No,
+  };
+
+  struct Update
+  {
+  private:
+    bool mWillNotify;
+    bool mIsAlternate;
+
+  public:
+    Update()
+      : mWillNotify(false)
+      , mIsAlternate(false)
+    {
+    }
+
+    Update(WillNotify aWillNotify, IsAlternate aIsAlternate)
+      : mWillNotify(aWillNotify == WillNotify::Yes)
+      , mIsAlternate(aIsAlternate == IsAlternate::Yes)
+    { }
+
+    bool WillNotify() const
+    {
+      return mWillNotify;
+    }
+
+    bool ShouldBlock() const
+    {
+      if (!mWillNotify) {
+        return false;
+      }
+
+      return !mIsAlternate;
+    }
+  };
+
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISTYLESHEETLINKINGELEMENT_IID)
 
   /**
    * Used to make the association between a style sheet and
    * the element that linked it to the document.
    *
    * @param aStyleSheet the style sheet associated with this
    *                    element.
@@ -56,20 +108,19 @@ public:
    *                          this was an inline sheet that completely finished
    *                          loading.  In the case when the load failed the
    *                          failure code will be returned.
    * @param [out] whether the sheet is an alternate sheet.  This value is only
    *              meaningful if aWillNotify is true.
    * @param aForceUpdate whether we wand to force the update, flushing the
    *                     cached version if any.
    */
-  virtual nsresult UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                                    bool *aWillNotify,
-                                    bool *aIsAlternate,
-                                    bool aForceUpdate = false) = 0;
+  virtual mozilla::Result<Update, nsresult>
+    UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
+                     ForceUpdate = ForceUpdate::No) = 0;
 
   /**
    * Tells this element whether to update the stylesheet when the
    * element's properties change.
    *
    * @param aEnableUpdates update on changes or not.
    */
   virtual void SetEnableUpdates(bool aEnableUpdates) = 0;
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -293,73 +293,65 @@ nsStyleLinkElement::CheckPreloadAttrs(co
       return true;
     } else {
       return false;
     }
   }
   return false;
 }
 
-nsresult
+Result<nsStyleLinkElement::Update, nsresult>
 nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                                     bool* aWillNotify,
-                                     bool* aIsAlternate,
-                                     bool aForceReload)
+                                     ForceUpdate aForceUpdate)
 {
-  if (aForceReload) {
+  if (aForceUpdate == ForceUpdate::Yes) {
     // We remove this stylesheet from the cache to load a new version.
     nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
       thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
     if (doc && doc->CSSLoader()->GetEnabled() &&
         mStyleSheet && !mStyleSheet->IsInline()) {
       doc->CSSLoader()->ObsoleteSheet(mStyleSheet->GetOriginalURI());
     }
   }
-  return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aWillNotify,
-                            aIsAlternate, aForceReload);
+  return DoUpdateStyleSheet(nullptr, nullptr, aObserver, aForceUpdate);
 }
 
-nsresult
-nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
-                                             ShadowRoot *aOldShadowRoot,
-                                             bool aForceUpdate)
+Result<nsStyleLinkElement::Update, nsresult>
+nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument* aOldDocument,
+                                             ShadowRoot* aOldShadowRoot,
+                                             ForceUpdate aForceUpdate)
 {
-  bool notify, alternate;
-  return DoUpdateStyleSheet(aOldDocument, aOldShadowRoot, nullptr, &notify,
-                            &alternate, aForceUpdate);
+  return DoUpdateStyleSheet(
+    aOldDocument, aOldShadowRoot, nullptr, aForceUpdate);
 }
 
-nsresult
+Result<nsStyleLinkElement::Update, nsresult>
 nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
                                        ShadowRoot* aOldShadowRoot,
                                        nsICSSLoaderObserver* aObserver,
-                                       bool* aWillNotify,
-                                       bool* aIsAlternate,
-                                       bool aForceUpdate)
+                                       ForceUpdate aForceUpdate)
 {
-  *aWillNotify = false;
-
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
   // All instances of nsStyleLinkElement should implement nsIContent.
   MOZ_ASSERT(thisContent);
 
   if (thisContent->IsInAnonymousSubtree() &&
       thisContent->IsAnonymousContentInSVGUseSubtree()) {
     // Stylesheets in <use>-cloned subtrees are disabled until we figure out
     // how they should behave.
-    return NS_OK;
+    return Update { };
   }
 
   // Check for a ShadowRoot because link elements are inert in a
   // ShadowRoot.
   ShadowRoot* containingShadow = thisContent->GetContainingShadow();
   if (thisContent->IsHTMLElement(nsGkAtoms::link) &&
       (aOldShadowRoot || containingShadow)) {
-    return NS_OK;
+    return Update { };
   }
 
   if (mStyleSheet && (aOldDocument || aOldShadowRoot)) {
     MOZ_ASSERT(!(aOldDocument && aOldShadowRoot),
                "ShadowRoot content is never in document, thus "
                "there should not be a old document and old "
                "ShadowRoot simultaneously.");
 
@@ -376,36 +368,38 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
     }
 
     nsStyleLinkElement::SetStyleSheet(nullptr);
   }
 
   // When static documents are created, stylesheets are cloned manually.
   if (mDontLoadStyle || !mUpdatesEnabled ||
       thisContent->OwnerDoc()->IsStaticDocument()) {
-    return NS_OK;
+    return Update { };
   }
 
   nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
     thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
   if (!doc || !doc->CSSLoader()->GetEnabled()) {
-    return NS_OK;
+    return Update { };
   }
 
   bool isInline;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline, getter_AddRefs(triggeringPrincipal));
 
-  if (!aForceUpdate && mStyleSheet && !isInline && uri) {
+  if (aForceUpdate == ForceUpdate::No && mStyleSheet && !isInline && uri) {
     nsIURI* oldURI = mStyleSheet->GetSheetURI();
     if (oldURI) {
       bool equal;
       nsresult rv = oldURI->Equals(uri, &equal);
       if (NS_SUCCEEDED(rv) && equal) {
-        return NS_OK; // We already loaded this stylesheet
+        // If href is empty and this is not inline style then just bail.
+        // IsAlternate doesn't really matter.
+        return Update { };
       }
     }
   }
 
   if (mStyleSheet) {
     if (thisContent->IsInShadowTree()) {
       ShadowRoot* containingShadow = thisContent->GetContainingShadow();
       containingShadow->RemoveSheet(mStyleSheet);
@@ -414,86 +408,89 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
       doc->RemoveStyleSheet(mStyleSheet);
       doc->EndUpdate(UPDATE_STYLE);
     }
 
     nsStyleLinkElement::SetStyleSheet(nullptr);
   }
 
   if (!uri && !isInline) {
-    return NS_OK; // If href is empty and this is not inline style then just bail
+    // If href is empty and this is not inline style then just bail
+    return Update { };
   }
 
   nsAutoString title, type, media;
-  bool isAlternate;
-
-  GetStyleSheetInfo(title, type, media, &isAlternate);
-
+  bool hasAlternateRel;
+  GetStyleSheetInfo(title, type, media, &hasAlternateRel);
   if (!type.LowerCaseEqualsLiteral("text/css")) {
-    return NS_OK;
+    return Update { };
   }
 
   bool doneLoading = false;
-  nsresult rv = NS_OK;
 
   // 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();
   }
 
+  bool isAlternate;
   if (isInline) {
     nsAutoString text;
     if (!nsContentUtils::GetNodeTextContent(thisContent, false, text, fallible)) {
-      return NS_ERROR_OUT_OF_MEMORY;
+      return Err(NS_ERROR_OUT_OF_MEMORY);
     }
 
+
     MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
                "<link> is not 'inline', and needs different CSP checks");
     MOZ_ASSERT(thisContent->IsElement());
+    nsresult rv = NS_OK;
     if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent->AsElement(),
                                            thisContent->NodePrincipal(),
                                            triggeringPrincipal,
                                            doc->GetDocumentURI(),
-                                           mLineNumber, text, &rv))
-      return rv;
+                                           mLineNumber, text, &rv)) {
+      if (NS_FAILED(rv)) {
+        return Err(rv);
+      }
+      return Update { };
+    }
 
     // Parse the style sheet.
     rv = 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()));
     }
 
-    rv = doc->CSSLoader()->
+    nsresult rv = doc->CSSLoader()->
       LoadStyleLink(thisContent, uri, triggeringPrincipal, title, media,
-                    isAlternate, GetCORSMode(), referrerPolicy, integrity,
+                    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.
-      doneLoading = true;
-      isAlternate = false;
-      rv = NS_OK;
+      return Update { };
     }
   }
 
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aWillNotify = !doneLoading;
-  *aIsAlternate = isAlternate;
-
-  return NS_OK;
+  auto willNotify = doneLoading ? WillNotify::No : WillNotify::Yes;
+  auto alternate = isAlternate ? IsAlternate::Yes : IsAlternate::No;
+  return Update { willNotify, alternate };
 }
--- a/dom/base/nsStyleLinkElement.h
+++ b/dom/base/nsStyleLinkElement.h
@@ -11,16 +11,17 @@
  */
 
 #ifndef nsStyleLinkElement_h___
 #define nsStyleLinkElement_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/StyleSheetInlines.h"
+#include "mozilla/Unused.h"
 #include "mozilla/net/ReferrerPolicy.h"
 #include "nsCOMPtr.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsTArray.h"
 #include "nsAttrValue.h"
 
 class nsIDocument;
 class nsIURI;
@@ -41,26 +42,26 @@ public:
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override = 0;
 
   mozilla::StyleSheet* GetSheet() const { return mStyleSheet; }
 
   // nsIStyleSheetLinkingElement
   void SetStyleSheet(mozilla::StyleSheet* aStyleSheet) override;
   mozilla::StyleSheet* GetStyleSheet() override;
   void InitStyleLinkElement(bool aDontLoadStyle) override;
-  nsresult UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
-                            bool* aWillNotify,
-                            bool* aIsAlternate,
-                            bool aForceReload) override;
+
+  mozilla::Result<Update, nsresult>
+    UpdateStyleSheet(nsICSSLoaderObserver*, ForceUpdate) override;
+
   void SetEnableUpdates(bool aEnableUpdates) override;
   void GetCharset(nsAString& aCharset) override;
 
-  virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
-  virtual void SetLineNumber(uint32_t aLineNumber) override;
-  virtual uint32_t GetLineNumber() override;
+  void OverrideBaseURI(nsIURI* aNewBaseURI) override;
+  void SetLineNumber(uint32_t aLineNumber) override;
+  uint32_t GetLineNumber() override;
 
   enum RelValue {
     ePREFETCH =     0x00000001,
     eDNS_PREFETCH = 0x00000002,
     eSTYLESHEET =   0x00000004,
     eNEXT =         0x00000008,
     eALTERNATE =    0x00000010,
     ePRECONNECT =   0x00000020,
@@ -71,30 +72,31 @@ public:
   // The return value is a bitwise or of 0 or more RelValues.
   static uint32_t ParseLinkTypes(const nsAString& aTypes);
 
   static bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
                                 const nsAString& aMedia, nsIDocument* aDocument);
 
   void UpdateStyleSheetInternal()
   {
-    UpdateStyleSheetInternal(nullptr, nullptr);
+    mozilla::Unused << UpdateStyleSheetInternal(nullptr, nullptr);
   }
 protected:
   /**
    * @param aOldDocument should be non-null only if we're updating because we
    *                     removed the node from the document.
    * @param aForceUpdate true will force the update even if the URI has not
    *                     changed.  This should be used in cases when something
    *                     about the content that affects the resulting sheet
    *                     changed but the URI may not have changed.
    */
-  nsresult UpdateStyleSheetInternal(nsIDocument *aOldDocument,
-                                    mozilla::dom::ShadowRoot *aOldShadowRoot,
-                                    bool aForceUpdate = false);
+  mozilla::Result<Update, nsresult> UpdateStyleSheetInternal(
+      nsIDocument* aOldDocument,
+      mozilla::dom::ShadowRoot* aOldShadowRoot,
+      ForceUpdate = ForceUpdate::No);
 
   virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) = 0;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsAlternate) = 0;
 
   virtual mozilla::CORSMode GetCORSMode() const
@@ -120,22 +122,21 @@ private:
    *                     Passed as a parameter because on an update, the node
    *                     is removed from the tree before the sheet is removed
    *                     from the ShadowRoot.
    * @param aForceUpdate true will force the update even if the URI has not
    *                     changed.  This should be used in cases when something
    *                     about the content that affects the resulting sheet
    *                     changed but the URI may not have changed.
    */
-  nsresult DoUpdateStyleSheet(nsIDocument* aOldDocument,
-                              mozilla::dom::ShadowRoot* aOldShadowRoot,
-                              nsICSSLoaderObserver* aObserver,
-                              bool* aWillNotify,
-                              bool* aIsAlternate,
-                              bool aForceUpdate);
+  mozilla::Result<Update, nsresult>
+    DoUpdateStyleSheet(nsIDocument* aOldDocument,
+                       mozilla::dom::ShadowRoot* aOldShadowRoot,
+                       nsICSSLoaderObserver* aObserver,
+                       ForceUpdate);
 
   RefPtr<mozilla::StyleSheet> mStyleSheet;
 protected:
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mDontLoadStyle;
   bool mUpdatesEnabled;
   uint32_t mLineNumber;
 };
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -179,17 +179,17 @@ HTMLLinkElement::UnbindFromTree(bool aDe
   // Check for a ShadowRoot because link elements are inert in a
   // ShadowRoot.
   ShadowRoot* oldShadowRoot = GetBindingParent() ?
     GetBindingParent()->GetShadowRoot() : nullptr;
 
   CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 
-  UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
+  Unused << UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
 }
 
 bool
 HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
                                 nsAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 nsAttrValue& aResult)
@@ -315,32 +315,34 @@ HTMLLinkElement::AfterSetAttr(int32_t aN
       }
 
       if ((aName == nsGkAtoms::as || aName == nsGkAtoms::type ||
            aName == nsGkAtoms::crossorigin || aName == nsGkAtoms::media) &&
           IsInComposedDoc()) {
         UpdatePreload(aName, aValue, aOldValue);
       }
 
-      UpdateStyleSheetInternal(nullptr, nullptr,
-                               dropSheet ||
-                               (aName == nsGkAtoms::title ||
-                                aName == nsGkAtoms::media ||
-                                aName == nsGkAtoms::type));
+      const bool forceUpdate = dropSheet ||
+        aName == nsGkAtoms::title ||
+        aName == nsGkAtoms::media ||
+        aName == nsGkAtoms::type;
+
+      Unused << UpdateStyleSheetInternal(
+          nullptr, nullptr, forceUpdate ? ForceUpdate::Yes : ForceUpdate::No);
     }
   } else {
     // Since removing href or rel makes us no longer link to a
     // stylesheet, force updates for those too.
     if (aNameSpaceID == kNameSpaceID_None) {
       if (aName == nsGkAtoms::href ||
           aName == nsGkAtoms::rel ||
           aName == nsGkAtoms::title ||
           aName == nsGkAtoms::media ||
           aName == nsGkAtoms::type) {
-        UpdateStyleSheetInternal(nullptr, nullptr, true);
+        Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
       }
       if ((aName == nsGkAtoms::as || aName == nsGkAtoms::type ||
            aName == nsGkAtoms::crossorigin || aName == nsGkAtoms::media) &&
           IsInComposedDoc()) {
         UpdatePreload(aName, aValue, aOldValue);
       }
     }
   }
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -89,17 +89,17 @@ HTMLStyleElement::ContentRemoved(nsICont
   ContentChanged(aChild);
 }
 
 void
 HTMLStyleElement::ContentChanged(nsIContent* aContent)
 {
   mTriggeringPrincipal = nullptr;
   if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
-    UpdateStyleSheetInternal(nullptr, nullptr);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr);
   }
 }
 
 nsresult
 HTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                              nsIContent* aBindingParent,
                              bool aCompileEventHandlers)
 {
@@ -125,31 +125,31 @@ HTMLStyleElement::UnbindFromTree(bool aD
 
   if (oldShadow && GetContainingShadow()) {
     // The style is in a shadow tree and is still in the
     // shadow tree. Thus the sheets in the shadow DOM
     // do not need to be updated.
     return;
   }
 
-  UpdateStyleSheetInternal(oldDoc, oldShadow);
+  Unused << UpdateStyleSheetInternal(oldDoc, oldShadow);
 }
 
 nsresult
 HTMLStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                                const nsAttrValue* aValue,
                                const nsAttrValue* aOldValue,
                                nsIPrincipal* aSubjectPrincipal,
                                bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::title ||
         aName == nsGkAtoms::media ||
         aName == nsGkAtoms::type) {
-      UpdateStyleSheetInternal(nullptr, nullptr, true);
+      Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
     }
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                             aOldValue, aSubjectPrincipal, aNotify);
 }
 
 void
@@ -186,17 +186,17 @@ HTMLStyleElement::SetTextContentInternal
   SetEnableUpdates(false);
 
   aError = nsContentUtils::SetNodeTextContent(this, aTextContent, true);
 
   SetEnableUpdates(true);
 
   mTriggeringPrincipal = aScriptedPrincipal;
 
-  UpdateStyleSheetInternal(nullptr, nullptr);
+  Unused << UpdateStyleSheetInternal(nullptr, nullptr);
 }
 
 already_AddRefed<nsIURI>
 HTMLStyleElement::GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal)
 {
   *aIsInline = true;
   *aTriggeringPrincipal = do_AddRef(mTriggeringPrincipal).take();
   return nullptr;
--- a/dom/svg/SVGStyleElement.cpp
+++ b/dom/svg/SVGStyleElement.cpp
@@ -81,31 +81,31 @@ SVGStyleElement::BindToTree(nsIDocument*
 }
 
 void
 SVGStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
   ShadowRoot* oldShadow = GetContainingShadow();
   SVGStyleElementBase::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheetInternal(oldDoc, oldShadow);
+  Unused << UpdateStyleSheetInternal(oldDoc, oldShadow);
 }
 
 nsresult
 SVGStyleElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
                               const nsAttrValue* aValue,
                               const nsAttrValue* aOldValue,
                               nsIPrincipal* aMaybeScriptedPrincipal,
                               bool aNotify)
 {
   if (aNameSpaceID == kNameSpaceID_None) {
     if (aName == nsGkAtoms::title ||
         aName == nsGkAtoms::media ||
         aName == nsGkAtoms::type) {
-      UpdateStyleSheetInternal(nullptr, nullptr, true);
+      Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
     }
   }
 
   return SVGStyleElementBase::AfterSetAttr(aNameSpaceID, aName, aValue,
                                            aOldValue, aMaybeScriptedPrincipal,
                                            aNotify);
 }
 
@@ -154,17 +154,17 @@ SVGStyleElement::ContentRemoved(nsIConte
 {
   ContentChanged(aChild);
 }
 
 void
 SVGStyleElement::ContentChanged(nsIContent* aContent)
 {
   if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
-    UpdateStyleSheetInternal(nullptr, nullptr);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr);
   }
 }
 
 //----------------------------------------------------------------------
 
 void
 SVGStyleElement::GetXmlspace(nsAString & aXmlspace)
 {
--- a/dom/xml/XMLStylesheetProcessingInstruction.cpp
+++ b/dom/xml/XMLStylesheetProcessingInstruction.cpp
@@ -64,28 +64,28 @@ XMLStylesheetProcessingInstruction::Bind
 }
 
 void
 XMLStylesheetProcessingInstruction::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
 
   ProcessingInstruction::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheetInternal(oldDoc, nullptr);
+  Unused << UpdateStyleSheetInternal(oldDoc, nullptr);
 }
 
 // nsIDOMNode
 
 void
 XMLStylesheetProcessingInstruction::SetNodeValueInternal(const nsAString& aNodeValue,
                                                          ErrorResult& aError)
 {
   CharacterData::SetNodeValueInternal(aNodeValue, aError);
   if (!aError.Failed()) {
-    UpdateStyleSheetInternal(nullptr, nullptr, true);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
   }
 }
 
 // nsStyleLinkElement
 
 void
 XMLStylesheetProcessingInstruction::GetCharset(nsAString& aCharset)
 {
--- a/dom/xml/XMLStylesheetProcessingInstruction.h
+++ b/dom/xml/XMLStylesheetProcessingInstruction.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_XMLStylesheetProcessingInstruction_h
 #define mozilla_dom_XMLStylesheetProcessingInstruction_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/Unused.h"
 #include "mozilla/dom/ProcessingInstruction.h"
 #include "nsIURI.h"
 #include "nsStyleLinkElement.h"
 
 namespace mozilla {
 namespace dom {
 
 class XMLStylesheetProcessingInstruction final
@@ -63,17 +64,17 @@ public:
   void GetCharset(nsAString& aCharset) override;
 
   virtual void SetData(const nsAString& aData, mozilla::ErrorResult& rv) override
   {
     CharacterData::SetData(aData, rv);
     if (rv.Failed()) {
       return;
     }
-    UpdateStyleSheetInternal(nullptr, nullptr, true);
+    Unused << UpdateStyleSheetInternal(nullptr, nullptr, ForceUpdate::Yes);
   }
 
 protected:
   virtual ~XMLStylesheetProcessingInstruction();
 
   nsCOMPtr<nsIURI> mOverriddenBaseURI;
 
   already_AddRefed<nsIURI>
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -598,22 +598,21 @@ nsXMLContentSink::CloseElement(nsIConten
     rv = ProcessMETATag(aContent);
   }
   else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
     if (ssle) {
       ssle->SetEnableUpdates(true);
-      bool willNotify;
-      bool isAlternate;
-      rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
-                                  &willNotify,
-                                  &isAlternate);
-      if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
+      auto updateOrError =
+        ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
+      if (updateOrError.isOk() &&
+          updateOrError.unwrap().ShouldBlock() &&
+          !mRunsToCompletion) {
         ++mPendingSheetCount;
         mScriptLoader->AddParserBlockingScriptExecutionBlocker();
       }
     }
   }
 
   return rv;
 }
@@ -1263,30 +1262,29 @@ nsXMLContentSink::HandleProcessingInstru
   nsresult rv = AddContentAsLeaf(node);
   NS_ENSURE_SUCCESS(rv, rv);
   DidAddContent();
 
   if (ssle) {
     // This is an xml-stylesheet processing instruction... but it might not be
     // a CSS one if the type is set to something else.
     ssle->SetEnableUpdates(true);
-    bool willNotify;
-    bool isAlternate;
-    rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
-                                &willNotify,
-                                &isAlternate);
-    NS_ENSURE_SUCCESS(rv, rv);
+    auto updateOrError =
+      ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
+    if (updateOrError.isErr()) {
+      return updateOrError.unwrapErr();
+    }
 
-    if (willNotify) {
+    auto update = updateOrError.unwrap();
+    if (update.WillNotify()) {
       // Successfully started a stylesheet load
-      if (!isAlternate && !mRunsToCompletion) {
+      if (update.ShouldBlock() && !mRunsToCompletion) {
         ++mPendingSheetCount;
         mScriptLoader->AddParserBlockingScriptExecutionBlocker();
       }
-
       return NS_OK;
     }
   }
 
   // Check whether this is a CSS stylesheet PI.  Make sure the type
   // handling here matches
   // XMLStylesheetProcessingInstruction::GetStyleSheetInfo.
   nsAutoString type;
--- a/dom/xslt/xslt/txMozillaXMLOutput.cpp
+++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp
@@ -317,21 +317,20 @@ txMozillaXMLOutput::endElement()
     }
 
     if (mCreatingNewDocument) {
         // Handle all sorts of stylesheets
         nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
             do_QueryInterface(mCurrentNode);
         if (ssle) {
             ssle->SetEnableUpdates(true);
-            bool willNotify;
-            bool isAlternate;
-            nsresult rv = ssle->UpdateStyleSheet(mNotifier, &willNotify,
-                                                 &isAlternate);
-            if (mNotifier && NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+            auto updateOrError = ssle->UpdateStyleSheet(mNotifier);
+            if (mNotifier &&
+                updateOrError.isOk() &&
+                updateOrError.unwrap().ShouldBlock()) {
                 mNotifier->AddPendingStylesheet();
             }
         }
     }
 
     // Add the element to the tree if it wasn't added before and take one step
     // up the tree
     uint32_t last = mCurrentNodeStack.Count() - 1;
@@ -395,20 +394,20 @@ txMozillaXMLOutput::processingInstructio
         }
     }
 
     rv = mCurrentNode->AppendChildTo(pi, true);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (ssle) {
         ssle->SetEnableUpdates(true);
-        bool willNotify;
-        bool isAlternate;
-        rv = ssle->UpdateStyleSheet(mNotifier, &willNotify, &isAlternate);
-        if (mNotifier && NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+        auto updateOrError = ssle->UpdateStyleSheet(mNotifier);
+        if (mNotifier &&
+            updateOrError.isOk() &&
+            updateOrError.unwrap().ShouldBlock()) {
             mNotifier->AddPendingStylesheet();
         }
     }
 
     return NS_OK;
 }
 
 nsresult
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -2099,28 +2099,30 @@ XULDocument::InsertXMLStylesheetPI(const
                                       ? aBeforeThis->AsContent() : nullptr,
                                     false);
     if (NS_FAILED(rv)) return rv;
 
     ssle->SetEnableUpdates(true);
 
     // load the stylesheet if necessary, passing ourselves as
     // nsICSSObserver
-    bool willNotify;
-    bool isAlternate;
-    rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
-    if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
-        ++mPendingSheets;
+    auto result = ssle->UpdateStyleSheet(this);
+    if (result.isErr()) {
+        // Ignore errors from UpdateStyleSheet; we don't want failure to
+        // do that to break the XUL document load.  But do propagate out
+        // NS_ERROR_OUT_OF_MEMORY.
+        if (result.unwrapErr() == NS_ERROR_OUT_OF_MEMORY) {
+            return result.unwrapErr();
+        }
+        return NS_OK;
     }
 
-    // Ignore errors from UpdateStyleSheet; we don't want failure to
-    // do that to break the XUL document load.  But do propagate out
-    // NS_ERROR_OUT_OF_MEMORY.
-    if (rv == NS_ERROR_OUT_OF_MEMORY) {
-        return rv;
+    auto update = result.unwrap();
+    if (update.ShouldBlock()) {
+        ++mPendingSheets;
     }
 
     return NS_OK;
 }
 
 nsresult
 XULDocument::InsertXULOverlayPI(const nsXULPrototypePI* aProtoPI,
                                 nsINode* aParent,
@@ -2487,20 +2489,17 @@ XULDocument::ResumeWalk()
                             element->NodeInfo()->Equals(nsGkAtoms::style,
                                                         kNameSpaceID_SVG)) {
                             // XXX sucks that we have to do this -
                             // see bug 370111
                             nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
                                 do_QueryInterface(element);
                             NS_ASSERTION(ssle, "<html:style> doesn't implement "
                                                "nsIStyleSheetLinkingElement?");
-                            bool willNotify;
-                            bool isAlternate;
-                            ssle->UpdateStyleSheet(nullptr, &willNotify,
-                                                   &isAlternate);
+                            Unused << ssle->UpdateStyleSheet(nullptr);
                         }
                     }
                 }
                 // Now pop the context stack back up to the parent
                 // element and continue the prototype walk.
                 mContextStack.Pop();
                 continue;
             }
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -836,16 +836,19 @@ SheetLoadData::VerifySheetReadyToParse(n
 bool
 Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel)
 {
   // A sheet is alternate if it has a nonempty title that doesn't match the
   // currently selected style set.  But if there _is_ no currently selected
   // style set, the sheet wasn't marked as an alternate explicitly, and aTitle
   // is nonempty, we should select the style set corresponding to aTitle, since
   // that's a preferred sheet.
+  //
+  // FIXME(emilio): This should return false for Shadow DOM regardless of the
+  // document.
   if (aTitle.IsEmpty()) {
     return false;
   }
 
   if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) {
     // There's no preferred set yet, and we now have a sheet with a title.
     // Make that be the preferred set.
     mDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, aTitle);
--- a/parser/html/nsHtml5DocumentBuilder.cpp
+++ b/parser/html/nsHtml5DocumentBuilder.cpp
@@ -74,21 +74,22 @@ nsHtml5DocumentBuilder::UpdateStyleSheet
 
   if (MOZ_UNLIKELY(!mParser)) {
     // EndDocUpdate ran stuff that called nsIParser::Terminate()
     return;
   }
 
   ssle->SetEnableUpdates(true);
 
-  bool willNotify;
-  bool isAlternate;
-  nsresult rv = ssle->UpdateStyleSheet(
-    mRunsToCompletion ? nullptr : this, &willNotify, &isAlternate);
-  if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
+  auto updateOrError =
+    ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this);
+
+  if (updateOrError.isOk() &&
+      updateOrError.unwrap().ShouldBlock() &&
+      !mRunsToCompletion) {
     ++mPendingSheetCount;
     mScriptLoader->AddParserBlockingScriptExecutionBlocker();
   }
 
   // Re-open update
   BeginDocUpdate();
 }