Bug 1436059: Make XBL / Shadow DOM use AuthorStyles. r?xidorn draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 12 Feb 2018 13:57:26 +0100
changeset 756082 d59f1598981584168aaf580eef77d85b06c0f384
parent 755799 ede64e4124eb5a17ff6404482cdc47ea996779fd
child 756083 9dbb2e25d00a9224aec9955f0c00d5279cd5daeb
push id99368
push userbmo:emilio@crisal.io
push dateFri, 16 Feb 2018 11:02:06 +0000
reviewersxidorn
bugs1436059
milestone60.0a1
Bug 1436059: Make XBL / Shadow DOM use AuthorStyles. r?xidorn It's just a struct aggregating stylesheets + CascadeData, with a quirks_mode parameter because XBL sucks so bad. MozReview-Commit-ID: 7q99tSNXo0K
dom/xbl/nsBindingManager.cpp
dom/xbl/nsBindingManager.h
dom/xbl/nsXBLBinding.cpp
dom/xbl/nsXBLBinding.h
dom/xbl/nsXBLPrototypeBinding.cpp
dom/xbl/nsXBLPrototypeBinding.h
dom/xbl/nsXBLPrototypeResources.cpp
dom/xbl/nsXBLPrototypeResources.h
dom/xbl/nsXBLResourceLoader.cpp
layout/inspector/InspectorUtils.cpp
layout/inspector/ServoStyleRuleMap.cpp
layout/inspector/ServoStyleRuleMap.h
layout/style/ServoBindingList.h
layout/style/ServoBindingTypes.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSheet.h
servo/components/style/author_styles.rs
servo/components/style/dom.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/gecko_bindings/sugar/ns_t_array.rs
servo/components/style/invalidation/element/state_and_attributes.rs
servo/components/style/lib.rs
servo/components/style/stylesheet_set.rs
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -783,34 +783,16 @@ nsBindingManager::MediumFeaturesChanged(
   return rulesChanged;
 #else
   MOZ_CRASH("old style system disabled");
   return false;
 #endif
 }
 
 void
-nsBindingManager::UpdateBoundContentBindingsForServo(nsPresContext* aPresContext)
-{
-  MOZ_ASSERT(mDocument->IsStyledByServo(),
-             "This should be called only by servo-backend!");
-
-  RefPtr<nsPresContext> presContext = aPresContext;
-
-  EnumerateBoundContentBindings([=](nsXBLBinding* aBinding) {
-    nsXBLPrototypeBinding* protoBinding = aBinding->PrototypeBinding();
-    ServoStyleSet* styleSet = protoBinding->GetServoStyleSet();
-    if (styleSet && styleSet->StyleSheetsHaveChanged()) {
-      protoBinding->ComputeServoStyleSet(presContext);
-    }
-    return true;
-  });
-}
-
-void
 nsBindingManager::AppendAllSheets(nsTArray<StyleSheet*>& aArray)
 {
   EnumerateBoundContentBindings([&aArray](nsXBLBinding* aBinding) {
     aBinding->PrototypeBinding()->AppendStyleSheetsTo(aArray);
     return true;
   });
 }
 
--- a/dom/xbl/nsBindingManager.h
+++ b/dom/xbl/nsBindingManager.h
@@ -137,20 +137,16 @@ public:
 
   // Do any processing that needs to happen as a result of a change in the
   // characteristics of the medium, and return whether this rule processor's
   // rules or the servo style set have changed (e.g., because of media
   // queries).
   bool MediumFeaturesChanged(nsPresContext* aPresContext,
                              mozilla::MediaFeatureChangeReason);
 
-  // Update the content bindings in mBoundContentSet due to medium features
-  // changed.
-  void UpdateBoundContentBindingsForServo(nsPresContext* aPresContext);
-
   void AppendAllSheets(nsTArray<mozilla::StyleSheet*>& aArray);
 
   void Traverse(nsIContent *aContent,
                             nsCycleCollectionTraversalCallback &cb);
 
   NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
 
   // Notify the binding manager when an outermost update begins and
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -833,20 +833,20 @@ nsXBLBinding::WalkRules(nsIStyleRuleProc
     mNextBinding->WalkRules(aFunc, aData);
 
   nsIStyleRuleProcessor *rules = mPrototypeBinding->GetRuleProcessor();
   if (rules)
     (*aFunc)(rules, aData);
 }
 #endif
 
-ServoStyleSet*
-nsXBLBinding::GetServoStyleSet() const
+const RawServoAuthorStyles*
+nsXBLBinding::GetServoStyles() const
 {
-  return mPrototypeBinding->GetServoStyleSet();
+  return mPrototypeBinding->GetServoStyles();
 }
 
 // Internal helper methods ////////////////////////////////////////////////////////////////
 
 // Get or create a WeakMap object on a given XBL-hosting global.
 //
 // The scheme is as follows. XBL-hosting globals (either privileged content
 // Windows or XBL scopes) get two lazily-defined WeakMap properties. Each
--- a/dom/xbl/nsXBLBinding.h
+++ b/dom/xbl/nsXBLBinding.h
@@ -18,19 +18,19 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupportsImpl.h"
 #include "js/TypeDecls.h"
 
 class nsXBLPrototypeBinding;
 class nsIContent;
 class nsAtom;
 class nsIDocument;
+struct RawServoAuthorStyles;
 
 namespace mozilla {
-class ServoStyleSet;
 namespace dom {
 
 class ShadowRoot;
 class XBLChildrenElement;
 
 } // namespace dom
 } // namespace mozilla
 
@@ -130,17 +130,17 @@ public:
                         bool aRemoveFlag, bool aNotify);
 
   void ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument);
 
 #ifdef MOZ_OLD_STYLE
   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
 #endif
 
-  mozilla::ServoStyleSet* GetServoStyleSet() const;
+  const RawServoAuthorStyles* GetServoStyles() const;
 
   static nsresult DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> obj,
                                 const nsString& aClassName,
                                 nsXBLPrototypeBinding* aProtoBinding,
                                 JS::MutableHandle<JSObject*> aClassObject,
                                 bool* aNew);
 
   bool AllowScripts();
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -574,30 +574,16 @@ nsXBLPrototypeBinding::GetRuleProcessor(
     return mResources->GetRuleProcessor();
   }
 
   return nullptr;
 }
 #endif
 
 void
-nsXBLPrototypeBinding::ComputeServoStyleSet(nsPresContext* aPresContext)
-{
-  if (mResources) {
-    mResources->ComputeServoStyleSet(aPresContext);
-  }
-}
-
-ServoStyleSet*
-nsXBLPrototypeBinding::GetServoStyleSet() const
-{
-  return mResources ? mResources->GetServoStyleSet() : nullptr;
-}
-
-void
 nsXBLPrototypeBinding::EnsureAttributeTable()
 {
   if (!mAttributeTable) {
     mAttributeTable =
         new nsClassHashtable<nsUint32HashKey, InnerAttributeTable>(2);
   }
 }
 
--- a/dom/xbl/nsXBLPrototypeBinding.h
+++ b/dom/xbl/nsXBLPrototypeBinding.h
@@ -130,18 +130,31 @@ public:
   mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
   size_t SheetCount() const;
   bool HasStyleSheets() const;
   void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
 
 #ifdef MOZ_OLD_STYLE
   nsIStyleRuleProcessor* GetRuleProcessor();
 #endif
