Bug 992521 - Part 2: Make styles work when not in document, but contained by a ShadowRoot with a host in document. r=smaug
authorWilliam Chen <wchen@mozilla.com>
Sat, 07 Jun 2014 01:42:54 -0700
changeset 206600 8968e7307508e5cba5e1ee7597cb507afbeb6486
parent 206599 78af7d36d4a63960e93e1e82b4c9e12112799236
child 206601 a93e92a37640bc09123f486e5d8142fe4035fa8c
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs992521
milestone32.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 992521 - Part 2: Make styles work when not in document, but contained by a ShadowRoot with a host in document. r=smaug
content/base/src/Element.cpp
content/base/src/ShadowRoot.cpp
content/base/src/ShadowRoot.h
content/base/src/nsStyleLinkElement.cpp
dom/events/EventStateManager.cpp
dom/tests/mochitest/webcomponents/test_shadowroot_style.html
dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
dom/tests/mochitest/webcomponents/test_shadowroot_style_order.html
layout/base/RestyleTracker.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/style/Loader.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSStyleSheet.cpp
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -185,17 +185,17 @@ Element::IntrinsicState() const
 {
   return IsEditable() ? NS_EVENT_STATE_MOZ_READWRITE :
                         NS_EVENT_STATE_MOZ_READONLY;
 }
 
 void
 Element::NotifyStateChange(EventStates aStates)
 {
-  nsIDocument* doc = GetCurrentDoc();
+  nsIDocument* doc = GetCrossShadowCurrentDoc();
   if (doc) {
     nsAutoScriptBlocker scriptBlocker;
     doc->ContentStateChanged(this, aStates);
   }
 }
 
 void
 Element::UpdateLinkState(EventStates aState)
--- a/content/base/src/ShadowRoot.cpp
+++ b/content/base/src/ShadowRoot.cpp
@@ -119,24 +119,24 @@ ShadowRoot::FromNode(nsINode* aNode)
                "ShadowRoot is a document fragment.");
     return static_cast<ShadowRoot*>(aNode);
   }
 
   return nullptr;
 }
 
 void
-ShadowRoot::Restyle()
+ShadowRoot::StyleSheetChanged()
 {
   mProtoBinding->FlushSkinSheets();
 
   nsIPresShell* shell = OwnerDoc()->GetShell();
   if (shell) {
     OwnerDoc()->BeginUpdate(UPDATE_STYLE);
-    shell->RestyleShadowRoot(this);
+    shell->RecordShadowStyleChange(this);
     OwnerDoc()->EndUpdate(UPDATE_STYLE);
   }
 }
 
 void
 ShadowRoot::InsertSheet(nsCSSStyleSheet* aSheet,
                         nsIContent* aLinkingContent)
 {
@@ -161,31 +161,35 @@ ShadowRoot::InsertSheet(nsCSSStyleSheet*
 
     nsINode* sheetOwnerNode = sheets->ElementAt(i)->GetOwnerNode();
     if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwnerNode)) {
       sheets->InsertElementAt(i, aSheet);
       break;
     }
   }
 
-  Restyle();
+  if (aSheet->IsApplicable()) {
+    StyleSheetChanged();
+  }
 }
 
 void
 ShadowRoot::RemoveSheet(nsCSSStyleSheet* aSheet)
 {
   nsTArray<nsRefPtr<nsCSSStyleSheet> >* sheets =
     mProtoBinding->GetOrCreateStyleSheets();
   MOZ_ASSERT(sheets, "Style sheets array should never be null.");
 
   DebugOnly<bool> found = sheets->RemoveElement(aSheet);
   MOZ_ASSERT(found, "Trying to remove a sheet from a ShadowRoot "
                     "that does not exist.");
 
-  Restyle();
+  if (aSheet->IsApplicable()) {
+    StyleSheetChanged();
+  }
 }
 
 Element*
 ShadowRoot::GetElementById(const nsAString& aElementId)
 {
   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
   return entry ? entry->GetIdElement() : nullptr;
 }
