Bug 508725 - Part 2: Record on nsCSSStyleSheets whether they are for a <style scoped>. r=dbaron
authorCameron McCormack <cam@mcc.id.au>
Wed, 09 Jan 2013 10:25:47 +1100
changeset 118522 b3c6cd8f1c5600decae9eb340ef626bec6acbdf8
parent 118521 20b096c3021c7a9260bdfcccb3603b7181c77035
child 118523 93fb0b4d9c77e870bf8fb4e7bf45bbb926f2e36e
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersdbaron
bugs508725
milestone21.0a1
Bug 508725 - Part 2: Record on nsCSSStyleSheets whether they are for a <style scoped>. r=dbaron
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsStyleLinkElement.cpp
layout/style/Loader.cpp
layout/style/Loader.h
layout/style/nsCSSStyleSheet.cpp
layout/style/nsCSSStyleSheet.h
layout/style/nsRuleData.h
layout/style/nsRuleNode.h
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2022,16 +2022,35 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
   // Refresh the principal on the compartment.
   nsPIDOMWindow* win = GetInnerWindow();
   if (win) {
     win->RefreshCompartmentPrincipal();
   }
 }
 
 void
+nsDocument::RemoveDocStyleSheetsFromStyleSets()
+{
+  // The stylesheets should forget us
+  int32_t indx = mStyleSheets.Count();
+  while (--indx >= 0) {
+    nsIStyleSheet* sheet = mStyleSheets[indx];
+    sheet->SetOwningDocument(nullptr);
+
+    if (sheet->IsApplicable()) {
+      nsCOMPtr<nsIPresShell> shell = GetShell();
+      if (shell) {
+        shell->StyleSet()->RemoveDocStyleSheet(sheet);
+      }
+    }
+    // XXX Tell observers?
+  }
+}
+
+void
 nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray<nsIStyleSheet>& aSheets, nsStyleSet::sheetType aType)
 {
   // The stylesheets should forget us
   int32_t indx = aSheets.Count();
   while (--indx >= 0) {
     nsIStyleSheet* sheet = aSheets[indx];
     sheet->SetOwningDocument(nullptr);
 
@@ -2048,17 +2067,17 @@ nsDocument::RemoveStyleSheetsFromStyleSe
 }
 
 nsresult
 nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
 {
   NS_PRECONDITION(aURI, "Null URI passed to ResetStylesheetsToURI");
 
   mozAutoDocUpdate upd(this, UPDATE_STYLE, true);
-  RemoveStyleSheetsFromStyleSets(mStyleSheets, nsStyleSet::eDocSheet);
+  RemoveDocStyleSheetsFromStyleSets();
   RemoveStyleSheetsFromStyleSets(mCatalogSheets, nsStyleSet::eAgentSheet);
   RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], nsStyleSet::eAgentSheet);
   RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], nsStyleSet::eUserSheet);
   RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], nsStyleSet::eDocSheet);
 
   // Release all the sheets
   mStyleSheets.Clear();
   for (uint32_t i = 0; i < SheetTypeCount; ++i)
@@ -3497,17 +3516,17 @@ nsDocument::AddStyleSheet(nsIStyleSheet*
   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, true));
 }
 
 void
 nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet)
 {
   nsCOMPtr<nsIPresShell> shell = GetShell();
   if (shell) {
-    shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet);
+    shell->StyleSet()->RemoveDocStyleSheet(aSheet);
   }
 }
 
 void
 nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
 {
   NS_PRECONDITION(aSheet, "null arg");
   nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -1075,16 +1075,17 @@ public:
   virtual void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv);
 
 protected:
   nsresult doCreateShell(nsPresContext* aContext,
                          nsViewManager* aViewManager, nsStyleSet* aStyleSet,
                          nsCompatibility aCompatMode,
                          nsIPresShell** aInstancePtrResult);
 