-  void ComputeServoStyleSet(nsPresContext* aPresContext);
-  mozilla::ServoStyleSet* GetServoStyleSet() const;
+  const RawServoAuthorStyles* GetServoStyles() const
+  {
+    return mResources ? mResources->GetServoStyles() : nullptr;
+  }
+  RawServoAuthorStyles* GetServoStyles()
+  {
+    return mResources
+      ? const_cast<RawServoAuthorStyles*>(mResources->GetServoStyles())
+      : nullptr;
+  }
+
+  mozilla::ServoStyleRuleMap* GetServoStyleRuleMap()
+  {
+    return mResources ? mResources->GetServoStyleRuleMap() : nullptr;
+  }
 
   nsresult FlushSkinSheets();
 
   nsAtom* GetBaseTag(int32_t* aNamespaceID);
   void SetBaseTag(int32_t aNamespaceID, nsAtom* aTag);
 
   bool ImplementsInterface(REFNSIID aIID) const;
 
--- a/dom/xbl/nsXBLPrototypeResources.cpp
+++ b/dom/xbl/nsXBLPrototypeResources.cpp
@@ -37,19 +37,16 @@ nsXBLPrototypeResources::nsXBLPrototypeR
 }
 
 nsXBLPrototypeResources::~nsXBLPrototypeResources()
 {
   MOZ_COUNT_DTOR(nsXBLPrototypeResources);
   if (mLoader) {
     mLoader->mResources = nullptr;
   }
-  if (mServoStyleSet) {
-    mServoStyleSet->Shutdown();
-  }
 }
 
 void
 nsXBLPrototypeResources::AddResource(nsAtom* aResourceType, const nsAString& aSrc)
 {
   if (mLoader)
     mLoader->AddResource(aResourceType, aSrc);
 }
@@ -117,17 +114,17 @@ nsXBLPrototypeResources::FlushSkinSheets
 
   if (doc->IsStyledByServo()) {
     // There may be no shell during unlink.
     //
     // FIXME(emilio): We shouldn't skip shadow root style updates just because?
     // Though during unlink is fine I guess...
     if (auto* shell = doc->GetShell()) {
       MOZ_ASSERT(shell->GetPresContext());
-      ComputeServoStyleSet(shell->GetPresContext());
+      ComputeServoStyles(*shell->StyleSet()->AsServo());
     }
   } else {
 #ifdef MOZ_OLD_STYLE
     GatherRuleProcessor();
 #else
     MOZ_CRASH("old style system disabled");
 #endif
   }
@@ -185,26 +182,39 @@ nsXBLPrototypeResources::GatherRuleProce
   mRuleProcessor = new nsCSSRuleProcessor(Move(sheets),
                                           SheetType::Doc,
                                           nullptr,
                                           mRuleProcessor);
 }
 #endif
 
 void
-nsXBLPrototypeResources::ComputeServoStyleSet(nsPresContext* aPresContext)
+nsXBLPrototypeResources::ComputeServoStyles(const ServoStyleSet& aMasterStyleSet)
 {
-  nsTArray<RefPtr<ServoStyleSheet>> sheets(mStyleSheetList.Length());
-  for (StyleSheet* sheet : mStyleSheetList) {
-    MOZ_ASSERT(sheet->IsServo(),
-               "This should only be called with Servo-flavored style backend!");
-    sheets.AppendElement(sheet->AsServo());
+  mStyleRuleMap.reset(nullptr);
+  mServoStyles.reset(Servo_AuthorStyles_Create());
+  for (auto& sheet : mStyleSheetList) {
+    Servo_AuthorStyles_AppendStyleSheet(mServoStyles.get(), sheet->AsServo());
+  }
+  Servo_AuthorStyles_Flush(mServoStyles.get(), aMasterStyleSet.RawSet());
+}
+
+ServoStyleRuleMap*
+nsXBLPrototypeResources::GetServoStyleRuleMap()
+{
+  if (!HasStyleSheets() || !mServoStyles) {
+    return nullptr;
   }
 
-  mServoStyleSet = ServoStyleSet::CreateXBLServoStyleSet(aPresContext, sheets);
+  if (!mStyleRuleMap) {
+    mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
+  }
+
+  mStyleRuleMap->EnsureTable(*this);
+  return mStyleRuleMap.get();
 }
 
 void
 nsXBLPrototypeResources::AppendStyleSheet(StyleSheet* aSheet)
 {
   mStyleSheetList.AppendElement(aSheet);
 }
 
@@ -215,32 +225,14 @@ nsXBLPrototypeResources::RemoveStyleShee
 }
 
 void
 nsXBLPrototypeResources::InsertStyleSheetAt(size_t aIndex, StyleSheet* aSheet)
 {
   mStyleSheetList.InsertElementAt(aIndex, aSheet);
 }
 
-StyleSheet*
-nsXBLPrototypeResources::StyleSheetAt(size_t aIndex) const
-{
-  return mStyleSheetList[aIndex];
-}
-
-size_t
-nsXBLPrototypeResources::SheetCount() const
-{
-  return mStyleSheetList.Length();
-}
-
-bool
-nsXBLPrototypeResources::HasStyleSheets() const
-{
-  return !mStyleSheetList.IsEmpty();
-}
-
 void
 nsXBLPrototypeResources::AppendStyleSheetsTo(
                                       nsTArray<StyleSheet*>& aResult) const
 {
   aResult.AppendElements(mStyleSheetList);
 }
--- a/dom/xbl/nsXBLPrototypeResources.h
+++ b/dom/xbl/nsXBLPrototypeResources.h
@@ -3,27 +3,30 @@
 /* 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 nsXBLPrototypeResources_h__
 #define nsXBLPrototypeResources_h__
 
 #include "mozilla/StyleSheet.h"
+#include "mozilla/ServoStyleRuleMap.h"
 #include "nsICSSLoaderObserver.h"
 
 class nsCSSRuleProcessor;
 class nsAtom;
 class nsIContent;
 class nsXBLPrototypeBinding;
 class nsXBLResourceLoader;
+struct RawServoAuthorStyles;
 
 namespace mozilla {
 class CSSStyleSheet;
 class ServoStyleSet;
+class ServoStyleRuleMap;
 } // namespace mozilla
 
 // *********************************************************************/
 // The XBLPrototypeResources class
 
 class nsXBLPrototypeResources
 {
 public:
@@ -40,51 +43,71 @@ public:
   void Traverse(nsCycleCollectionTraversalCallback &cb);
   void Unlink();
 
   void ClearLoader();
 
   void AppendStyleSheet(mozilla::StyleSheet* aSheet);
   void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
   void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
-  mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
-  size_t SheetCount() const;
-  bool HasStyleSheets() const;
+
+  mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const
+  {
+    return mStyleSheetList[aIndex];
+  }
+
+  size_t SheetCount() const
+  {
+    return mStyleSheetList.Length();
+  }
+
+  bool HasStyleSheets() const
+  {
+    return !mStyleSheetList.IsEmpty();
+  }
+
   void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
 
 #ifdef MOZ_OLD_STYLE
   /**
    * Recreates mRuleProcessor to represent the current list of style sheets
    * stored in mStyleSheetList.  (Named GatherRuleProcessor to parallel
    * nsStyleSet::GatherRuleProcessors.)
    */
   void GatherRuleProcessor();
 
   nsCSSRuleProcessor* GetRuleProcessor() const { return mRuleProcessor; }
 #endif
 
+  const RawServoAuthorStyles* GetServoStyles() const
+  {
+    return mServoStyles.get();
+  }
+
+  mozilla::ServoStyleRuleMap* GetServoStyleRuleMap();
+
   // Updates the ServoStyleSet object that holds the result of cascading the
   // sheets in mStyleSheetList. Equivalent to GatherRuleProcessor(), but for
   // the Servo style backend.
-  void ComputeServoStyleSet(nsPresContext* aPresContext);
-
-  mozilla::ServoStyleSet* GetServoStyleSet() const { return mServoStyleSet.get(); }
+  void ComputeServoStyles(const mozilla::ServoStyleSet& aMasterStyleSet);
 
 private:
   // A loader object. Exists only long enough to load resources, and then it dies.
   RefPtr<nsXBLResourceLoader> mLoader;
 
   // A list of loaded stylesheets for this binding.
+  //
+  // FIXME(emilio): Remove when the old style system is gone, defer to
+  // mServoStyles.
   nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheetList;
 
 #ifdef MOZ_OLD_STYLE
   // The list of stylesheets converted to a rule processor.
   RefPtr<nsCSSRuleProcessor> mRuleProcessor;
 #endif
 
   // The result of cascading the XBL style sheets like mRuleProcessor, but
   // for the Servo style backend.
-  // XXX: We might want to design a better representation for the result of
-  // cascading the XBL style sheets, like a collection of SelectorMaps.
-  mozilla::UniquePtr<mozilla::ServoStyleSet> mServoStyleSet;
+  mozilla::UniquePtr<RawServoAuthorStyles> mServoStyles;
+  mozilla::UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap;
 };
 
 #endif