@@ -498,17 +502,17 @@ ShadowRoot::ApplyAuthorStyles()
 void
 ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
 {
   mProtoBinding->SetInheritsStyle(aApplyAuthorStyles);
 
   nsIPresShell* shell = OwnerDoc()->GetShell();
   if (shell) {
     OwnerDoc()->BeginUpdate(UPDATE_STYLE);
-    shell->RestyleShadowRoot(this);
+    shell->RecordShadowStyleChange(this);
     OwnerDoc()->EndUpdate(UPDATE_STYLE);
   }
 }
 
 StyleSheetList*
 ShadowRoot::StyleSheets()
 {
   if (!mStyleSheetList) {
--- a/content/base/src/ShadowRoot.h
+++ b/content/base/src/ShadowRoot.h
@@ -122,18 +122,18 @@ public:
     GetElementsByTagName(const nsAString& aNamespaceURI);
   already_AddRefed<nsContentList>
     GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                            const nsAString& aLocalName);
   already_AddRefed<nsContentList>
     GetElementsByClassName(const nsAString& aClasses);
   void GetInnerHTML(nsAString& aInnerHTML);
   void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
+  void StyleSheetChanged();
 protected:
-  void Restyle();
 
   // The pool host is the parent of the nodes that will be distributed
   // into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
   nsCOMPtr<nsIContent> mPoolHost;
 
   // An array of content insertion points that are a descendant of the ShadowRoot
   // sorted in tree order. Insertion points are responsible for notifying
   // the ShadowRoot when they are removed or added as a descendant. The insertion
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -312,21 +312,26 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
   ShadowRoot* containingShadow = thisContent->GetContainingShadow();
   if (thisContent->IsHTML(nsGkAtoms::link) &&
       (aOldShadowRoot || containingShadow)) {
     return NS_OK;
   }
 
   Element* oldScopeElement = GetScopeElement(mStyleSheet);
 
-  if (mStyleSheet && aOldDocument) {
-    // We're removing the link element from the document, unload the
-    // stylesheet.  We want to do this even if updates are disabled, since
-    // otherwise a sheet with a stale linking element pointer will be hanging
-    // around -- not good!
+  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.");
+
+    // We're removing the link element from the document or shadow tree,
+    // unload the stylesheet.  We want to do this even if updates are
+    // disabled, since otherwise a sheet with a stale linking element pointer
+    // will be hanging around -- not good!
     if (aOldShadowRoot) {
       aOldShadowRoot->RemoveSheet(mStyleSheet);
     } else {
       aOldDocument->BeginUpdate(UPDATE_STYLE);
       aOldDocument->RemoveStyleSheet(mStyleSheet);
       aOldDocument->EndUpdate(UPDATE_STYLE);
     }
 
@@ -337,18 +342,17 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
   }
 
   // When static documents are created, stylesheets are cloned manually.
   if (mDontLoadStyle || !mUpdatesEnabled ||
       thisContent->OwnerDoc()->IsStaticDocument()) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDocument> doc = thisContent->GetDocument();
-
+  nsCOMPtr<nsIDocument> doc = thisContent->GetCrossShadowCurrentDoc();
   if (!doc || !doc->CSSLoader()->GetEnabled()) {
     return NS_OK;
   }
 
   bool isInline;
   nsCOMPtr<nsIURI> uri = GetStyleSheetURL(&isInline);
 
   if (!aForceUpdate && mStyleSheet && !isInline && uri) {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2006,17 +2006,17 @@ EventStateManager::DoScrollZoom(nsIFrame
   nsIContent *content = aTargetFrame->GetContent();
   if (content &&
       !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
       !nsContentUtils::IsInChromeDocshell(content->OwnerDoc()))
     {
       // positive adjustment to decrease zoom, negative to increase
       int32_t change = (adjustment > 0) ? -1 : 1;
 
-      if (Preferences::GetBool("browser.zoom.full") || content->GetCurrentDoc()->IsSyntheticDocument()) {
+      if (Preferences::GetBool("browser.zoom.full") || content->OwnerDoc()->IsSyntheticDocument()) {
         ChangeFullZoom(change);
       } else {
         ChangeTextSize(change);
       }
     }
 }
 
 static nsIFrame*
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_style.html
+++ b/dom/tests/mochitest/webcomponents/test_shadowroot_style.html
@@ -5,20 +5,23 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <title>Test for ShadowRoot styling</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <div class="tall" id="bodydiv"></div>
+<div id="container"></div>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
 <script>
 // Create ShadowRoot.
+var container = document.getElementById("container");
 var elem = document.createElement("div");
+container.appendChild(elem); // Put ShadowRoot host in document.
 var root = elem.createShadowRoot();
 
 // A style element that will be appended into the ShadowRoot.
 var shadowStyle = document.createElement("style");
 shadowStyle.innerHTML = ".tall { height: 100px; } .fat { padding-left: inherit; }";
 
 root.innerHTML = '<div id="divtostyle" class="tall fat"></div>';
 var divToStyle = root.getElementById("divtostyle");
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
+++ b/dom/tests/mochitest/webcomponents/test_shadowroot_style_multiple_shadow.html
@@ -5,20 +5,23 @@ https://bugzilla.mozilla.org/show_bug.cg
 -->
 <head>
   <title>Test for ShadowRoot styles with multiple ShadowRoot on host.</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <div class="tall" id="bodydiv"></div>
+<div id="container"></div>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
 <script>
 // Create ShadowRoot.
+var container = document.getElementById("container");
 var elem = document.createElement("div");
+container.appendChild(elem); // Put ShadowRoot host in document.
 var firstRoot = elem.createShadowRoot();
 var secondRoot = elem.createShadowRoot();
 var thirdRoot = elem.createShadowRoot();
 
 // A style element that will be appended into the ShadowRoot.
 var firstStyle = document.createElement("style");
 firstRoot.appendChild(firstStyle);
 is(firstRoot.styleSheets.length, 1, "firstStyle should be the only style in firstRoot.");
--- a/dom/tests/mochitest/webcomponents/test_shadowroot_style_order.html
+++ b/dom/tests/mochitest/webcomponents/test_shadowroot_style_order.html
@@ -4,20 +4,23 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=806506
 -->
 <head>
   <title>Test for ShadowRoot style order</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
+<div id="container"></div>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=806506">Bug 806506</a>
 <script>
 // Create ShadowRoot.
+var container = document.getElementById("container");
 var elem = document.createElement("div");
+container.appendChild(elem); // Put ShadowRoot host in document.
 var root = elem.createShadowRoot();
 
 // Style elements that will be appended into the ShadowRoot.
 var tallShadowStyle = document.createElement("style");
 tallShadowStyle.innerHTML = ".tall { height: 100px; }";
 
 var veryTallShadowStyle = document.createElement("style");
 veryTallShadowStyle.innerHTML = ".tall { height: 200px; }";
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -35,17 +35,17 @@ CollectLaterSiblings(nsISupports* aEleme
   dom::Element* element =
     static_cast<dom::Element*>(aElement);
   LaterSiblingCollector* collector =
     static_cast<LaterSiblingCollector*>(aSiblingCollector);
   // Only collect the entries that actually need restyling by us (and
   // haven't, for example, already been restyled).
   // It's important to not mess with the flags on entries not in our
   // document.
-  if (element->GetCurrentDoc() == collector->tracker->Document() &&
+  if (element->GetCrossShadowCurrentDoc() == collector->tracker->Document() &&
       element->HasFlag(collector->tracker->RestyleBit()) &&
       (aData.mRestyleHint & eRestyle_LaterSiblings)) {
     collector->elements->AppendElement(element);
   }
 
   return PL_DHASH_NEXT;
 }
 
@@ -62,17 +62,17 @@ CollectRestyles(nsISupports* aElement,
   dom::Element* element =
     static_cast<dom::Element*>(aElement);
   RestyleCollector* collector =
     static_cast<RestyleCollector*>(aRestyleCollector);
   // Only collect the entries that actually need restyling by us (and
   // haven't, for example, already been restyled).
   // It's important to not mess with the flags on entries not in our
   // document.
-  if (element->GetCurrentDoc() != collector->tracker->Document() ||
+  if (element->GetCrossShadowCurrentDoc() != collector->tracker->Document() ||
       !element->HasFlag(collector->tracker->RestyleBit())) {
     return PL_DHASH_NEXT;
   }
 
   NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
                // Maybe we're just not reachable via the frame tree?
                (element->GetFlattenedTreeParent() &&
                 (!element->GetFlattenedTreeParent()->GetPrimaryFrame()||
@@ -108,17 +108,17 @@ CollectRestyles(nsISupports* aElement,
 inline void
 RestyleTracker::ProcessOneRestyle(Element* aElement,
                                   nsRestyleHint aRestyleHint,
                                   nsChangeHint aChangeHint)
 {
   NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
                   "Someone should have handled this before calling us");
   NS_PRECONDITION(Document(), "Must have a document");
-  NS_PRECONDITION(aElement->GetCurrentDoc() == Document(),
+  NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
                   "Element has unexpected document");
 
   nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
   if (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) {
     mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
                                     *this,
                                     (aRestyleHint & eRestyle_Subtree) != 0);
   } else if (aChangeHint &&
@@ -187,17 +187,17 @@ RestyleTracker::DoProcessRestyles()
       // element.
       nsRefPtr<Element> element;
       element.swap(mRestyleRoots[rootCount - 1]);
       mRestyleRoots.RemoveElementAt(rootCount - 1);
 
       // Do the document check before calling GetRestyleData, since we
       // don't want to do the sibling-processing GetRestyleData does if
       // the node is no longer relevant.
-      if (element->GetCurrentDoc() != Document()) {
+      if (element->GetCrossShadowCurrentDoc() != Document()) {
         // Content node has been removed from our document; nothing else
         // to do here
         continue;
       }
 
       RestyleData data;
       if (!GetRestyleData(element, &data)) {
         continue;
@@ -238,17 +238,17 @@ RestyleTracker::DoProcessRestyles()
   }
 
   mRestyleManager->EndProcessingRestyles();
 }
 
 bool
 RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData)
 {
-  NS_PRECONDITION(aElement->GetCurrentDoc() == Document(),
+  NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
                   "Unexpected document; this will lead to incorrect behavior!");
 
   if (!aElement->HasFlag(RestyleBit())) {
     NS_ASSERTION(!aElement->HasFlag(RootBit()), "Bogus root bit?");
     return false;
   }
 
 #ifdef DEBUG
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -537,17 +537,17 @@ public:
 
   void PostRecreateFramesFor(mozilla::dom::Element* aElement);
   void RestyleForAnimation(mozilla::dom::Element* aElement,
                            nsRestyleHint aHint);
 
   // ShadowRoot has APIs that can change styles so we only
   // want to restyle elements in the ShadowRoot and not the whole
   // document.
-  virtual void RestyleShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) = 0;
+  virtual void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot) = 0;
 
   /**
    * Determine if it is safe to flush all pending notifications
    * @param aIsSafeToFlush true if it is safe, false otherwise.
    *
    */
   virtual bool IsSafeToFlush() const = 0;
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6064,29 +6064,19 @@ public:
     tabChild->UpdateHitRegion(region);
   }
 private:
   PresShell* mShell;
   nsIFrame* mFrame;
 };
 
 void
-PresShell::RestyleShadowRoot(ShadowRoot* aShadowRoot)
-{
-  // Mark the children of the ShadowRoot as style changed but not
-  // the ShadowRoot itself because it is a document fragment and does not
-  // have a frame.
-  ExplicitChildIterator iterator(aShadowRoot);
-  for (nsIContent* child = iterator.GetNextChild();
-       child;
-       child = iterator.GetNextChild()) {
-    if (child->IsElement()) {
-      mChangedScopeStyleRoots.AppendElement(child->AsElement());
-    }
-  }
+PresShell::RecordShadowStyleChange(ShadowRoot* aShadowRoot)
+{
+  mChangedScopeStyleRoots.AppendElement(aShadowRoot->GetHost()->AsElement());
 }
 
 void
 PresShell::Paint(nsView*        aViewToPaint,
                  const nsRegion& aDirtyRegion,
                  uint32_t        aFlags)
 {
   PROFILER_LABEL("PresShell", "Paint",
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -361,17 +361,17 @@ public:
   virtual void RebuildImageVisibility(nsRect* aRect = nullptr) MOZ_OVERRIDE;
 
   virtual void EnsureImageInVisibleList(nsIImageLoadingContent* aImage) MOZ_OVERRIDE;
 
   virtual void RemoveImageFromVisibleList(nsIImageLoadingContent* aImage) MOZ_OVERRIDE;
 
   virtual bool AssumeAllImagesVisible() MOZ_OVERRIDE;
 
-  virtual void RestyleShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot);
+  virtual void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);
 
   void SetNextPaintCompressed() { mNextPaintCompressed = true; }
 
 protected:
   virtual ~PresShell();
 
   void HandlePostedReflowCallbacks(bool aInterruptible);
   void CancelPostedReflowCallbacks();
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1197,17 +1197,17 @@ Loader::CreateSheet(nsIURI* aURI,
     nsIURI *sheetURI;
     nsCOMPtr<nsIURI> baseURI;
     nsIURI* originalURI;
     if (!aURI) {
       // Inline style.  Use the document's base URL so that @import in
       // the inline sheet picks up the right base.
       NS_ASSERTION(aLinkingContent, "Inline stylesheet without linking content?");
       baseURI = aLinkingContent->GetBaseURI();
-      sheetURI = aLinkingContent->GetDocument()->GetDocumentURI();
+      sheetURI = aLinkingContent->OwnerDoc()->GetDocumentURI();
       originalURI = nullptr;
     } else {
       baseURI = aURI;
       sheetURI = aURI;
       originalURI = aURI;
     }
 
     nsRefPtr<nsCSSStyleSheet> sheet = new nsCSSStyleSheet(aCORSMode);
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -3504,20 +3504,21 @@ TreeMatchContext::InitAncestors(Element 
 {
   MOZ_ASSERT(!mAncestorFilter.mFilter);
   MOZ_ASSERT(mAncestorFilter.mHashes.IsEmpty());
   MOZ_ASSERT(mStyleScopes.IsEmpty());
 
   mAncestorFilter.mFilter = new AncestorFilter::Filter();
 
   if (MOZ_LIKELY(aElement)) {
-    MOZ_ASSERT(aElement->IsInDoc(),
-               "aElement must be in the document for the assumption that "
-               "GetParentNode() is non-null on all element ancestors of "
-               "aElement to be true");
+    MOZ_ASSERT(aElement->GetCurrentDoc() ||
+               aElement->HasFlag(NODE_IS_IN_SHADOW_TREE),
+               "aElement must be in the document or in shadow tree "
+               "for the assumption that GetParentNode() is non-null "
+               "on all element ancestors of aElement to be true");
     // Collect up the ancestors
     nsAutoTArray<Element*, 50> ancestors;
     Element* cur = aElement;
     do {
       ancestors.AppendElement(cur);
       nsINode* parent = cur->GetParentNode();
       if (!parent->IsElement()) {
         break;
--- a/layout/style/nsCSSStyleSheet.cpp
+++ b/layout/style/nsCSSStyleSheet.cpp
@@ -7,16 +7,17 @@
 /* representation of a CSS style sheet */
 
 #include "nsCSSStyleSheet.h"
 
 #include "nsIAtom.h"
 #include "nsCSSRuleProcessor.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/MediaListBinding.h"
 #include "mozilla/css/NameSpaceRule.h"
 #include "mozilla/css/GroupRule.h"
 #include "mozilla/css/ImportRule.h"
 #include "nsIMediaList.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
@@ -1288,16 +1289,23 @@ nsCSSStyleSheet::SetComplete()
   NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!");
   mInner->mComplete = true;
   if (mDocument && !mDisabled) {
     // Let the document know
     mDocument->BeginUpdate(UPDATE_STYLE);
     mDocument->SetStyleSheetApplicableState(this, true);
     mDocument->EndUpdate(UPDATE_STYLE);
   }
+
+  if (mOwningNode && !mDisabled &&
+      mOwningNode->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
+      mOwningNode->IsContent()) {
+    ShadowRoot* shadowRoot = mOwningNode->AsContent()->GetContainingShadow();
+    shadowRoot->StyleSheetChanged();
+  }
 }
 
 /* virtual */ nsIStyleSheet*
 nsCSSStyleSheet::GetParentSheet() const
 {
   return mParent;
 }