+  void RemoveDocStyleSheetsFromStyleSets();
   void RemoveStyleSheetsFromStyleSets(nsCOMArray<nsIStyleSheet>& aSheets, 
                                       nsStyleSet::sheetType aType);
   nsresult ResetStylesheetsToURI(nsIURI* aURI);
   void FillStyleSet(nsStyleSet* aStyleSet);
 
   // Return whether all the presshells for this document are safe to flush
   bool IsSafeToFlush() const;
   
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -373,17 +373,17 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
   nsresult rv = NS_OK;
   if (isInline) {
     nsAutoString text;
     nsContentUtils::GetNodeTextContent(thisContent, false, text);
 
     // Parse the style sheet.
     rv = doc->CSSLoader()->
       LoadInlineStyle(thisContent, text, mLineNumber, title, media,
-                      aObserver, &doneLoading, &isAlternate);
+                      scopeElement, aObserver, &doneLoading, &isAlternate);
   }
   else {
     // XXXbz clone the URI here to work around content policies modifying URIs.
     nsCOMPtr<nsIURI> clonedURI;
     uri->Clone(getter_AddRefs(clonedURI));
     NS_ENSURE_TRUE(clonedURI, NS_ERROR_OUT_OF_MEMORY);
     rv = doc->CSSLoader()->
       LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -13,16 +13,17 @@
  * Date             Modified by     Description of modification
  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
  */
 
 /* loading of CSS style sheets using the network APIs */
 
 #include "mozilla/Util.h"
 
+#include "mozilla/dom/Element.h"
 #include "mozilla/css/Loader.h"
 #include "nsIRunnable.h"
 #include "nsIUnicharStreamLoader.h"
 #include "nsSyncLoadService.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsString.h"
 #include "nsIContent.h"
@@ -65,16 +66,18 @@
 
 #include "nsIChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "mozilla/dom/EncodingUtils.h"
 using mozilla::dom::EncodingUtils;
 
+using namespace mozilla::dom;
+
 /**
  * OVERALL ARCHITECTURE
  *
  * The CSS Loader gets requests to load various sorts of style sheets:
  * inline style from <style> elements, linked style, @import-ed child
  * sheets, non-document sheets.  The loader handles the following tasks:
  *
  * 1) Checking whether the load is allowed: CheckLoadAllowed()
@@ -1201,16 +1204,17 @@ Loader::CreateSheet(nsIURI* aURI,
  * well as setting the enabled state based on the title and whether
  * the sheet had "alternate" in its rel.
  */
 nsresult
 Loader::PrepareSheet(nsCSSStyleSheet* aSheet,
                      const nsSubstring& aTitle,
                      const nsSubstring& aMediaString,
                      nsMediaList* aMediaList,
+                     Element* aScopeElement,
                      bool isAlternate)
 {
   NS_PRECONDITION(aSheet, "Must have a sheet!");
 
   nsresult rv;
   nsRefPtr<nsMediaList> mediaList(aMediaList);
 
   if (!aMediaString.IsEmpty()) {
@@ -1227,16 +1231,17 @@ Loader::PrepareSheet(nsCSSStyleSheet* aS
                                      true);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   aSheet->SetMedia(mediaList);
 
   aSheet->SetTitle(aTitle);
   aSheet->SetEnabled(! isAlternate);
+  aSheet->SetScopeElement(aScopeElement);
   return NS_OK;
 }
 
 /**
  * InsertSheetInDoc handles ordering of sheets in the document.  Here
  * we have two types of sheets -- those with linking elements and
  * those without.  The latter are loaded by Link: headers.
  * The following constraints are observed:
@@ -1789,16 +1794,17 @@ Loader::DoSheetComplete(SheetLoadData* a
 }
 
 nsresult
 Loader::LoadInlineStyle(nsIContent* aElement,
                         const nsAString& aBuffer,
                         uint32_t aLineNumber,
                         const nsAString& aTitle,
                         const nsAString& aMedia,
+                        Element* aScopeElement,
                         nsICSSLoaderObserver* aObserver,
                         bool* aCompleted,
                         bool* aIsAlternate)
 {
   LOG(("css::Loader::LoadInlineStyle"));
   NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
 
   *aCompleted = true;
@@ -1821,17 +1827,18 @@ Loader::LoadInlineStyle(nsIContent* aEle
   nsresult rv = CreateSheet(nullptr, aElement, nullptr, CORS_NONE, false, false,
                             aTitle, state, aIsAlternate, getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ASSERTION(state == eSheetNeedsParser,
                "Inline sheets should not be cached");
 
   LOG(("  Sheet is alternate: %d", *aIsAlternate));
 
-  rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate);
+  rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement,
+                    *aIsAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = InsertSheetInDoc(sheet, aElement, mDocument);
   NS_ENSURE_SUCCESS(rv, rv);
 
   SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
                                           owningElement, *aIsAlternate,
                                           aObserver, nullptr);
@@ -1894,17 +1901,17 @@ Loader::LoadStyleLink(nsIContent* aEleme
   nsRefPtr<nsCSSStyleSheet> sheet;
   rv = CreateSheet(aURL, aElement, principal, aCORSMode, false,
                    aHasAlternateRel, aTitle, state, aIsAlternate,
                    getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOG(("  Sheet is alternate: %d", *aIsAlternate));
 
-  rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate);
+  rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = InsertSheetInDoc(sheet, aElement, mDocument);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
 
   if (state == eSheetComplete) {
@@ -2052,17 +2059,17 @@ Loader::LoadChildSheet(nsCSSStyleSheet* 
   StyleSheetState state;
   const nsSubstring& empty = EmptyString();
   // For now, use CORS_NONE for child sheets
   rv = CreateSheet(aURL, nullptr, principal, CORS_NONE,
                    parentData ? parentData->mSyncLoad : false,
                    false, empty, state, &isAlternate, getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = PrepareSheet(sheet, empty, empty, aMedia, isAlternate);
+  rv = PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete"));
     // We're completely done.  No need to notify, even, since the
@@ -2163,17 +2170,17 @@ Loader::InternalLoadNonDocumentSheet(nsI
   nsRefPtr<nsCSSStyleSheet> sheet;
   bool syncLoad = (aObserver == nullptr);
   const nsSubstring& empty = EmptyString();
 
   rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aCORSMode, syncLoad, false,
                    empty, state, &isAlternate, getter_AddRefs(sheet));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = PrepareSheet(sheet, empty, empty, nullptr, isAlternate);
+  rv = PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete"));
     if (aObserver || !mObservers.IsEmpty()) {
       rv = PostLoadEvent(aURL, sheet, aObserver, false, nullptr);
     }
     if (aSheet) {
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -27,16 +27,22 @@ class nsCSSStyleSheet;
 class nsIContent;
 class nsIDocument;
 class nsCSSParser;
 class nsMediaList;
 class nsIStyleSheetLinkingElement;
 class nsCycleCollectionTraversalCallback;
 
 namespace mozilla {
+namespace dom {
+class Element;
+}
+}
+
+namespace mozilla {
 
 class URIPrincipalAndCORSModeHashKey : public nsURIHashKey
 {
 public:
   typedef URIPrincipalAndCORSModeHashKey* KeyType;
   typedef const URIPrincipalAndCORSModeHashKey* KeyTypePointer;
 
   URIPrincipalAndCORSModeHashKey(const URIPrincipalAndCORSModeHashKey* aKey)
@@ -155,16 +161,17 @@ public:
    * @param [out] aIsAlternate whether the stylesheet ended up being an
    *        alternate sheet.
    */
   nsresult LoadInlineStyle(nsIContent* aElement,
                            const nsAString& aBuffer,
                            uint32_t aLineNumber,
                            const nsAString& aTitle,
                            const nsAString& aMedia,
+                           mozilla::dom::Element* aScopeElement,
                            nsICSSLoaderObserver* aObserver,
                            bool* aCompleted,
                            bool* aIsAlternate);
 
   /**
    * Load a linked (document) stylesheet.  If a successful result is returned,
    * aObserver is guaranteed to be notified asynchronously once the sheet is
    * loaded and marked complete.  If an error is returned, aObserver will not
@@ -390,16 +397,17 @@ private:
 
   // Pass in either a media string or the nsMediaList from the
   // CSSParser.  Don't pass both.
   // This method will set the sheet's enabled state based on isAlternate
   nsresult PrepareSheet(nsCSSStyleSheet* aSheet,
                         const nsAString& aTitle,
                         const nsAString& aMediaString,
                         nsMediaList* aMediaList,
+                        mozilla::dom::Element* aScopeElement,
                         bool isAlternate);
 
   nsresult InsertSheetInDoc(nsCSSStyleSheet* aSheet,
                             nsIContent* aLinkingContent,
                             nsIDocument* aDocument);
 
   nsresult InsertChildSheet(nsCSSStyleSheet* aSheet,
                             nsCSSStyleSheet* aParentSheet,
--- a/layout/style/nsCSSStyleSheet.cpp
+++ b/layout/style/nsCSSStyleSheet.cpp
@@ -6,16 +6,17 @@
 
 /* representation of a CSS style sheet */
 
 #include "nsCSSStyleSheet.h"
 
 #include "nsCRT.h"
 #include "nsIAtom.h"
 #include "nsCSSRuleProcessor.h"
+#include "mozilla/dom/Element.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"
 #include "nsString.h"
@@ -36,16 +37,17 @@
 #include "mozAutoDocUpdate.h"
 #include "mozilla/css/Declaration.h"
 #include "nsRuleNode.h"
 #include "nsMediaFeatures.h"
 #include "nsDOMClassInfoID.h"
 #include "mozilla/Likely.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 
 // -------------------------------
 // Style Rule List for the DOM
 //
 class CSSRuleListImpl : public nsICSSRuleList
 {
 public:
@@ -1028,16 +1030,17 @@ nsCSSStyleSheetInner::SizeOfIncludingThi
 nsCSSStyleSheet::nsCSSStyleSheet(CORSMode aCORSMode)
   : mTitle(), 
     mParent(nullptr),
     mOwnerRule(nullptr),
     mDocument(nullptr),
     mOwningNode(nullptr),
     mDisabled(false),
     mDirty(false),
+    mScopeElement(nullptr),
     mRuleProcessors(nullptr)
 {
 
   mInner = new nsCSSStyleSheetInner(this, aCORSMode);
 }
 
 nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
                                  nsCSSStyleSheet* aParentToUse,
@@ -1046,16 +1049,17 @@ nsCSSStyleSheet::nsCSSStyleSheet(const n
                                  nsIDOMNode* aOwningNodeToUse)
   : mTitle(aCopy.mTitle),
     mParent(aParentToUse),
     mOwnerRule(aOwnerRuleToUse),
     mDocument(aDocumentToUse),
     mOwningNode(aOwningNodeToUse),
     mDisabled(aCopy.mDisabled),
     mDirty(aCopy.mDirty),
+    mScopeElement(nullptr),
     mInner(aCopy.mInner),
     mRuleProcessors(nullptr)
 {
 
   mInner->AddSheet(this);
 
   if (mDirty) { // CSSOM's been there, force full copy now
     NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
@@ -1192,22 +1196,24 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSStyl
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSStyleSheet)
   tmp->DropMedia();
   // We do not unlink mNext; our parent will handle that.  If we
   // unlinked it here, our parent would not be able to walk its list
   // of child sheets and null out the back-references to it, if we got
   // unlinked before it does.
   tmp->DropRuleCollection();
   tmp->UnlinkInner();
+  tmp->mScopeElement = nullptr;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSStyleSheet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia)
   // We do not traverse mNext; our parent will handle that.  See
   // comments in Unlink for why.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement)
   tmp->TraverseInner(cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 nsresult
 nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
 {
   if (! mRuleProcessors) {
--- a/layout/style/nsCSSStyleSheet.h
+++ b/layout/style/nsCSSStyleSheet.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* representation of a CSS style sheet */
 
 #ifndef nsCSSStyleSheet_h_
 #define nsCSSStyleSheet_h_
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/Element.h"
 
 #include "nscore.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIStyleSheet.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsCOMArray.h"
@@ -242,16 +243,22 @@ public:
   // list after we clone a unique inner for ourselves.
   static bool RebuildChildList(mozilla::css::Rule* aRule, void* aBuilder);
 
   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const MOZ_OVERRIDE;
 
   // Get this style sheet's CORS mode
   mozilla::CORSMode GetCORSMode() const { return mInner->mCORSMode; }
 
+  mozilla::dom::Element* GetScopeElement() const { return mScopeElement; }
+  void SetScopeElement(mozilla::dom::Element* aScopeElement)
+  {
+    mScopeElement = aScopeElement;
+  }
+
 private:
   nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
                   nsCSSStyleSheet* aParentToUse,
                   mozilla::css::ImportRule* aOwnerRuleToUse,
                   nsIDocument* aDocumentToUse,
                   nsIDOMNode* aOwningNodeToUse);
 
   nsCSSStyleSheet(const nsCSSStyleSheet& aCopy) MOZ_DELETE;
@@ -292,16 +299,17 @@ protected:
   nsCSSStyleSheet*      mParent;    // weak ref
   mozilla::css::ImportRule* mOwnerRule; // weak ref
 
   nsRefPtr<CSSRuleListImpl> mRuleCollection;
   nsIDocument*          mDocument; // weak ref; parents maintain this for their children
   nsIDOMNode*           mOwningNode; // weak ref
   bool                  mDisabled;
   bool                  mDirty; // has been modified 
+  nsRefPtr<mozilla::dom::Element> mScopeElement;
 
   nsCSSStyleSheetInner* mInner;
 
   nsAutoTArray<nsCSSRuleProcessor*, 8>* mRuleProcessors;
 
   friend class nsMediaList;
   friend class nsCSSRuleProcessor;
   friend struct ChildSheetListBuilder;
--- a/layout/style/nsRuleData.h
+++ b/layout/style/nsRuleData.h
@@ -20,17 +20,17 @@ struct nsRuleData;
 
 typedef void (*nsPostResolveFunc)(void* aStyleStruct, nsRuleData* aData);
 
 struct nsRuleData
 {
   const uint32_t mSIDs;
   bool mCanStoreInRuleTree;
   bool mIsImportantRule;
-  uint8_t mLevel; // an nsStyleSet::sheetType
+  uint16_t mLevel; // an nsStyleSet::sheetType
   nsPresContext* const mPresContext;
   nsStyleContext* const mStyleContext;
   const nsPostResolveFunc mPostResolveCallback;
 
   // We store nsCSSValues needed to compute the data for one or more
   // style structs (specified by the bitfield mSIDs).  These are stored
   // in a single array allocation (which our caller allocates; see
   // AutoCSSValueArray)   The offset of each property |prop| in
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -640,17 +640,17 @@ public:
   static void EnsureBlockDisplay(uint8_t& display);
 
   // Transition never returns null; on out of memory it'll just return |this|.
   nsRuleNode* Transition(nsIStyleRule* aRule, uint8_t aLevel,
                          bool aIsImportantRule);
   nsRuleNode* GetParent() const { return mParent; }
   bool IsRoot() const { return mParent == nullptr; }
 
-  // These PRUint8s are really nsStyleSet::sheetType values.
+  // These uint8_ts are really nsStyleSet::sheetType values.
   uint8_t GetLevel() const {
     NS_ASSERTION(!IsRoot(), "can't call on root");
     return (mDependentBits & NS_RULE_NODE_LEVEL_MASK) >>
              NS_RULE_NODE_LEVEL_SHIFT;
   }
   bool IsImportantRule() const {
     NS_ASSERTION(!IsRoot(), "can't call on root");
     return (mDependentBits & NS_RULE_NODE_IS_IMPORTANT) != 0;
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -95,16 +95,17 @@ nsInitialStyleRule::List(FILE* out, int3
   fputs("[initial style rule] {}\n", out);
 }
 #endif
 
 static const nsStyleSet::sheetType gCSSSheetTypes[] = {
   nsStyleSet::eAgentSheet,
   nsStyleSet::eUserSheet,
   nsStyleSet::eDocSheet,
+  nsStyleSet::eScopedDocSheet,
   nsStyleSet::eOverrideSheet
 };
 
 nsStyleSet::nsStyleSet()
   : mRuleTree(nullptr),
     mBatching(0),
     mInShutdown(false),
     mAuthorStyleDisabled(false),
@@ -256,16 +257,25 @@ nsStyleSet::GatherRuleProcessors(sheetTy
         mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
         break;
     }
   }
 
   return NS_OK;
 }
 
+static bool
+IsScopedStyleSheet(nsIStyleSheet* aSheet)
+{
+  nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
+  NS_ASSERTION(cssSheet, "expected aSheet to be an nsCSSStyleSheet");
+
+  return cssSheet->GetScopeElement();
+}
+
 nsresult
 nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
 {
   NS_PRECONDITION(aSheet, "null arg");
   NS_ASSERTION(aSheet->IsApplicable(),
                "Inapplicable sheet being placed in style set");
   mSheets[aType].RemoveObject(aSheet);
   if (!mSheets[aType].AppendObject(aSheet))
@@ -371,49 +381,60 @@ nsStyleSet::SetAuthorStyleDisabled(bool 
 
 nsresult
 nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
 {
   NS_PRECONDITION(aSheet && aDocument, "null arg");
   NS_ASSERTION(aSheet->IsApplicable(),
                "Inapplicable sheet being placed in style set");
 
-  nsCOMArray<nsIStyleSheet>& docSheets = mSheets[eDocSheet];
+  sheetType type = IsScopedStyleSheet(aSheet) ?
+                     eScopedDocSheet :
+                     eDocSheet;
+  nsCOMArray<nsIStyleSheet>& sheets = mSheets[type];
 
-  docSheets.RemoveObject(aSheet);
+  sheets.RemoveObject(aSheet);
   nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
 
   // lowest index first
   int32_t newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
 
-  int32_t count = docSheets.Count();
+  int32_t count = sheets.Count();
   int32_t index;
   for (index = 0; index < count; index++) {
-    nsIStyleSheet* sheet = docSheets.ObjectAt(index);
+    nsIStyleSheet* sheet = sheets.ObjectAt(index);
     int32_t sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
     if (sheetDocIndex > newDocIndex)
       break;
 
     // If the sheet is not owned by the document it can be an author
     // sheet registered at nsStyleSheetService or an additional author
     // sheet on the document, which means the new 
     // doc sheet should end up before it.
     if (sheetDocIndex < 0 &&
         ((sheetService &&
         sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0) ||
         sheet == aDocument->FirstAdditionalAuthorSheet()))
         break;
   }
-  if (!docSheets.InsertObjectAt(aSheet, index))
+  if (!sheets.InsertObjectAt(aSheet, index))
     return NS_ERROR_OUT_OF_MEMORY;
   if (!mBatching)
-    return GatherRuleProcessors(eDocSheet);
+    return GatherRuleProcessors(type);
+
+  mDirty |= 1 << type;
+  return NS_OK;
+}
 
-  mDirty |= 1 << eDocSheet;
-  return NS_OK;
+nsresult
+nsStyleSet::RemoveDocStyleSheet(nsIStyleSheet *aSheet)
+{
+  nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
+  bool isScoped = cssSheet && cssSheet->GetScopeElement();
+  return RemoveStyleSheet(isScoped ? eScopedDocSheet : eDocSheet, aSheet);
 }
 
 // Batching
 void
 nsStyleSet::BeginUpdate()
 {
   ++mBatching;
 }
@@ -1254,46 +1275,52 @@ nsStyleSet::ResolveXULTreePseudoStyle(El
 
 bool
 nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext,
                                 nsTArray<nsFontFaceRuleContainer>& aArray)
 {
   NS_ENSURE_FALSE(mInShutdown, false);
 
   for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
+    if (gCSSSheetTypes[i] == eScopedDocSheet)
+      continue;
     nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
     if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
       return false;
   }
   return true;
 }
 
 bool
 nsStyleSet::AppendKeyframesRules(nsPresContext* aPresContext,
                                  nsTArray<nsCSSKeyframesRule*>& aArray)
 {
   NS_ENSURE_FALSE(mInShutdown, false);
 
   for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
+    if (gCSSSheetTypes[i] == eScopedDocSheet)
+      continue;
     nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
     if (ruleProc && !ruleProc->AppendKeyframesRules(aPresContext, aArray))
       return false;
   }
   return true;
 }
 
 bool
 nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
                             nsTArray<nsCSSPageRule*>& aArray)
 {
   NS_ENSURE_FALSE(mInShutdown, false);
 
   for (uint32_t i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
+    if (gCSSSheetTypes[i] == eScopedDocSheet)
+      continue;
     nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
     if (ruleProc && !ruleProc->AppendPageRules(aPresContext, aArray))
       return false;
   }
   return true;
 }
 
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -228,16 +228,17 @@ class nsStyleSet
 
   // The "origins" of the CSS cascade, from lowest precedence to
   // highest (for non-!important rules).
   enum sheetType {
     eAgentSheet, // CSS
     eUserSheet, // CSS
     ePresHintSheet,
     eDocSheet, // CSS
+    eScopedDocSheet,
     eStyleAttrSheet,
     eOverrideSheet, // CSS
     eAnimationSheet,
     eTransitionSheet,
     eSheetTypeCount
     // be sure to keep the number of bits in |mDirty| below and in
     // NS_RULE_NODE_LEVEL_MASK updated when changing the number of sheet
     // types
@@ -248,28 +249,29 @@ class nsStyleSet
   nsresult AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
   nsresult PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
   nsresult RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
   nsresult ReplaceSheets(sheetType aType,
                          const nsCOMArray<nsIStyleSheet> &aNewSheets);
   nsresult InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
                                   nsIStyleSheet *aReferenceSheet);
 
-  // Enable/Disable entire author style level (Doc & PresHint levels)
+  // Enable/Disable entire author style level (Doc, ScopedDoc & PresHint levels)
   bool GetAuthorStyleDisabled();
   nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
 
   int32_t SheetCount(sheetType aType) const {
     return mSheets[aType].Count();
   }
 
   nsIStyleSheet* StyleSheetAt(sheetType aType, int32_t aIndex) const {
     return mSheets[aType].ObjectAt(aIndex);
   }
 
+  nsresult RemoveDocStyleSheet(nsIStyleSheet* aSheet);
   nsresult AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument);
 
   void     BeginUpdate();
   nsresult EndUpdate();
 
   // Methods for reconstructing the tree; BeginReconstruct basically moves the
   // old rule tree root and style context roots out of the way,
   // and EndReconstruct destroys the old rule tree when we're done
@@ -383,17 +385,17 @@ class nsStyleSet
                          // lexicographic tree of matched rules that style
                          // contexts use to look up properties.
 
   uint16_t mBatching;
 
   unsigned mInShutdown : 1;
   unsigned mAuthorStyleDisabled: 1;
   unsigned mInReconstruct : 1;
-  unsigned mDirty : 8;  // one dirty bit is used per sheet type
+  unsigned mDirty : 9;  // one dirty bit is used per sheet type
 
   uint32_t mUnusedRuleNodeCount; // used to batch rule node GC
   nsTArray<nsStyleContext*> mRoots; // style contexts with no parent
 
   // Empty style rules to force things that restrict which properties
   // apply into different branches of the rule tree.
   nsRefPtr<nsEmptyStyleRule> mFirstLineRule, mFirstLetterRule, mPlaceholderRule;