--- a/dom/xbl/nsXBLResourceLoader.cpp
+++ b/dom/xbl/nsXBLResourceLoader.cpp
@@ -193,18 +193,18 @@ nsXBLResourceLoader::StyleSheetLoaded(St
     // All stylesheets are loaded.
     if (aSheet->IsGecko()) {
 #ifdef MOZ_OLD_STYLE
       mResources->GatherRuleProcessor();
 #else
       MOZ_CRASH("old style system disabled");
 #endif
     } else {
-      mResources->ComputeServoStyleSet(
-        mBoundDocument->GetShell()->GetPresContext());
+      mResources->ComputeServoStyles(
+        *mBoundDocument->GetShell()->StyleSet()->AsServo());
     }
 
     // XXX Check for mPendingScripts when scripts also come online.
     if (!mInLoadResourcesFunc)
       NotifyBoundElements();
   }
   return NS_OK;
 }
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -225,28 +225,28 @@ InspectorUtils::GetCSSStyleRules(GlobalO
     ServoStyleContext* servo = styleContext->AsServo();
     nsTArray<const RawServoStyleRule*> rawRuleList;
     Servo_ComputedValues_GetStyleRuleList(servo, &rawRuleList);
 
     AutoTArray<ServoStyleRuleMap*, 1> maps;
     {
       ServoStyleSet* styleSet = shell->StyleSet()->AsServo();
       ServoStyleRuleMap* map = styleSet->StyleRuleMap();
-      map->EnsureTable();
       maps.AppendElement(map);
     }
 
     // Collect style rule maps for bindings.
     for (nsIContent* bindingContent = &aElement; bindingContent;
          bindingContent = bindingContent->GetBindingParent()) {
       for (nsXBLBinding* binding = bindingContent->GetXBLBinding();
            binding; binding = binding->GetBaseBinding()) {
-        if (ServoStyleSet* styleSet = binding->GetServoStyleSet()) {
-          ServoStyleRuleMap* map = styleSet->StyleRuleMap();
-          map->EnsureTable();
+        // TODO(emilio): We're going to need to figure out something for Shadow
+        // DOM and inspector, since those rules can definitely mutate and
+        // such...
+        if (auto* map = binding->PrototypeBinding()->GetServoStyleRuleMap()) {
           maps.AppendElement(map);
         }
       }
       // Note that we intentionally don't cut off here, unlike when we
       // do styling, because even if style rules from parent binding
       // do not apply to the element directly in those cases, their
       // rules may still show up in the list we get above due to the
       // inheritance in cascading.
--- a/layout/inspector/ServoStyleRuleMap.cpp
+++ b/layout/inspector/ServoStyleRuleMap.cpp
@@ -13,40 +13,42 @@
 #include "mozilla/ServoStyleSet.h"
 #include "mozilla/ServoImportRule.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "nsDocument.h"
 #include "nsStyleSheetService.h"
 
 namespace mozilla {
 
-ServoStyleRuleMap::ServoStyleRuleMap(ServoStyleSet* aStyleSet)
-  : mStyleSet(aStyleSet)
-{
-}
-
-ServoStyleRuleMap::~ServoStyleRuleMap()
-{
-}
-
 void
-ServoStyleRuleMap::EnsureTable()
+ServoStyleRuleMap::EnsureTable(ServoStyleSet& aStyleSet)
 {
   if (!IsEmpty()) {
     return;
   }
-  mStyleSet->EnumerateStyleSheetArrays(
+  aStyleSet.EnumerateStyleSheetArrays(
     [this](const nsTArray<RefPtr<ServoStyleSheet>>& aArray) {
       for (auto& sheet : aArray) {
         FillTableFromStyleSheet(*sheet);
       }
     });
 }
 
 void
+ServoStyleRuleMap::EnsureTable(nsXBLPrototypeResources& aXBLResources)
+{
+  if (!IsEmpty() || !aXBLResources.GetServoStyles()) {
+    return;
+  }
+  for (auto index : IntegerRange(aXBLResources.SheetCount())) {
+    FillTableFromStyleSheet(*aXBLResources.StyleSheetAt(index)->AsServo());
+  }
+}
+
+void
 ServoStyleRuleMap::SheetAdded(ServoStyleSheet& aStyleSheet)
 {
   if (!IsEmpty()) {
     FillTableFromStyleSheet(aStyleSheet);
   }
 }
 
 void
--- a/layout/inspector/ServoStyleRuleMap.h
+++ b/layout/inspector/ServoStyleRuleMap.h
@@ -7,55 +7,57 @@
 #ifndef mozilla_ServoStyleRuleMap_h
 #define mozilla_ServoStyleRuleMap_h
 
 #include "mozilla/ServoStyleRule.h"
 
 #include "nsDataHashtable.h"
 
 struct RawServoStyleRule;
+class nsXBLPrototypeResources;
 
 namespace mozilla {
 class ServoCSSRuleList;
 class ServoStyleSet;
 namespace css {
 class Rule;
 } // namespace css
 
 class ServoStyleRuleMap
 {
 public:
-  explicit ServoStyleRuleMap(ServoStyleSet* aStyleSet);
+  ServoStyleRuleMap() = default;
 
-  void EnsureTable();
-  ServoStyleRule* Lookup(const RawServoStyleRule* aRawRule) const {
+  void EnsureTable(ServoStyleSet&);
+  void EnsureTable(nsXBLPrototypeResources&);
+  ServoStyleRule* Lookup(const RawServoStyleRule* aRawRule) const
+  {
     return mTable.Get(aRawRule);
   }
 
-  void SheetAdded(ServoStyleSheet& aStyleSheet);
-  void SheetRemoved(ServoStyleSheet& aStyleSheet);
+  void SheetAdded(ServoStyleSheet&);
+  void SheetRemoved(ServoStyleSheet&);
 
   void RuleAdded(ServoStyleSheet& aStyleSheet, css::Rule&);
-  void RuleRemoved(ServoStyleSheet& aStyleSheet, css::Rule& aStyleRule);
+  void RuleRemoved(ServoStyleSheet& aStyleSheet, css::Rule&);
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
-  ~ServoStyleRuleMap();
+  ~ServoStyleRuleMap() = default;
 
 private:
   // Since we would never have a document which contains no style rule,
   // we use IsEmpty as an indication whether we need to walk through
   // all stylesheets to fill the table.
   bool IsEmpty() const { return mTable.Count() == 0; }
 
   void FillTableFromRule(css::Rule& aRule);
   void FillTableFromRuleList(ServoCSSRuleList& aRuleList);
   void FillTableFromStyleSheet(ServoStyleSheet& aSheet);
 
   typedef nsDataHashtable<nsPtrHashKey<const RawServoStyleRule>,
                           WeakPtr<ServoStyleRule>> Hashtable;
   Hashtable mTable;
-  ServoStyleSet* mStyleSet;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ServoStyleRuleMap_h
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -38,17 +38,18 @@ SERVO_BINDING_FUNC(Servo_Element_IsDispl
                    bool,
                    RawGeckoElementBorrowed element)
 SERVO_BINDING_FUNC(Servo_Element_IsPrimaryStyleReusedViaRuleNode,
                    bool,
                    RawGeckoElementBorrowed element)
 SERVO_BINDING_FUNC(Servo_InvalidateStyleForDocStateChanges,
                    void,
                    RawGeckoElementBorrowed root,
-                   const nsTArray<RawServoStyleSetBorrowed>* sets,
+                   RawServoStyleSetBorrowed doc_styles,
+                   const nsTArray<RawServoAuthorStylesBorrowed>* non_document_styles,
                    uint64_t aStatesChanged)
 
 // Styleset and Stylesheet management
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes,
                    RawServoStyleSheetContentsStrong,
                    mozilla::css::Loader* loader,
                    mozilla::ServoStyleSheet* gecko_stylesheet,
                    const uint8_t* data,
@@ -78,23 +79,24 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_GetS
 // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetOrigin, uint8_t,
                    RawServoStyleSheetContentsBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSet*, RawGeckoPresContextOwned pres_context)
 SERVO_BINDING_FUNC(Servo_StyleSet_RebuildCachedData, void,
                    RawServoStyleSetBorrowed set)
+
 // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
 SERVO_BINDING_FUNC(Servo_StyleSet_MediumFeaturesChanged,
                    MediumFeaturesChangedResult,
                    RawServoStyleSetBorrowed document_set,
-                   const nsTArray<mozilla::ServoStyleSet*>* non_document_sets,
+                   nsTArray<RawServoAuthorStylesBorrowed>* non_document_sets,
                    bool may_affect_default_style)
 // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
 // work as return values with the Linux 32-bit ABI at the moment because
 // they wrap the value in a struct.
 SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
 SERVO_BINDING_FUNC(Servo_StyleSet_CompatModeChanged, void,
                    RawServoStyleSetBorrowed raw_data)
 SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void,
@@ -168,16 +170,30 @@ SERVO_BINDING_FUNC(Servo_StyleSet_AddSiz
                    mozilla::MallocSizeOf malloc_size_of,
                    mozilla::MallocSizeOf malloc_enclosing_size_of,
                    mozilla::ServoStyleSetSizes* sizes,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_UACache_AddSizeOf, void,
                    mozilla::MallocSizeOf malloc_size_of,
                    mozilla::MallocSizeOf malloc_enclosing_size_of,
                    mozilla::ServoStyleSetSizes* sizes)
+
+// AuthorStyles
+SERVO_BINDING_FUNC(Servo_AuthorStyles_Create, RawServoAuthorStyles*)
+// TODO(emilio): This will need to take an optional master style set to
+// implement invalidation for Shadow DOM.
+SERVO_BINDING_FUNC(Servo_AuthorStyles_AppendStyleSheet, void,
+                   RawServoAuthorStylesBorrowedMut self,
+                   const mozilla::ServoStyleSheet* gecko_sheet)
+// TODO(emilio): This will need to take an element to implement invalidation for
+// Shadow DOM.
+SERVO_BINDING_FUNC(Servo_AuthorStyles_Flush, void,
+                   RawServoAuthorStylesBorrowedMut self,
+                   RawServoStyleSetBorrowed document_styles)
+
 SERVO_BINDING_FUNC(Servo_StyleContext_AddRef, void, ServoStyleContextBorrowed ctx);
 SERVO_BINDING_FUNC(Servo_StyleContext_Release, void, ServoStyleContextBorrowed ctx);
 
 SERVO_BINDING_FUNC(Servo_StyleSet_MightHaveAttributeDependency, bool,
                    RawServoStyleSetBorrowed set,
                    RawGeckoElementBorrowed element,
                    nsAtom* local_name)
 SERVO_BINDING_FUNC(Servo_StyleSet_HasStateDependency, bool,
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -10,16 +10,17 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/ServoTypes.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/gfx/Types.h"
 #include "nsCSSPropertyID.h"
 #include "nsStyleAutoArray.h"
 #include "nsTArray.h"
 
+struct RawServoAuthorStyles;
 struct RawServoStyleSet;
 struct RawServoSelectorList;
 struct RawServoSourceSizeList;
 struct RawServoAnimationValueMap;
 struct RustString;
 
 #define SERVO_ARC_TYPE(name_, type_) struct type_;
 #include "mozilla/ServoArcTypeList.h"
@@ -130,17 +131,18 @@ struct MOZ_MUST_USE_TYPE ServoStyleConte
 #define DECL_NULLABLE_OWNED_REF_TYPE_FOR(type_)    \
   typedef type_* type_##OwnedOrNull;               \
   DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_)       \
   DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
 
 // This is a reference to a reference of RawServoDeclarationBlock, which
 // corresponds to Option<&Arc<RawServoDeclarationBlock>> in Servo side.
 DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoDeclarationBlockStrong)
-
+DECL_OWNED_REF_TYPE_FOR(RawServoAuthorStyles)
+DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoAuthorStyles)
 DECL_OWNED_REF_TYPE_FOR(RawServoStyleSet)
 DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoStyleSet)
 DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
 DECL_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
 DECL_OWNED_REF_TYPE_FOR(ServoElementSnapshot)
 DECL_OWNED_REF_TYPE_FOR(RawServoAnimationValueMap)
 
 // We don't use BorrowedMut because the nodes may alias
@@ -223,14 +225,15 @@ DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawS
     void operator()(type_* aPtr) const                      \
     {                                                       \
       Servo_##name_##_Drop(aPtr);                           \
     }                                                       \
   };                                                        \
   }
 
 DEFINE_BOXED_TYPE(StyleSet, RawServoStyleSet);
+DEFINE_BOXED_TYPE(AuthorStyles, RawServoAuthorStyles);
 DEFINE_BOXED_TYPE(SelectorList, RawServoSelectorList);
 DEFINE_BOXED_TYPE(SourceSizeList, RawServoSourceSizeList);
 
 #undef DEFINE_BOXED_TYPE
 
 #endif // mozilla_ServoBindingTypes_h
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2429,21 +2429,20 @@ Gecko_GetBindingParent(RawGeckoElementBo
 }
 
 RawGeckoXBLBindingBorrowedOrNull
 Gecko_GetXBLBinding(RawGeckoElementBorrowed aElement)
 {
   return aElement->GetXBLBinding();
 }
 
-RawServoStyleSetBorrowedOrNull
-Gecko_XBLBinding_GetRawServoStyleSet(RawGeckoXBLBindingBorrowed aXBLBinding)
+RawServoAuthorStylesBorrowedOrNull
+Gecko_XBLBinding_GetRawServoStyles(RawGeckoXBLBindingBorrowed aXBLBinding)
 {
-  const ServoStyleSet* set = aXBLBinding->GetServoStyleSet();
-  return set ? set->RawSet() : nullptr;
+  return aXBLBinding->GetServoStyles();
 }
 
 bool
 Gecko_XBLBinding_InheritsStyle(RawGeckoXBLBindingBorrowed aXBLBinding)
 {
   return aXBLBinding->InheritsStyle();
 }
 
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -602,17 +602,17 @@ void Gecko_nsStyleFont_PrefillDefaultFor
                                                 uint8_t generic_id);
 void Gecko_nsStyleFont_FixupMinFontSize(nsStyleFont* font,
                                         RawGeckoPresContextBorrowed pres_context);
 FontSizePrefs Gecko_GetBaseSize(nsAtom* lang);
 
 // XBL related functions.
 RawGeckoElementBorrowedOrNull Gecko_GetBindingParent(RawGeckoElementBorrowed aElement);
 RawGeckoXBLBindingBorrowedOrNull Gecko_GetXBLBinding(RawGeckoElementBorrowed aElement);
-RawServoStyleSetBorrowedOrNull Gecko_XBLBinding_GetRawServoStyleSet(RawGeckoXBLBindingBorrowed aXBLBinding);
+RawServoAuthorStylesBorrowedOrNull Gecko_XBLBinding_GetRawServoStyles(RawGeckoXBLBindingBorrowed aXBLBinding);
 bool Gecko_XBLBinding_InheritsStyle(RawGeckoXBLBindingBorrowed aXBLBinding);
 
 struct GeckoFontMetrics
 {
   nscoord mChSize;
   nscoord mXSize;
 };
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -465,17 +465,16 @@ structs-types = [
     "mozilla::css::ErrorReporter",
     "mozilla::css::ImageValue",
     "mozilla::css::URLValue",
     "mozilla::css::URLValueData",
     "mozilla::dom::CallerType",
     "mozilla::AnonymousCounterStyle",
     "mozilla::AtomArray",
     "mozilla::MallocSizeOf",
-    "mozilla::ServoStyleSet",
     "mozilla::OriginFlags",
     "mozilla::UniquePtr",
     "ServoRawOffsetArc",
     "nsIContent",
     "nsIDocument",
     "nsIDocument_DocumentTheme",
     "nsSimpleContentList",
     "MediumFeaturesChangedResult",
@@ -614,16 +613,17 @@ structs-types = [
     "FontFamilyName",
     "mozilla::SharedFontList",
 ]
 array-types = [
     { cpp-type = "uintptr_t", rust-type = "usize" },
 ]
 servo-owned-types = [
     { name = "RawServoStyleSet", opaque = true },
+    { name = "RawServoAuthorStyles", opaque = true },
     { name = "RawServoSelectorList", opaque = false },
     { name = "RawServoSourceSizeList", opaque = false },
     { name = "ServoElementSnapshot", opaque = false },
     { name = "RawServoAnimationValueMap", opaque = true },
 ]
 servo-immutable-borrow-types = [
     "RawGeckoNode",
     "RawGeckoElement",
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -227,30 +227,29 @@ ServoStyleSet::InvalidateStyleForDocumen
   if (!root) {
     return;
   }
 
   // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree
   // for XBL sheets / shadow DOM. Consider just enumerating bound content
   // instead and run invalidation individually, passing mRawSet for the UA /
   // User sheets.
-  AutoTArray<RawServoStyleSetBorrowed, 20> styleSets;
-  styleSets.AppendElement(mRawSet.get());
+  AutoTArray<RawServoAuthorStylesBorrowed, 20> xblStyles;
   // FIXME(emilio): When bug 1425759 is fixed we need to enumerate ShadowRoots
   // too.
   mDocument->BindingManager()->EnumerateBoundContentBindings(
     [&](nsXBLBinding* aBinding) {
-      if (ServoStyleSet* set = aBinding->PrototypeBinding()->GetServoStyleSet()) {
-        styleSets.AppendElement(set->RawSet());
+      if (auto* authorStyles = aBinding->PrototypeBinding()->GetServoStyles()) {
+        xblStyles.AppendElement(authorStyles);
       }
       return true;
     });
 
   Servo_InvalidateStyleForDocStateChanges(
-    root, &styleSets, aStatesChanged.ServoValue());
+    root, mRawSet.get(), &xblStyles, aStatesChanged.ServoValue());
 }
 
 static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
   // Zoom changes change the meaning of em units.
   MediaFeatureChangeReason::ZoomChange |
   // Changes the meaning of em units, depending on which one is the actual
   // min-font-size.
   MediaFeatureChangeReason::MinFontSizeChange |
@@ -258,35 +257,35 @@ static const MediaFeatureChangeReason kM
   // structs (Border, Outline, Column) store for clamping. We should arguably
   // not do that, maybe doing it on layout directly, to try to avoid relying on
   // the pres context (bug 1418159).
   MediaFeatureChangeReason::ResolutionChange;
 
 nsRestyleHint
 ServoStyleSet::MediumFeaturesChanged(MediaFeatureChangeReason aReason)
 {
-  AutoTArray<ServoStyleSet*, 20> nonDocumentStyleSets;
+  AutoTArray<RawServoAuthorStylesBorrowed, 20> nonDocumentStyles;
   // FIXME(emilio): When bug 1425759 is fixed we need to enumerate ShadowRoots
   // too.
   //
   // FIXME(emilio): This is broken for XBL. See bug 1406875.
   mDocument->BindingManager()->EnumerateBoundContentBindings(
     [&](nsXBLBinding* aBinding) {
-      if (ServoStyleSet* set = aBinding->PrototypeBinding()->GetServoStyleSet()) {
-        nonDocumentStyleSets.AppendElement(set);
+      if (auto* authorStyles = aBinding->PrototypeBinding()->GetServoStyles()) {
+        nonDocumentStyles.AppendElement(authorStyles);
       }
       return true;
     });
 
   bool mayAffectDefaultStyle =
     bool(aReason & kMediaFeaturesAffectingDefaultStyle);
 
   const MediumFeaturesChangedResult result =
     Servo_StyleSet_MediumFeaturesChanged(
-      mRawSet.get(), &nonDocumentStyleSets, mayAffectDefaultStyle);
+      mRawSet.get(), &nonDocumentStyles, mayAffectDefaultStyle);
 
   const bool rulesChanged =
     result.mAffectsDocumentRules || result.mAffectsNonDocumentRules;
 
   if (result.mAffectsDocumentRules) {
     SetStylistStyleSheetsDirty();
   }
 
@@ -1456,20 +1455,23 @@ ServoStyleSet::UpdateStylist()
       snapshots = &pc->RestyleManager()->AsServo()->Snapshots();
     }
     Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root, snapshots);
   }
 
   if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) {
     MOZ_ASSERT(IsMaster(), "Only master styleset can mark XBL stylesets dirty!");
     MOZ_ASSERT(GetPresContext(), "How did they get dirty?");
-    // NOTE(emilio): This right now rebuilds the stylist in the prototype
-    // binding. That is fine, and if we wanted to be more incremental, which we
-    // probably should, we need to move away from using a StyleSet for XBL.
-    mDocument->BindingManager()->UpdateBoundContentBindingsForServo(GetPresContext());
+    mDocument->BindingManager()->EnumerateBoundContentBindings(
+      [&](nsXBLBinding* aBinding) {
+        if (auto* authorStyles = aBinding->PrototypeBinding()->GetServoStyles()) {
+          Servo_AuthorStyles_Flush(authorStyles, mRawSet.get());
+        }
+        return true;
+      });
   }
 
   mStylistState = StylistState::NotDirty;
 }
 
 void
 ServoStyleSet::MaybeGCRuleTree()
 {
@@ -1563,18 +1565,19 @@ ServoStyleSet::RunPostTraversalTasks()
     task.Run();
   }
 }
 
 ServoStyleRuleMap*
 ServoStyleSet::StyleRuleMap()
 {
   if (!mStyleRuleMap) {
-    mStyleRuleMap = MakeUnique<ServoStyleRuleMap>(this);
+    mStyleRuleMap = MakeUnique<ServoStyleRuleMap>();
   }
+  mStyleRuleMap->EnsureTable(*this);
   return mStyleRuleMap.get();
 }
 
 bool
 ServoStyleSet::MightHaveAttributeDependency(const Element& aElement,
                                             nsAtom* aAttribute) const
 {
   return Servo_StyleSet_MightHaveAttributeDependency(
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -113,18 +113,18 @@ public:
     dom::CSSImportRule* aCloneOwnerRule,
     nsIDocument* aCloneDocument,
     nsINode* aCloneOwningNode) const final override;
 
   // nsICSSLoaderObserver interface
   NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate,
                               nsresult aStatus) final override;
 
