Bug 1456435: Make UpdateStyleSheet less bool-happy. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Tue, 24 Apr 2018 12:50:35 +0200
changeset 471877 52a7abd4ee49faefa002c8ee5f9bf54e68957c63
parent 471876 fd2fe5744270e6770fe71f0a01c7643c5ce2cc00
child 471878 144000c6901bc15ff984525c7f50996f870c9133
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1456435
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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.
@@ -45,31 +97,22 @@ public:
    */
   virtual void InitStyleLinkElement(bool aDontLoadStyle) = 0;
 
   /**
    * Tells this element to update the stylesheet.
    *
    * @param aObserver    observer to notify once the stylesheet is loaded.
    *                     This will be passed to the CSSLoader
-   * @param [out] aWillNotify whether aObserver will be notified when the sheet
-   *                          loads.  If this is false, then either we didn't
-   *                          start the sheet load at all, the load failed, or
-   *                          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
@@ -171,73 +171,65 @@ uint32_t nsStyleLinkElement::ParseLinkTy
   }
   if (inString) {
     nsContentUtils::ASCIIToLower(Substring(start, current), subString);
     linkMask |= ToLinkMask(subString);
   }
   return linkMask;
 }
 
-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.");
 
@@ -254,36 +246,35 @@ 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) {
-    nsIURI* oldURI = mStyleSheet->GetSheetURI();
-    if (oldURI) {
+  if (aForceUpdate == ForceUpdate::No && mStyleSheet && !isInline && uri) {
+    if (nsIURI* oldURI = mStyleSheet->GetSheetURI()) {
       bool equal;
       nsresult rv = oldURI->Equals(uri, &equal);
       if (NS_SUCCEEDED(rv) && equal) {
-        return NS_OK; // We already loaded this stylesheet
+        return Update { };
       }
     }
   }
 
   if (mStyleSheet) {
     if (thisContent->IsInShadowTree()) {
       ShadowRoot* containingShadow = thisContent->GetContainingShadow();
       containingShadow->RemoveSheet(mStyleSheet);
@@ -292,86 +283,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"
 
 class nsIDocument;
 class nsIURI;
 
@@ -40,26 +41,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,
@@ -67,30 +68,35 @@ public:
     ePRELOAD =      0x00000080
   };
 
   // The return value is a bitwise or of 0 or more RelValues.
   static uint32_t ParseLinkTypes(const nsAString& aTypes);
 
   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 aOldDocument   should be non-null only if we're updating because we
+   *                       removed the node from the document.
+   * @param aOldShadowRoot should be non-null only if we're updating because we
+   *                       removed the node from a shadow tree.
    * @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.
+   *
+   * TODO(emilio): Should probably pass a single DocumentOrShadowRoot.
    */
-  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
@@ -116,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
@@ -187,17 +187,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)
@@ -323,32 +323,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.isErr()) {
+        rv = updateOrError.unwrapErr();
+      } else if (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
@@ -835,16 +835,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();
 }