-  // Internal GetCssRules method which do not have security check and
-  // completelness check.
+  // Internal GetCssRules methods which do not have security check and
+  // completeness check.
   ServoCSSRuleList* GetCssRulesInternal();
 
   // Returns the stylesheet's Servo origin as an OriginFlags value.
   OriginFlags GetOrigin();
 
 protected:
   virtual ~ServoStyleSheet();
 
new file mode 100644
--- /dev/null
+++ b/servo/components/style/author_styles.rs
@@ -0,0 +1,87 @@
+/* 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/. */
+
+//! A set of author stylesheets and their computed representation, such as the
+//! ones used for ShadowRoot and XBL.
+
+use context::QuirksMode;
+use dom::TElement;
+#[cfg(feature = "gecko")]
+use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI};
+use invalidation::media_queries::ToMediaListKey;
+use media_queries::Device;
+use shared_lock::SharedRwLockReadGuard;
+use stylesheet_set::AuthorStylesheetSet;
+use stylesheets::StylesheetInDocument;
+use stylist::CascadeData;
+
+
+/// A set of author stylesheets and their computed representation, such as the
+/// ones used for ShadowRoot and XBL.
+pub struct AuthorStyles<S>
+where
+    S: StylesheetInDocument + PartialEq + 'static,
+{
+    /// The sheet collection, which holds the sheet pointers, the invalidations,
+    /// and all that stuff.
+    pub stylesheets: AuthorStylesheetSet<S>,
+    /// The actual cascade data computed from the stylesheets.
+    pub data: CascadeData,
+    /// The quirks mode of the last stylesheet flush, used because XBL sucks and
+    /// we should really fix it, see bug 1406875.
+    pub quirks_mode: QuirksMode,
+}
+
+impl<S> AuthorStyles<S>
+where
+    S: StylesheetInDocument + PartialEq + 'static,
+{
+    /// Create an empty AuthorStyles.
+    #[inline]
+    pub fn new() -> Self {
+        Self {
+            stylesheets: AuthorStylesheetSet::new(),
+            data: CascadeData::new(),
+            quirks_mode: QuirksMode::NoQuirks,
+        }
+    }
+
+    /// Flush the pending sheet changes, updating `data` as appropriate.
+    ///
+    /// TODO(emilio): Need a host element and a snapshot map to do invalidation
+    /// properly.
+    #[inline]
+    pub fn flush<E>(
+        &mut self,
+        device: &Device,
+        quirks_mode: QuirksMode,
+        guard: &SharedRwLockReadGuard,
+    )
+    where
+        E: TElement,
+        S: ToMediaListKey,
+    {
+        let flusher = self.stylesheets.flush::<E>(
+            /* host = */ None,
+            /* snapshot_map = */ None,
+        );
+
+        // Ignore OOM.
+        let _ = self.data.rebuild(
+            device,
+            quirks_mode,
+            flusher.sheets,
+            guard,
+        );
+    }
+}
+
+#[cfg(feature = "gecko")]
+unsafe impl HasFFI for AuthorStyles<::gecko::data::GeckoStyleSheet> {
+    type FFIType = ::gecko_bindings::bindings::RawServoAuthorStyles;
+}
+#[cfg(feature = "gecko")]
+unsafe impl HasSimpleFFI for AuthorStyles<::gecko::data::GeckoStyleSheet> {}
+#[cfg(feature = "gecko")]
+unsafe impl HasBoxFFI for AuthorStyles<::gecko::data::GeckoStyleSheet> {}
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -749,29 +749,29 @@ pub trait TElement
     }
 
     /// Implements Gecko's `nsBindingManager::WalkRules`.
     ///
     /// Returns whether to cut off the inheritance.
     fn each_xbl_cascade_data<'a, F>(&self, _: F) -> bool
     where
         Self: 'a,
-        F: FnMut(AtomicRef<'a, CascadeData>, QuirksMode),
+        F: FnMut(&'a CascadeData, QuirksMode),
     {
         false
     }
 
     /// Executes the callback for each applicable style rule data which isn't
     /// the main document's data (which stores UA / author rules).
     ///
     /// Returns whether normal document author rules should apply.
     fn each_applicable_non_document_style_rule_data<'a, F>(&self, mut f: F) -> bool
     where
         Self: 'a,
-        F: FnMut(AtomicRef<'a, CascadeData>, QuirksMode),
+        F: FnMut(&'a CascadeData, QuirksMode),
     {
         let cut_off_inheritance = self.each_xbl_cascade_data(&mut f);
 
         let mut current = self.assigned_slot();
         while let Some(slot) = current {
             slot.each_xbl_cascade_data(&mut f);
             current = slot.assigned_slot();
         }
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -12,23 +12,24 @@
 //!
 //! This theoretically should live in its own crate, but now it lives in the
 //! style system it's kind of pointless in the Stylo case, and only Servo forces
 //! the separation between the style system implementation and everything else.
 
 use CaseSensitivityExt;
 use app_units::Au;
 use applicable_declarations::ApplicableDeclarationBlock;
-use atomic_refcell::{AtomicRefCell, AtomicRef, AtomicRefMut};
+use atomic_refcell::{AtomicRefCell, AtomicRefMut};
+use author_styles::AuthorStyles;
 use context::{QuirksMode, SharedStyleContext, PostAnimationTasks, UpdateAnimationsTasks};
 use data::ElementData;
 use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TDocument, TNode};
 use element_state::{ElementState, DocumentState};
 use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
-use gecko::data::PerDocumentStyleData;
+use gecko::data::GeckoStyleSheet;
 use gecko::global_style_data::GLOBAL_STYLE_DATA;
 use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
 use gecko::snapshot_helpers;
 use gecko_bindings::bindings;
 use gecko_bindings::bindings::{Gecko_ConstructStyleChildrenIterator, Gecko_DestroyStyleChildrenIterator};
 use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme};
 use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild};
 use gecko_bindings::bindings::{Gecko_IsRootElement, Gecko_MatchesElement};
@@ -426,30 +427,29 @@ impl<'lb> GeckoXBLBinding<'lb> {
                 return Some(binding);
             }
             binding = binding.base_binding()?;
         }
     }
 
     fn each_xbl_cascade_data<F>(&self, f: &mut F)
     where
-        F: FnMut(AtomicRef<'lb, CascadeData>, QuirksMode),
+        F: FnMut(&'lb CascadeData, QuirksMode),
     {
         if let Some(base) = self.base_binding() {
             base.each_xbl_cascade_data(f);
         }
 
-        let raw_data = unsafe {
-            bindings::Gecko_XBLBinding_GetRawServoStyleSet(self.0)
+        let data = unsafe {
+            bindings::Gecko_XBLBinding_GetRawServoStyles(self.0)
         };
 
-        if let Some(raw_data) = raw_data {
-            let data = PerDocumentStyleData::from_ffi(&*raw_data).borrow();
-            let quirks_mode = data.stylist.quirks_mode();
-            f(AtomicRef::map(data, |d| d.stylist.author_cascade_data()), quirks_mode);
+        if let Some(data) = data {
+            let data: &'lb _ = AuthorStyles::<GeckoStyleSheet>::from_ffi(data);
+            f(&data.data, data.quirks_mode)
         }
     }
 }
 
 /// A simple wrapper over a non-null Gecko `Element` pointer.
 #[derive(Clone, Copy)]
 pub struct GeckoElement<'le>(pub &'le RawGeckoElement);
 
@@ -1373,17 +1373,17 @@ impl<'le> TElement for GeckoElement<'le>
 
     fn has_css_transitions(&self) -> bool {
         self.may_have_animations() && unsafe { Gecko_ElementHasCSSTransitions(self.0) }
     }
 
     fn each_xbl_cascade_data<'a, F>(&self, mut f: F) -> bool
     where
         'le: 'a,
-        F: FnMut(AtomicRef<'a, CascadeData>, QuirksMode),
+        F: FnMut(&'a CascadeData, QuirksMode),
     {
         // Walk the binding scope chain, starting with the binding attached to
         // our content, up till we run out of scopes or we get cut off.
         //
         // If we are a NAC pseudo-element, we want to get rules from our
         // rule_hash_target, that is, our originating element.
         let mut current = Some(self.rule_hash_target());
 
--- a/servo/components/style/gecko_bindings/sugar/ns_t_array.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_t_array.rs
@@ -31,16 +31,17 @@ impl<T> DerefMut for nsTArray<T> {
 }
 
 impl<T> nsTArray<T> {
     #[inline]
     fn header<'a>(&'a self) -> &'a nsTArrayHeader {
         debug_assert!(!self.mBuffer.is_null());
         unsafe { mem::transmute(self.mBuffer) }
     }
+
     // unsafe, since header may be in shared static or something
     unsafe fn header_mut<'a>(&'a mut self) -> &'a mut nsTArrayHeader {
         debug_assert!(!self.mBuffer.is_null());
 
         mem::transmute(self.mBuffer)
     }
 
     #[inline]
--- a/servo/components/style/invalidation/element/state_and_attributes.rs
+++ b/servo/components/style/invalidation/element/state_and_attributes.rs
@@ -1,17 +1,16 @@
 /* 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/. */
 
 //! An invalidation processor for style changes due to state and attribute
 //! changes.
 
 use Atom;
-use atomic_refcell::AtomicRef;
 use context::{QuirksMode, SharedStyleContext};
 use data::ElementData;
 use dom::TElement;
 use element_state::ElementState;
 use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper};
 use invalidation::element::invalidation_map::*;
 use invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector};
 use invalidation::element::invalidator::{Invalidation, InvalidationProcessor};
@@ -52,28 +51,28 @@ where
     sibling_invalidations: &'a mut InvalidationVector<'selectors>,
     invalidates_self: bool,
 }
 
 /// An invalidation processor for style changes due to state and attribute
 /// changes.
 pub struct StateAndAttrInvalidationProcessor<'a, 'b: 'a, E: TElement> {
     shared_context: &'a SharedStyleContext<'b>,
-    shadow_rule_datas: &'a [(AtomicRef<'b, CascadeData>, QuirksMode)],
+    shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode)],
     cut_off_inheritance: bool,
     element: E,
     data: &'a mut ElementData,
     matching_context: MatchingContext<'a, E::Impl>,
 }
 
 impl<'a, 'b: 'a, E: TElement> StateAndAttrInvalidationProcessor<'a, 'b, E> {
     /// Creates a new StateAndAttrInvalidationProcessor.
     pub fn new(
         shared_context: &'a SharedStyleContext<'b>,
-        shadow_rule_datas: &'a [(AtomicRef<'b, CascadeData>, QuirksMode)],
+        shadow_rule_datas: &'a [(&'b CascadeData, QuirksMode)],
         cut_off_inheritance: bool,
         element: E,
         data: &'a mut ElementData,
         nth_index_cache: &'a mut NthIndexCache,
     ) -> Self {
         let matching_context = MatchingContext::new_for_visited(
             MatchingMode::Normal,
             None,
--- a/servo/components/style/lib.rs
+++ b/servo/components/style/lib.rs
@@ -82,16 +82,17 @@ extern crate void;
 
 #[macro_use]
 mod macros;
 
 #[cfg(feature = "servo")] pub mod animation;
 pub mod applicable_declarations;
 #[allow(missing_docs)] // TODO.
 #[cfg(feature = "servo")] pub mod attr;
+pub mod author_styles;
 pub mod bezier;
 pub mod bloom;
 pub mod context;
 pub mod counter_style;
 pub mod custom_properties;
 pub mod data;
 pub mod dom;
 pub mod dom_apis;
--- a/servo/components/style/stylesheet_set.rs
+++ b/servo/components/style/stylesheet_set.rs
@@ -578,26 +578,51 @@ where
     /// Whether any sheet invalidation matched.
     pub had_invalidations: bool,
 }
 
 impl<S> AuthorStylesheetSet<S>
 where
     S: StylesheetInDocument + PartialEq + 'static,
 {
+    /// Create a new empty AuthorStylesheetSet.
+    #[inline]
+    pub fn new() -> Self {
+        Self {
+            collection: Default::default(),
+            invalidations: StylesheetInvalidationSet::new(),
+        }
+    }
+
+    /// Whether anything has changed since the last time this was flushed.
+    pub fn dirty(&self) -> bool {
+        self.collection.dirty
+    }
+
     fn collection_for(
         &mut self,
         _sheet: &S,
         _guard: &SharedRwLockReadGuard,
     ) -> &mut SheetCollection<S> {
         &mut self.collection
     }
 
     sheet_set_methods!("AuthorStylesheetSet");
 
+    /// Iterate over the list of stylesheets.
+    pub fn iter(&self) -> StylesheetCollectionIterator<S> {
+        self.collection.iter()
+    }
+
+    /// Mark the sheet set dirty, as appropriate.
+    pub fn force_dirty(&mut self) {
+        self.invalidations.invalidate_fully();
+        self.collection.set_data_validity_at_least(DataValidity::FullyInvalid);
+    }
+
     /// Flush the stylesheets for this author set.
     ///
     /// `host` is the root of the affected subtree, like the shadow host, for
     /// example.
     pub fn flush<E>(
         &mut self,
         host: Option<E>,
         snapshots: Option<&SnapshotMap>,
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -1978,17 +1978,18 @@ pub struct CascadeData {
     /// The total number of selectors.
     num_selectors: usize,
 
     /// The total number of declarations.
     num_declarations: usize,
 }
 
 impl CascadeData {
-    fn new() -> Self {
+    /// Creates an empty `CascadeData`.
+    pub fn new() -> Self {
         Self {
             normal_rules: ElementAndPseudoRules::default(),
             slotted_rules: None,
             invalidation_map: InvalidationMap::new(),
             attribute_dependencies: NonCountingBloomFilter::new(),
             style_attribute_dependency: false,
             state_dependencies: ElementState::empty(),
             document_state_dependencies: DocumentState::empty(),
@@ -2000,17 +2001,17 @@ impl CascadeData {
             rules_source_order: 0,
             num_selectors: 0,
             num_declarations: 0,
         }
     }
 
     /// Rebuild the cascade data from a given SheetCollection, incrementally if
     /// possible.
-    fn rebuild<'a, S>(
+    pub fn rebuild<'a, S>(
         &mut self,
         device: &Device,
         quirks_mode: QuirksMode,
         collection: SheetCollectionFlusher<S>,
         guard: &SharedRwLockReadGuard,
     ) -> Result<(), FailedAllocationError>
     where
         S: StylesheetInDocument + ToMediaListKey + PartialEq + 'static,
@@ -2276,17 +2277,17 @@ impl CascadeData {
             }
         }
 
         Ok(())
     }
 
     /// Returns whether all the media-feature affected values matched before and
     /// match now in the given stylesheet.
-    fn media_feature_affected_matches<S>(
+    pub fn media_feature_affected_matches<S>(
         &self,
         stylesheet: &S,
         guard: &SharedRwLockReadGuard,
         device: &Device,
         quirks_mode: QuirksMode,
     ) -> bool
     where
         S: StylesheetInDocument + ToMediaListKey + 'static,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -12,16 +12,17 @@ use servo_arc::{Arc, ArcBorrow, RawOffse
 use smallvec::SmallVec;
 use std::cell::RefCell;
 use std::env;
 use std::fmt::Write;
 use std::iter;
 use std::mem;
 use std::ptr;
 use style::applicable_declarations::ApplicableDeclarationBlock;
+use style::author_styles::AuthorStyles;
 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
 use style::context::ThreadLocalStyleContext;
 use style::counter_style;
 use style::data::{ElementStyles, self};
 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
 use style::driver;
 use style::element_state::{DocumentState, ElementState};
 use style::error_reporting::{ContextualParseError, NullReporter, ParseErrorReporter};
@@ -46,16 +47,17 @@ use style::gecko_bindings::bindings::{Ra
 use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoPageRule, RawServoPageRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoSelectorListBorrowed, RawServoSelectorListOwned};
 use style::gecko_bindings::bindings::{RawServoSourceSizeListBorrowedOrNull, RawServoSourceSizeListOwned};
 use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetBorrowedOrNull, RawServoStyleSetOwned};
 use style::gecko_bindings::bindings::{RawServoStyleSheetContentsBorrowed, ServoComputedDataBorrowed};
 use style::gecko_bindings::bindings::{RawServoStyleSheetContentsStrong, ServoStyleContextBorrowed};
 use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed};
+use style::gecko_bindings::bindings::{RawServoAuthorStylesBorrowed, RawServoAuthorStylesBorrowedMut, RawServoAuthorStylesOwned};
 use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
 use style::gecko_bindings::bindings::{nsACString, nsAString, nsCSSPropertyIDSetBorrowedMut};
 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
 use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
@@ -1116,19 +1118,79 @@ pub extern "C" fn Servo_StyleSet_AppendS
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let data = &mut *data;
     let guard = global_style_data.shared_lock.read();
     let sheet = unsafe { GeckoStyleSheet::new(sheet) };
     data.stylist.append_stylesheet(sheet, &guard);
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_AuthorStyles_Create() -> *mut AuthorStyles<GeckoStyleSheet> {
+    Box::into_raw(Box::new(AuthorStyles::new()))
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_AuthorStyles_Drop(
+    styles: RawServoAuthorStylesOwned,
+) {
+    let _ = styles.into_box::<AuthorStyles<_>>();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
+    styles: RawServoAuthorStylesBorrowedMut,
+    sheet: *const ServoStyleSheet,
+) {
+    let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
+
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let guard = global_style_data.shared_lock.read();
+    let sheet = GeckoStyleSheet::new(sheet);
+    styles.stylesheets.append_stylesheet(None, sheet, &guard);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_AuthorStyles_Flush(
+    styles: RawServoAuthorStylesBorrowedMut,
+    document_set: RawServoStyleSetBorrowed,
+) {
+    let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
+    // Try to avoid the atomic borrow below if possible.
+    if !styles.stylesheets.dirty() {
+        return;
+    }
+
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let guard = global_style_data.shared_lock.read();
+
+    // NOTE(emilio): We don't actually need to flush the stylist here and ensure
+    // it's up to date.
+    //
+    // In case it isn't we would trigger a rebuild + restyle as needed too.
+    //
+    // We need to ensure the default computed values are up to date though,
+    // because those can influence the result of media query evaluation.
+    let document_data =
+        PerDocumentStyleData::from_ffi(document_set).borrow();
+
+    let stylist = &document_data.stylist;
+
+    // TODO(emilio): This is going to need an element or something to do proper
+    // invalidation in Shadow roots.
+    styles.flush::<GeckoElement>(
+        stylist.device(),
+        stylist.quirks_mode(),
+        &guard,
+    );
+}
+
+#[no_mangle]
 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
     document_set: RawServoStyleSetBorrowed,
-    non_document_sets: *const nsTArray<*mut structs::ServoStyleSet>,
+    non_document_styles: *mut nsTArray<RawServoAuthorStylesBorrowedMut>,
     may_affect_default_style: bool,
 ) -> structs::MediumFeaturesChangedResult {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
 
     // NOTE(emilio): We don't actually need to flush the stylist here and ensure
     // it's up to date.
     //
@@ -1151,37 +1213,30 @@ pub unsafe extern "C" fn Servo_StyleSet_
         );
 
     let affects_document_rules = !origins_in_which_rules_changed.is_empty();
     if affects_document_rules {
         document_data.stylist.force_stylesheet_origins_dirty(origins_in_which_rules_changed);
     }
 
     let mut affects_non_document_rules = false;
-    for non_document_style_set in &**non_document_sets {
-        let non_document_data = &*(**non_document_style_set).mRawSet.mPtr;
-        let non_document_data =
-            mem::transmute::<&structs::RawServoStyleSet, &bindings::RawServoStyleSet>(non_document_data);
-        let mut non_document_data =
-            PerDocumentStyleData::from_ffi(non_document_data).borrow_mut();
-
-        let origins_changed =
-            non_document_data.stylist.media_features_change_changed_style(
-                &guards,
+    for author_styles in &mut **non_document_styles {
+        let author_styles =
+            AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(&mut *author_styles);
+        let affected_style = author_styles.stylesheets.iter().any(|sheet| {
+            !author_styles.data.media_feature_affected_matches(
+                sheet,
+                &guards.author,
                 document_data.stylist.device(),
-            );
-        if !origins_changed.is_empty() {
+                document_data.stylist.quirks_mode(),
+            )
+        });
+        if affected_style {
             affects_non_document_rules = true;
-            // XBL stylesets are rebuilt entirely, so we need to mark them
-            // dirty from here instead of going through the stylist
-            // force_origin_dirty stuff, which would be useless.
-            //
-            // FIXME(emilio, bug 1436059): This is super-hacky, make XBL /
-            // Shadow DOM not use a style set at all.
-            (**non_document_style_set).mStylistState = structs::StylistState_StyleSheetsDirty;
+            author_styles.stylesheets.force_dirty();
         }
     }
 
     let uses_viewport_units =
         document_data.stylist.device().used_viewport_size();
 
     structs::MediumFeaturesChangedResult {
         mAffectsDocumentRules: affects_document_rules,
@@ -4925,29 +4980,35 @@ pub extern "C" fn Servo_ParseCounterStyl
         Ok(name) => name.0.into_addrefed(),
         Err(_) => ptr::null_mut(),
     }
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
     root: RawGeckoElementBorrowed,
-    raw_style_sets: *const nsTArray<RawServoStyleSetBorrowed>,
+    document_style: RawServoStyleSetBorrowed,
+    non_document_styles: *const nsTArray<RawServoAuthorStylesBorrowed>,
     states_changed: u64,
 ) {
     use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
     use style::invalidation::element::invalidator::TreeStyleInvalidator;
 
-    let mut borrows = SmallVec::<[_; 20]>::with_capacity((*raw_style_sets).len());
-    for style_set in &**raw_style_sets {
-        borrows.push(PerDocumentStyleData::from_ffi(*style_set).borrow());
-    }
+    let document_data = PerDocumentStyleData::from_ffi(document_style).borrow();
+
+    let iter =
+        document_data.stylist.iter_origins().map(|(data, _origin)| data)
+        .chain((*non_document_styles).iter().map(|author_styles| {
+            let styles: &_ = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
+            &styles.data
+        }));
+
     let root = GeckoElement(root);
     let mut processor = DocumentStateInvalidationProcessor::new(
-        borrows.iter().flat_map(|b| b.stylist.iter_origins().map(|(data, _origin)| data)),
+        iter,
         DocumentState::from_bits_truncate(states_changed),
         root.as_node().owner_doc().quirks_mode(),
     );
 
     let result = TreeStyleInvalidator::new(
         root,
         /* stack_limit_checker = */ None,
         &mut processor,