Bug 1544535 - Bug 1542263 - Don't keep two list of stylesheets in ServoStyleSet. r=firefox-style-system-reviewers,jwatt
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 19 Apr 2019 04:20:31 +0000
changeset 470170 7b1bfcf749fd4b947b4f9202fe858c12d0bba2ee
parent 470169 141cbcdbcef86709c3419cf1cba5aba72a090f02
child 470171 2099599a5ad519efa9e85f900d6ea51136469001
push id112843
push useraiakab@mozilla.com
push dateFri, 19 Apr 2019 09:50:22 +0000
treeherdermozilla-inbound@c06f27cbfe40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfirefox-style-system-reviewers, jwatt
bugs1544535, 1542263
milestone68.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 1544535 - Bug 1542263 - Don't keep two list of stylesheets in ServoStyleSet. r=firefox-style-system-reviewers,jwatt Just one set of stylesheets is enough. While at it, unify SheetType and Origin. Differential Revision: https://phabricator.services.mozilla.com/D27564
dom/base/Document.cpp
dom/base/Document.h
dom/base/DocumentInlines.h
dom/base/DocumentOrShadowRoot.cpp
layout/base/PresShell.cpp
layout/base/nsIPresShell.h
layout/inspector/InspectorUtils.cpp
layout/inspector/ServoStyleRuleMap.cpp
layout/style/FontFaceSet.cpp
layout/style/FontFaceSet.h
layout/style/ServoBindings.toml
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/ServoTypes.h
layout/style/SheetType.h
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
layout/style/moz.build
layout/style/nsCSSValue.h
layout/style/nsStyleStruct.h
servo/components/style/gecko/conversions.rs
servo/components/style/stylesheet_set.rs
servo/components/style/stylesheets/origin.rs
servo/components/style/stylist.rs
servo/ports/geckolib/cbindgen.toml
servo/ports/geckolib/glue.rs
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -2200,30 +2200,64 @@ already_AddRefed<nsIPrincipal> Document:
         }
       }
     }
   }
   nsCOMPtr<nsIPrincipal> principal(aPrincipal);
   return principal.forget();
 }
 
+size_t Document::FindDocStyleSheetInsertionPoint(const StyleSheet& aSheet) {
+  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
+
+  // lowest index first
+  int32_t newDocIndex = IndexOfSheet(aSheet);
+
+  size_t count = mStyleSet->SheetCount(StyleOrigin::Author);
+  size_t index = 0;
+  for (; index < count; index++) {
+    auto* sheet = mStyleSet->SheetAt(StyleOrigin::Author, index);
+    MOZ_ASSERT(sheet);
+    int32_t sheetDocIndex = IndexOfSheet(*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) {
+      if (sheetService) {
+        auto& authorSheets = *sheetService->AuthorStyleSheets();
+        if (authorSheets.IndexOf(sheet) != authorSheets.NoIndex) {
+          break;
+        }
+      }
+      if (sheet == GetFirstAdditionalAuthorSheet()) {
+        break;
+      }
+    }
+  }
+
+  return index;
+}
+
 void Document::RemoveDocStyleSheetsFromStyleSets() {
   MOZ_ASSERT(mStyleSetFilled);
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
     sheet->ClearAssociatedDocumentOrShadowRoot();
     if (sheet->IsApplicable()) {
       mStyleSet->RemoveDocStyleSheet(sheet);
     }
     // XXX Tell observers?
   }
 }
 
 void Document::RemoveStyleSheetsFromStyleSets(
-    const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType) {
+    const nsTArray<RefPtr<StyleSheet>>& aSheets, StyleOrigin aType) {
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(aSheets)) {
     sheet->ClearAssociatedDocumentOrShadowRoot();
     if (mStyleSetFilled && sheet->IsApplicable()) {
       mStyleSet->RemoveStyleSheet(aType, sheet);
     }
     // XXX Tell observers?
   }
@@ -2233,26 +2267,26 @@ void Document::ResetStylesheetsToURI(nsI
   MOZ_ASSERT(aURI);
 
   if (mStyleSetFilled) {
     // Skip removing style sheets from the style set if we know we haven't
     // filled the style set.  (This allows us to avoid calling
     // GetStyleBackendType() too early.)
     RemoveDocStyleSheetsFromStyleSets();
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet],
-                                   SheetType::Agent);
+                                   StyleOrigin::UserAgent);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet],
-                                   SheetType::User);
+                                   StyleOrigin::User);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet],
-                                   SheetType::Doc);
+                                   StyleOrigin::Author);
 
     if (nsStyleSheetService* sheetService =
             nsStyleSheetService::GetInstance()) {
       RemoveStyleSheetsFromStyleSets(*sheetService->AuthorStyleSheets(),
-                                     SheetType::Doc);
+                                     StyleOrigin::Author);
     }
   }
 
   // Release all the sheets
   mStyleSheets.Clear();
   for (auto& sheets : mAdditionalSheets) {
     sheets.Clear();
   }
@@ -2279,118 +2313,120 @@ void Document::ResetStylesheetsToURI(nsI
     if (mStyleSet->StyleSheetsHaveChanged()) {
       ApplicableStylesChanged();
     }
   }
 }
 
 static void AppendSheetsToStyleSet(ServoStyleSet* aStyleSet,
                                    const nsTArray<RefPtr<StyleSheet>>& aSheets,
-                                   SheetType aType) {
+                                   StyleOrigin aOrigin) {
   for (StyleSheet* sheet : Reversed(aSheets)) {
-    aStyleSet->AppendStyleSheet(aType, sheet);
+    aStyleSet->AppendStyleSheet(aOrigin, sheet);
   }
 }
 
 void Document::FillStyleSetUserAndUASheets() {
   // Make sure this does the same thing as PresShell::Add{User,Agent}Sheet wrt
   // ordering.
 
   // The document will fill in the document sheets when we create the presshell
   auto cache = nsLayoutStylesheetCache::Singleton();
 
   nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
   MOZ_ASSERT(sheetService,
              "should never be creating a StyleSet after the style sheet "
              "service has gone");
 
   for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
-    mStyleSet->AppendStyleSheet(SheetType::User, sheet);
+    mStyleSet->AppendStyleSheet(StyleOrigin::User, sheet);
   }
 
   StyleSheet* sheet = IsInChromeDocShell() ? cache->GetUserChromeSheet()
                                            : cache->GetUserContentSheet();
   if (sheet) {
-    mStyleSet->AppendStyleSheet(SheetType::User, sheet);
-  }
-
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->UASheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::User, sheet);
+  }
+
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->UASheet());
 
   if (MOZ_LIKELY(NodeInfoManager()->MathMLEnabled())) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->MathMLSheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->MathMLSheet());
   }
 
   if (MOZ_LIKELY(NodeInfoManager()->SVGEnabled())) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->SVGSheet());
-  }
-
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->HTMLSheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->SVGSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->HTMLSheet());
 
   if (nsLayoutUtils::ShouldUseNoFramesSheet(this)) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->NoFramesSheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->NoFramesSheet());
   }
 
   if (nsLayoutUtils::ShouldUseNoScriptSheet(this)) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->NoScriptSheet());
-  }
-
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->CounterStylesSheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->NoScriptSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent,
+                              cache->CounterStylesSheet());
 
   // Load the minimal XUL rules for scrollbars and a few other XUL things
   // that non-XUL (typically HTML) documents commonly use.
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->MinimalXULSheet());
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->MinimalXULSheet());
 
   // Only load the full XUL sheet if we'll need it.
   if (LoadsFullXULStyleSheetUpFront()) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->XULSheet());
-  }
-
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->FormsSheet());
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->ScrollbarsSheet());
-  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->PluginProblemSheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->XULSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->FormsSheet());
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->ScrollbarsSheet());
+  mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent,
+                              cache->PluginProblemSheet());
 
   for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, sheet);
   }
 
   MOZ_ASSERT(!mQuirkSheetAdded);
   if (NeedsQuirksSheet()) {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->QuirkSheet());
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, cache->QuirkSheet());
     mQuirkSheetAdded = true;
   }
 }
 
 void Document::FillStyleSet() {
   MOZ_ASSERT(!mStyleSetFilled);
   FillStyleSetUserAndUASheets();
   FillStyleSetDocumentSheets();
   mStyleSetFilled = true;
 }
 
 void Document::FillStyleSetDocumentSheets() {
-  MOZ_ASSERT(mStyleSet->SheetCount(SheetType::Doc) == 0,
+  MOZ_ASSERT(mStyleSet->SheetCount(StyleOrigin::Author) == 0,
              "Style set already has document sheets?");
 
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
     if (sheet->IsApplicable()) {
-      mStyleSet->AddDocStyleSheet(sheet, this);
+      mStyleSet->AddDocStyleSheet(sheet);
     }
   }
 
   nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
   for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
-    mStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
+    mStyleSet->AppendStyleSheet(StyleOrigin::Author, sheet);
   }
 
   AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eAgentSheet],
-                         SheetType::Agent);
+                         StyleOrigin::UserAgent);
   AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eUserSheet],
-                         SheetType::User);
+                         StyleOrigin::User);
   AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eAuthorSheet],
-                         SheetType::Doc);
+                         StyleOrigin::Author);
 }
 
 void Document::CompatibilityModeChanged() {
   MOZ_ASSERT(IsHTMLOrXHTML());
   CSSLoader()->SetCompatibilityMode(mCompatMode);
   mStyleSet->CompatibilityModeChanged();
   if (PresShell* presShell = GetPresShell()) {
     // Selectors may have become case-sensitive / case-insensitive, the stylist
@@ -2402,19 +2438,19 @@ void Document::CompatibilityModeChanged(
     return;
   }
   if (mQuirkSheetAdded == NeedsQuirksSheet()) {
     return;
   }
   auto cache = nsLayoutStylesheetCache::Singleton();
   StyleSheet* sheet = cache->QuirkSheet();
   if (mQuirkSheetAdded) {
-    mStyleSet->RemoveStyleSheet(SheetType::Agent, sheet);
+    mStyleSet->RemoveStyleSheet(StyleOrigin::UserAgent, sheet);
   } else {
-    mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+    mStyleSet->AppendStyleSheet(StyleOrigin::UserAgent, sheet);
   }
   mQuirkSheetAdded = !mQuirkSheetAdded;
   ApplicableStylesChanged();
 }
 
 static void WarnIfSandboxIneffective(nsIDocShell* aDocShell,
                                      uint32_t aSandboxFlags,
                                      nsIChannel* aChannel) {
@@ -4156,17 +4192,17 @@ void Document::RemoveChildNode(nsIConten
   nsINode::RemoveChildNode(aKid, aNotify);
   MOZ_ASSERT(mCachedRootElement != aKid,
              "Stale pointer in mCachedRootElement, after we tried to clear it "
              "(maybe somebody called GetRootElement() too early?)");
 }
 
 void Document::AddStyleSheetToStyleSets(StyleSheet* aSheet) {
   if (mStyleSetFilled) {
-    mStyleSet->AddDocStyleSheet(aSheet, this);
+    mStyleSet->AddDocStyleSheet(aSheet);
     ApplicableStylesChanged();
   }
 }
 
 void Document::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
   mStyleSet->RecordShadowStyleChange(aShadowRoot);
   ApplicableStylesChanged();
 }
@@ -4329,29 +4365,27 @@ void Document::NotifyStyleSheetApplicabl
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
   if (observerService) {
     observerService->NotifyObservers(
         ToSupports(this), "style-sheet-applicable-state-changed", nullptr);
   }
 }
 
-static SheetType ConvertAdditionalSheetType(
+static StyleOrigin ConvertAdditionalSheetType(
     Document::additionalSheetType aType) {
   switch (aType) {
     case Document::eAgentSheet:
-      return SheetType::Agent;
+      return StyleOrigin::UserAgent;
     case Document::eUserSheet:
-      return SheetType::User;
+      return StyleOrigin::User;
     case Document::eAuthorSheet:
-      return SheetType::Doc;
+      return StyleOrigin::Author;
     default:
-      MOZ_ASSERT(false, "wrong type");
-      // we must return something although this should never happen
-      return SheetType::Count;
+      MOZ_CRASH("Wrong sheet type");
   }
 }
 
 static int32_t FindSheet(const nsTArray<RefPtr<StyleSheet>>& aSheets,
                          nsIURI* aSheetURI) {
   for (int32_t i = aSheets.Length() - 1; i >= 0; i--) {
     bool bEqual;
     nsIURI* uri = aSheets[i]->GetSheetURI();
@@ -4407,18 +4441,17 @@ nsresult Document::AddAdditionalStyleShe
                                            StyleSheet* aSheet) {
   if (mAdditionalSheets[aType].Contains(aSheet)) return NS_ERROR_INVALID_ARG;
 
   if (!aSheet->IsApplicable()) return NS_ERROR_INVALID_ARG;
 
   mAdditionalSheets[aType].AppendElement(aSheet);
 
   if (mStyleSetFilled) {
-    SheetType type = ConvertAdditionalSheetType(aType);
-    mStyleSet->AppendStyleSheet(type, aSheet);
+    mStyleSet->AppendStyleSheet(ConvertAdditionalSheetType(aType), aSheet);
     ApplicableStylesChanged();
   }
 
   // Passing false, so documet.styleSheets.length will not be affected by
   // these additional sheets.
   NotifyStyleSheetAdded(aSheet, false);
   return NS_OK;
 }
@@ -4432,18 +4465,18 @@ void Document::RemoveAdditionalStyleShee
   int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI);
   if (i >= 0) {
     RefPtr<StyleSheet> sheetRef = sheets[i];
     sheets.RemoveElementAt(i);
 
     if (!mIsGoingAway) {
       MOZ_ASSERT(sheetRef->IsApplicable());
       if (mStyleSetFilled) {
-        SheetType type = ConvertAdditionalSheetType(aType);
-        mStyleSet->RemoveStyleSheet(type, sheetRef);
+        mStyleSet->RemoveStyleSheet(ConvertAdditionalSheetType(aType),
+                                    sheetRef);
         ApplicableStylesChanged();
       }
     }
 
     // Passing false, so documet.styleSheets.length will not be affected by
     // these additional sheets.
     NotifyStyleSheetRemoved(sheetRef, false);
     sheetRef->ClearAssociatedDocumentOrShadowRoot();
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -1706,27 +1706,20 @@ class Document : public nsINode,
                                    StyleSheet* aSheet);
   void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI);
 
   StyleSheet* GetFirstAdditionalAuthorSheet() {
     return mAdditionalSheets[eAuthorSheet].SafeElementAt(0);
   }
 
   /**
-   * Assuming that aDocSheets is an array of document-level style
-   * sheets for this document, returns the index that aSheet should
-   * be inserted at to maintain document ordering.
-   *
-   * Type T has to cast to StyleSheet*.
-   *
-   * Defined in DocumentInlines.h.
-   */
-  template <typename T>
-  size_t FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
-                                         const StyleSheet& aSheet);
+   * Returns the index that aSheet should be inserted at to maintain document
+   * ordering.
+   */
+  size_t FindDocStyleSheetInsertionPoint(const StyleSheet& aSheet);
 
   /**
    * Get this document's CSSLoader.  This is guaranteed to not return null.
    */
   css::Loader* CSSLoader() const { return mCSSLoader; }
 
   /**
    * Get this document's StyleImageLoader.  This is guaranteed to not return
@@ -3824,17 +3817,17 @@ class Document : public nsINode,
   }
 
   bool GetChildDocumentUseCounter(UseCounter aUseCounter) {
     return mChildDocumentUseCounters[aUseCounter];
   }
 
   void RemoveDocStyleSheetsFromStyleSets();
   void RemoveStyleSheetsFromStyleSets(
-      const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType);
+      const nsTArray<RefPtr<StyleSheet>>& aSheets, StyleOrigin);
   void ResetStylesheetsToURI(nsIURI* aURI);
   void FillStyleSet();
   void FillStyleSetUserAndUASheets();
   void FillStyleSetDocumentSheets();
   void CompatibilityModeChanged();
   bool NeedsQuirksSheet() const {
     // SVG documents never load quirk.css.
     return mCompatMode == eCompatibility_NavQuirks && !IsSVGDocument();
--- a/dom/base/DocumentInlines.h
+++ b/dom/base/DocumentInlines.h
@@ -25,52 +25,16 @@ inline nsPresContext* Document::GetPresC
   PresShell* presShell = GetPresShell();
   return presShell ? presShell->GetPresContext() : nullptr;
 }
 
 inline HTMLBodyElement* Document::GetBodyElement() {
   return static_cast<HTMLBodyElement*>(GetHtmlChildElement(nsGkAtoms::body));
 }
 
-template <typename T>
-size_t Document::FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
-                                                 const StyleSheet& aSheet) {
-  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
-
-  // lowest index first
-  int32_t newDocIndex = IndexOfSheet(aSheet);
-
-  size_t count = aDocSheets.Length();
-  size_t index = 0;
-  for (; index < count; index++) {
-    auto* sheet = static_cast<StyleSheet*>(aDocSheets[index]);
-    MOZ_ASSERT(sheet);
-    int32_t sheetDocIndex = IndexOfSheet(*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) {
-      if (sheetService) {
-        auto& authorSheets = *sheetService->AuthorStyleSheets();
-        if (authorSheets.IndexOf(sheet) != authorSheets.NoIndex) {
-          break;
-        }
-      }
-      if (sheet == GetFirstAdditionalAuthorSheet()) {
-        break;
-      }
-    }
-  }
-
-  return size_t(index);
-}
-
 inline void Document::SetServoRestyleRoot(nsINode* aRoot, uint32_t aDirtyBits) {
   MOZ_ASSERT(aRoot);
 
   MOZ_ASSERT(!mServoRestyleRoot || mServoRestyleRoot == aRoot ||
              nsContentUtils::ContentIsFlattenedTreeDescendantOfForStyle(
                  mServoRestyleRoot, aRoot));
   MOZ_ASSERT(aRoot == aRoot->OwnerDocAsNode() || aRoot->IsElement());
   mServoRestyleRoot = aRoot;
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -600,19 +600,16 @@ void DocumentOrShadowRoot::Traverse(Docu
     }
     // The style set or mServoStyles keep more references to it if the sheet is
     // applicable.
     if (tmp->mKind == Kind::ShadowRoot) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
       cb.NoteXPCOMChild(sheet);
     } else if (tmp->AsNode().AsDocument()->StyleSetFilled()) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
-          cb, "mStyleSet->mStyleSheets[SheetType::Author][i]");
-      cb.NoteXPCOMChild(sheet);
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
           cb, "mStyleSet->mRawSet.stylist.stylesheets.author[i]");
       cb.NoteXPCOMChild(sheet);
     }
   }
   for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
     iter.Get()->Traverse(&cb);
   }
   for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
+#include "MobileViewportManager.h"
 #include <algorithm>
 
 #ifdef XP_WIN
 #  include "winuser.h"
 #endif
 
 #include "gfxContext.h"
 #include "gfxPrefs.h"
@@ -1455,23 +1456,23 @@ void nsIPresShell::UpdatePreferenceStyle
   }
 
   RemovePreferenceStyles();
 
   // NOTE(emilio): This sheet is added as an agent sheet, because we don't want
   // it to be modifiable from devtools and similar, see bugs 1239336 and
   // 1436782. I think it conceptually should be a user sheet, and could be
   // without too much trouble I'd think.
-  StyleSet()->AppendStyleSheet(SheetType::Agent, newPrefSheet);
+  StyleSet()->AppendStyleSheet(StyleOrigin::UserAgent, newPrefSheet);
   mPrefStyleSheet = newPrefSheet;
 }
 
 void nsIPresShell::RemovePreferenceStyles() {
   if (mPrefStyleSheet) {
-    StyleSet()->RemoveStyleSheet(SheetType::Agent, mPrefStyleSheet);
+    StyleSet()->RemoveStyleSheet(StyleOrigin::UserAgent, mPrefStyleSheet);
     mPrefStyleSheet = nullptr;
   }
 }
 
 void nsIPresShell::AddUserSheet(StyleSheet* aSheet) {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
   // ordering. We want this new sheet to come after all the existing stylesheet
   // service sheets (which are at the start), but before other user sheets; see
@@ -1488,52 +1489,52 @@ void nsIPresShell::AddUserSheet(StyleShe
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(userSheets.LastElement() == aSheet);
 
   size_t index = userSheets.Length() - 1;
 
   // Assert that all of userSheets (except for the last, new element) matches up
   // with what's in the style set.
   for (size_t i = 0; i < index; ++i) {
-    MOZ_ASSERT(StyleSet()->StyleSheetAt(SheetType::User, i) == userSheets[i]);
-  }
-
-  if (index == static_cast<size_t>(StyleSet()->SheetCount(SheetType::User))) {
-    StyleSet()->AppendStyleSheet(SheetType::User, aSheet);
+    MOZ_ASSERT(StyleSet()->SheetAt(StyleOrigin::User, i) == userSheets[i]);
+  }
+
+  if (index == static_cast<size_t>(StyleSet()->SheetCount(StyleOrigin::User))) {
+    StyleSet()->AppendStyleSheet(StyleOrigin::User, aSheet);
   } else {
-    StyleSheet* ref = StyleSet()->StyleSheetAt(SheetType::User, index);
-    StyleSet()->InsertStyleSheetBefore(SheetType::User, aSheet, ref);
+    StyleSheet* ref = StyleSet()->SheetAt(StyleOrigin::User, index);
+    StyleSet()->InsertStyleSheetBefore(StyleOrigin::User, aSheet, ref);
   }
 
   mDocument->ApplicableStylesChanged();
 }
 
 void nsIPresShell::AddAgentSheet(StyleSheet* aSheet) {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does
   // wrt ordering.
-  StyleSet()->AppendStyleSheet(SheetType::Agent, aSheet);
+  StyleSet()->AppendStyleSheet(StyleOrigin::UserAgent, aSheet);
   mDocument->ApplicableStylesChanged();
 }
 
 void nsIPresShell::AddAuthorSheet(StyleSheet* aSheet) {
   // Document specific "additional" Author sheets should be stronger than the
   // ones added with the StyleSheetService.
   StyleSheet* firstAuthorSheet = mDocument->GetFirstAdditionalAuthorSheet();
   if (firstAuthorSheet) {
-    StyleSet()->InsertStyleSheetBefore(SheetType::Doc, aSheet,
+    StyleSet()->InsertStyleSheetBefore(StyleOrigin::Author, aSheet,
                                        firstAuthorSheet);
   } else {
-    StyleSet()->AppendStyleSheet(SheetType::Doc, aSheet);
+    StyleSet()->AppendStyleSheet(StyleOrigin::Author, aSheet);
   }
 
   mDocument->ApplicableStylesChanged();
 }
 
-void nsIPresShell::RemoveSheet(SheetType aType, StyleSheet* aSheet) {
-  StyleSet()->RemoveStyleSheet(aType, aSheet);
+void nsIPresShell::RemoveSheet(StyleOrigin aOrigin, StyleSheet* aSheet) {
+  StyleSet()->RemoveStyleSheet(aOrigin, aSheet);
   mDocument->ApplicableStylesChanged();
 }
 
 NS_IMETHODIMP
 PresShell::SetDisplaySelection(int16_t aToggle) {
   RefPtr<nsFrameSelection> frameSelection = mSelection;
   frameSelection->SetDisplaySelection(aToggle);
   return NS_OK;
@@ -8807,41 +8808,44 @@ void PresShell::RespectDisplayportSuppre
 }
 
 bool PresShell::IsDisplayportSuppressed() {
   return sDisplayPortSuppressionRespected && mActiveSuppressDisplayport > 0;
 }
 
 nsresult PresShell::GetAgentStyleSheets(nsTArray<RefPtr<StyleSheet>>& aSheets) {
   aSheets.Clear();
-  int32_t sheetCount = StyleSet()->SheetCount(SheetType::Agent);
+  int32_t sheetCount = StyleSet()->SheetCount(StyleOrigin::UserAgent);
 
   if (!aSheets.SetCapacity(sheetCount, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (int32_t i = 0; i < sheetCount; ++i) {
-    StyleSheet* sheet = StyleSet()->StyleSheetAt(SheetType::Agent, i);
+    StyleSheet* sheet = StyleSet()->SheetAt(StyleOrigin::UserAgent, i);
     aSheets.AppendElement(sheet);
   }
 
   return NS_OK;
 }
 
 nsresult PresShell::SetAgentStyleSheets(
     const nsTArray<RefPtr<StyleSheet>>& aSheets) {
-  return StyleSet()->ReplaceSheets(SheetType::Agent, aSheets);
+  StyleSet()->ReplaceSheets(StyleOrigin::UserAgent, aSheets);
+  return NS_OK;
 }
 
 nsresult PresShell::AddOverrideStyleSheet(StyleSheet* aSheet) {
-  return StyleSet()->AppendStyleSheet(SheetType::Override, aSheet);
+  StyleSet()->AppendStyleSheet(aSheet->GetOrigin(), aSheet);
+  return NS_OK;
 }
 
 nsresult PresShell::RemoveOverrideStyleSheet(StyleSheet* aSheet) {
-  return StyleSet()->RemoveStyleSheet(SheetType::Override, aSheet);
+  StyleSet()->RemoveStyleSheet(aSheet->GetOrigin(), aSheet);
+  return NS_OK;
 }
 
 static void FreezeElement(nsISupports* aSupports, void* /* unused */) {
   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
   if (olc) {
     olc->StopPluginInstance();
   }
 }
@@ -9974,19 +9978,19 @@ void PresShell::ListComputedStyles(FILE*
     nsIFrame* rootElementFrame = rootElement->GetPrimaryFrame();
     if (rootElementFrame) {
       rootElementFrame->Style()->List(out, aIndent);
     }
   }
 }
 
 void PresShell::ListStyleSheets(FILE* out, int32_t aIndent) {
-  int32_t sheetCount = StyleSet()->SheetCount(SheetType::Doc);
+  int32_t sheetCount = StyleSet()->SheetCount(StyleOrigin::Author);
   for (int32_t i = 0; i < sheetCount; ++i) {
-    StyleSet()->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
+    StyleSet()->SheetAt(StyleOrigin::Author, i)->List(out, aIndent);
     fputs("\n", out);
   }
 }
 #endif
 
 //=============================================================
 //=============================================================
 //-- Debug Reflow Counts
@@ -10861,28 +10865,28 @@ void nsIPresShell::SyncWindowProperties(
   nsIFrame* frame = aView->GetFrame();
   if (frame && mPresContext) {
     // CreateReferenceRenderingContext can return nullptr
     RefPtr<gfxContext> rcx(CreateReferenceRenderingContext());
     nsContainerFrame::SyncWindowProperties(mPresContext, frame, aView, rcx, 0);
   }
 }
 
-static SheetType ToSheetType(uint32_t aServiceSheetType) {
+static StyleOrigin ToOrigin(uint32_t aServiceSheetType) {
   switch (aServiceSheetType) {
     case nsIStyleSheetService::AGENT_SHEET:
-      return SheetType::Agent;
+      return StyleOrigin::UserAgent;
       break;
     case nsIStyleSheetService::USER_SHEET:
-      return SheetType::User;
+      return StyleOrigin::User;
       break;
     default:
       MOZ_FALLTHROUGH_ASSERT("unexpected aSheetType value");
     case nsIStyleSheetService::AUTHOR_SHEET:
-      return SheetType::Doc;
+      return StyleOrigin::Author;
   }
 }
 
 nsresult nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(
     uint32_t aSheetType, bool* aRetVal) {
   *aRetVal = false;
   return NS_OK;
 }
@@ -10902,17 +10906,17 @@ void nsIPresShell::NotifyStyleSheetServi
     default:
       MOZ_ASSERT_UNREACHABLE("unexpected aSheetType value");
       break;
   }
 }
 
 void nsIPresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
                                                        uint32_t aSheetType) {
-  RemoveSheet(ToSheetType(aSheetType), aSheet);
+  RemoveSheet(ToOrigin(aSheetType), aSheet);
 }
 
 nsIContent* PresShell::EventHandler::GetOverrideClickTarget(
     WidgetGUIEvent* aGUIEvent, nsIFrame* aFrame) {
   if (aGUIEvent->mMessage != eMouseUp) {
     return nullptr;
   }
 
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -10,16 +10,17 @@
 #define nsIPresShell_h___
 
 #include "mozilla/ArenaObjectID.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/FlushType.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ScrollTypes.h"
 #include "mozilla/ServoStyleSet.h"
+#include "mozilla/ServoStyleConsts.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "FrameMetrics.h"
 #include "GeckoProfiler.h"
 #include "gfxPoint.h"
 #include "nsTHashtable.h"
@@ -1788,17 +1789,17 @@ class nsIPresShell : public nsStubDocume
 
   /**
    * Methods to handle changes to user and UA sheet lists that we get
    * notified about.
    */
   void AddUserSheet(mozilla::StyleSheet*);
   void AddAgentSheet(mozilla::StyleSheet*);
   void AddAuthorSheet(mozilla::StyleSheet*);
-  void RemoveSheet(mozilla::SheetType, mozilla::StyleSheet*);
+  void RemoveSheet(mozilla::StyleOrigin, mozilla::StyleSheet*);
   void RemovePreferenceStyles();
 
   void WillDoReflow();
 
   // This data is stored as a content property (nsGkAtoms::scrolling) on
   // mContentToScrollTo when we have a pending ScrollIntoView.
   struct ScrollIntoViewData {
     ScrollAxis mContentScrollVAxis;
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -60,23 +60,23 @@ void InspectorUtils::GetAllStyleSheets(G
                                        nsTArray<RefPtr<StyleSheet>>& aResult) {
   // Get the agent, then user and finally xbl sheets in the style set.
   PresShell* presShell = aDocument.GetPresShell();
 
   if (presShell) {
     ServoStyleSet* styleSet = presShell->StyleSet();
 
     if (!aDocumentOnly) {
-      SheetType sheetType = SheetType::Agent;
-      for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
-        aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
-      }
-      sheetType = SheetType::User;
-      for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
-        aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
+      const StyleOrigin kOrigins[] = {StyleOrigin::UserAgent,
+                                      StyleOrigin::User};
+      for (const auto origin : kOrigins) {
+        for (size_t i = 0, count = styleSet->SheetCount(origin); i < count;
+             i++) {
+          aResult.AppendElement(styleSet->SheetAt(origin, i));
+        }
       }
     }
 
     AutoTArray<StyleSheet*, 32> xblSheetArray;
     styleSet->AppendAllNonDocumentAuthorSheets(xblSheetArray);
 
     // The XBL stylesheet array will quite often be full of duplicates. Cope:
     //
--- a/layout/inspector/ServoStyleRuleMap.cpp
+++ b/layout/inspector/ServoStyleRuleMap.cpp
@@ -21,22 +21,18 @@
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 void ServoStyleRuleMap::EnsureTable(ServoStyleSet& aStyleSet) {
   if (!IsEmpty()) {
     return;
   }
-  aStyleSet.EnumerateStyleSheetArrays(
-      [this](const nsTArray<RefPtr<StyleSheet>>& aArray) {
-        for (auto& sheet : aArray) {
-          FillTableFromStyleSheet(*sheet);
-        }
-      });
+  aStyleSet.EnumerateStyleSheets(
+      [&](StyleSheet& aSheet) { FillTableFromStyleSheet(aSheet); });
 }
 
 void ServoStyleRuleMap::EnsureTable(nsXBLPrototypeResources& aXBLResources) {
   if (!IsEmpty() || !aXBLResources.GetServoStyles()) {
     return;
   }
   for (auto index : IntegerRange(aXBLResources.SheetCount())) {
     FillTableFromStyleSheet(*aXBLResources.StyleSheetAt(index));
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -448,17 +448,17 @@ void FontFaceSet::Add(FontFace& aFontFac
   for (const FontFaceRecord& rec : mNonRuleFaces) {
     MOZ_ASSERT(rec.mFontFace != &aFontFace,
                "FontFace should not occur in mNonRuleFaces twice");
   }
 #endif
 
   FontFaceRecord* rec = mNonRuleFaces.AppendElement();
   rec->mFontFace = &aFontFace;
-  rec->mSheetType = SheetType::Unknown;  // unused for mNonRuleFaces
+  rec->mOrigin = Nothing();
   rec->mLoadEventShouldFire =
       aFontFace.Status() == FontFaceLoadStatus::Unloaded ||
       aFontFace.Status() == FontFaceLoadStatus::Loading;
 
   mNonRuleFacesDirty = true;
   MarkUserFontSetDirty();
   mHasLoadingFontFacesIsDirty = true;
   CheckLoadingStarted();
@@ -721,17 +721,17 @@ bool FontFaceSet::UpdateRules(const nsTA
     if (!handledRules.EnsureInserted(rule)) {
       // rule was already present in the hashtable
       continue;
     }
     RefPtr<FontFace> f = ruleFaceMap.Get(rule);
     if (!f.get()) {
       f = FontFace::CreateForRule(GetParentObject(), this, rule);
     }
-    InsertRuleFontFace(f, aRules[i].mSheetType, oldRecords, modified);
+    InsertRuleFontFace(f, aRules[i].mOrigin, oldRecords, modified);
   }
 
   for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
     // Do the same for the non rule backed FontFace objects.
     InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace, modified);
   }
 
   // Remove any residual families that have no font entries (i.e., they were
@@ -811,28 +811,29 @@ void FontFaceSet::InsertNonRuleFontFace(
 
   nsAtomCString family(fontFamily);
 
   // Just create a new font entry if we haven't got one already.
   if (!aFontFace->GetUserFontEntry()) {
     // XXX Should we be checking mUserFontSet->mLocalRulesUsed like
     // InsertRuleFontFace does?
     RefPtr<gfxUserFontEntry> entry = FindOrCreateUserFontEntryFromFontFace(
-        family, aFontFace, SheetType::Doc);
+        family, aFontFace, StyleOrigin::Author);
     if (!entry) {
       return;
     }
     aFontFace->SetUserFontEntry(entry);
   }
 
   aFontSetModified = true;
   mUserFontSet->AddUserFontEntry(family, aFontFace->GetUserFontEntry());
 }
 
-void FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
+void FontFaceSet::InsertRuleFontFace(FontFace* aFontFace,
+                                     StyleOrigin aSheetType,
                                      nsTArray<FontFaceRecord>& aOldRecords,
                                      bool& aFontSetModified) {
   nsAtom* fontFamily = aFontFace->GetFamilyName();
   if (!fontFamily) {
     // If there is no family name, this rule cannot contribute a
     // usable font, so there is no point in processing it further.
     return;
   }
@@ -843,17 +844,17 @@ void FontFaceSet::InsertRuleFontFace(Fon
   nsAtomCString family(fontFamily);
 
   // This is a rule backed FontFace.  First, we check in aOldRecords; if
   // the FontFace for the rule exists there, just move it to the new record
   // list, and put the entry into the appropriate family.
   for (size_t i = 0; i < aOldRecords.Length(); ++i) {
     FontFaceRecord& rec = aOldRecords[i];
 
-    if (rec.mFontFace == aFontFace && rec.mSheetType == aSheetType) {
+    if (rec.mFontFace == aFontFace && rec.mOrigin == Some(aSheetType)) {
       // if local rules were used, don't use the old font entry
       // for rules containing src local usage
       if (mUserFontSet->mLocalRulesUsed && mUserFontSet->mRebuildLocalRules) {
         if (aFontFace->HasLocalSrc()) {
           // Remove the old record, but wait to see if we successfully create a
           // new user font entry below.
           remove = true;
           removeIndex = i;
@@ -895,17 +896,17 @@ void FontFaceSet::InsertRuleFontFace(Fon
     // Remove the old record so that we don't have the same FontFace listed
     // in both mRuleFaces and oldRecords, which would cause us to call
     // DisconnectFromRule on a FontFace that should still be rule backed.
     aOldRecords.RemoveElementAt(removeIndex);
   }
 
   FontFaceRecord rec;
   rec.mFontFace = aFontFace;
-  rec.mSheetType = aSheetType;
+  rec.mOrigin = Some(aSheetType);
   rec.mLoadEventShouldFire =
       aFontFace->Status() == FontFaceLoadStatus::Unloaded ||
       aFontFace->Status() == FontFaceLoadStatus::Loading;
 
   aFontFace->SetUserFontEntry(entry);
 
   MOZ_ASSERT(!HasRuleFontFace(aFontFace),
              "FontFace should not occur in mRuleFaces twice");
@@ -929,17 +930,17 @@ FontFaceSet::FindOrCreateUserFontEntryFr
   nsAtom* fontFamily = aFontFace->GetFamilyName();
   if (!fontFamily) {
     // If there is no family name, this rule cannot contribute a
     // usable font, so there is no point in processing it further.
     return nullptr;
   }
 
   return FindOrCreateUserFontEntryFromFontFace(nsAtomCString(fontFamily),
-                                               aFontFace, SheetType::Doc);
+                                               aFontFace, StyleOrigin::Author);
 }
 
 static WeightRange GetWeightRangeForDescriptor(
     const Maybe<StyleComputedFontWeightRange>& aVal,
     gfxFontEntry::RangeFlags& aRangeFlags) {
   if (!aVal) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoWeight;
     return WeightRange(FontWeight::Normal());
@@ -980,17 +981,17 @@ static StretchRange GetStretchRangeForDe
 }
 
 // TODO(emilio): Should this take an nsAtom* aFamilyName instead?
 //
 // All callers have one handy.
 /* static */
 already_AddRefed<gfxUserFontEntry>
 FontFaceSet::FindOrCreateUserFontEntryFromFontFace(
-    const nsACString& aFamilyName, FontFace* aFontFace, SheetType aSheetType) {
+    const nsACString& aFamilyName, FontFace* aFontFace, StyleOrigin aOrigin) {
   FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
 
   uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
   StyleFontDisplay fontDisplay = StyleFontDisplay::Auto;
 
   gfxFontEntry::RangeFlags rangeFlags = gfxFontEntry::RangeFlags::eNoFlags;
 
   // set up weight
@@ -1065,17 +1066,17 @@ FontFaceSet::FindOrCreateUserFontEntryFr
           face->mOriginPrincipal =
               new gfxFontSrcPrincipal(extraData->Principal());
 
           // agent and user stylesheets are treated slightly differently,
           // the same-site origin check and access control headers are
           // enforced against the sheet principal rather than the document
           // principal to allow user stylesheets to include @font-face rules
           face->mUseOriginPrincipal =
-              (aSheetType == SheetType::User || aSheetType == SheetType::Agent);
+              aOrigin == StyleOrigin::User || aOrigin == StyleOrigin::UserAgent;
 
           face->mLocalName.Truncate();
           face->mFormatFlags = 0;
 
           while (i + 1 < len) {
             const auto& maybeFontFormat = sourceListComponents[i + 1];
             if (maybeFontFormat.tag !=
                 StyleFontFaceSourceListComponent::Tag::FormatHint) {
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -244,28 +244,27 @@ class FontFaceSet final : public DOMEven
   void DispatchLoadingFinishedEvent(
       const nsAString& aType, nsTArray<OwningNonNull<FontFace>>&& aFontFaces);
 
   // Note: if you add new cycle collected objects to FontFaceRecord,
   // make sure to update FontFaceSet's cycle collection macros
   // accordingly.
   struct FontFaceRecord {
     RefPtr<FontFace> mFontFace;
-    SheetType mSheetType;  // only relevant for mRuleFaces entries
+    Maybe<StyleOrigin> mOrigin;  // only relevant for mRuleFaces entries
 
     // When true, indicates that when finished loading, the FontFace should be
     // included in the subsequent loadingdone/loadingerror event fired at the
     // FontFaceSet.
     bool mLoadEventShouldFire;
   };
 
   static already_AddRefed<gfxUserFontEntry>
   FindOrCreateUserFontEntryFromFontFace(const nsACString& aFamilyName,
-                                        FontFace* aFontFace,
-                                        SheetType aSheetType);
+                                        FontFace* aFontFace, StyleOrigin);
 
   // search for @font-face rule that matches a userfont font entry
   RawServoFontFaceRule* FindRuleForUserFontEntry(
       gfxUserFontEntry* aUserFontEntry);
 
   nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
                      const gfxFontFaceSrc* aFontFaceSrc);
   gfxFontSrcPrincipal* GetStandardFontLoadPrincipal();
@@ -276,17 +275,17 @@ class FontFaceSet final : public DOMEven
   void DispatchFontLoadViolations(nsTArray<nsCOMPtr<nsIRunnable>>& aViolations);
   nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
                             const gfxFontFaceSrc* aFontFaceSrc,
                             uint8_t*& aBuffer, uint32_t& aBufferLength);
   nsresult LogMessage(gfxUserFontEntry* aUserFontEntry, const char* aMessage,
                       uint32_t aFlags, nsresult aStatus);
   void MarkUserFontSetDirty();
 
-  void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
+  void InsertRuleFontFace(FontFace* aFontFace, StyleOrigin aOrigin,
                           nsTArray<FontFaceRecord>& aOldRecords,
                           bool& aFontSetModified);
   void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
 
 #ifdef DEBUG
   bool HasRuleFontFace(FontFace* aFontFace);
 #endif
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -465,16 +465,17 @@ cbindgen-types = [
     { gecko = "StyleOwnedOrNull", servo = "gecko_bindings::sugar::ownership::OwnedOrNull" },
     { gecko = "StyleStrong", servo = "gecko_bindings::sugar::ownership::Strong" },
     { gecko = "StyleGenericFontFamily", servo = "values::computed::font::GenericFontFamily" },
     { gecko = "StyleFontFamilyNameSyntax", servo = "values::computed::font::FontFamilyNameSyntax" },
     { gecko = "StyleGenericColor", servo = "values::generics::color::Color" },
     { gecko = "StyleGenericColorOrAuto", servo = "values::generics::color::ColorOrAuto" },
     { gecko = "StyleGenericScrollbarColor", servo = "values::generics::ui::ScrollbarColor" },
     { gecko = "StyleRGBA", servo = "cssparser::RGBA" },
+    { gecko = "StyleOrigin", servo = "stylesheets::Origin" },
 ]
 
 mapped-generic-types = [
     { generic = true, gecko = "mozilla::RustCell", servo = "::std::cell::Cell" },
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::servo_arc::Arc<::custom_properties::CustomPropertiesMap>>" },
     { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -87,32 +87,23 @@ class MOZ_RAII AutoPrepareTraversal {
 
  private:
   AutoRestyleTimelineMarker mTimelineMarker;
   AutoSetInServoTraversal mSetInServoTraversal;
 };
 
 }  // namespace mozilla
 
-ServoStyleSet::ServoStyleSet(Document& aDocument)
-    : mDocument(&aDocument),
-      mAuthorStyleDisabled(false),
-      mStylistState(StylistState::NotDirty),
-      mUserFontSetUpdateGeneration(0),
-      mNeedsRestyleAfterEnsureUniqueInner(false) {
+ServoStyleSet::ServoStyleSet(Document& aDocument) : mDocument(&aDocument) {
   PreferenceSheet::EnsureInitialized();
   mRawSet.reset(Servo_StyleSet_Init(&aDocument));
 }
 
 ServoStyleSet::~ServoStyleSet() {
-  for (auto& sheetArray : mSheets) {
-    for (auto& sheet : sheetArray) {
-      sheet->DropStyleSet(this);
-    }
-  }
+  EnumerateStyleSheets([&](StyleSheet& aSheet) { aSheet.DropStyleSet(this); });
 }
 
 nsPresContext* ServoStyleSet::GetPresContext() {
   return mDocument->GetPresContext();
 }
 
 template <typename Functor>
 void EnumerateShadowRoots(const Document& aDoc, const Functor& aCb) {
@@ -562,176 +553,151 @@ already_AddRefed<ComputedStyle> ServoSty
   return Servo_ComputedValues_ResolveXULTreePseudoStyle(
              aParentElement, aPseudoTag, aParentStyle, &aInputWord,
              mRawSet.get())
       .Consume();
 }
 #endif
 
 // manage the set of style sheets in the style set
-nsresult ServoStyleSet::AppendStyleSheet(SheetType aType, StyleSheet* aSheet) {
+void ServoStyleSet::AppendStyleSheet(StyleOrigin aOrigin, StyleSheet* aSheet) {
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(aSheet->IsApplicable());
-  MOZ_ASSERT(IsCSSSheetType(aType));
   MOZ_ASSERT(aSheet->RawContents(),
              "Raw sheet should be in place before insertion.");
 
-  RemoveSheetOfType(aType, aSheet);
-  AppendSheetOfType(aType, aSheet);
+  aSheet->AddStyleSet(this);
 
   // Maintain a mirrored list of sheets on the servo side.
   // Servo will remove aSheet from its original position as part of the call
   // to Servo_StyleSet_AppendStyleSheet.
   Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
   SetStylistStyleSheetsDirty();
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(*aSheet);
   }
-
-  return NS_OK;
 }
 
-nsresult ServoStyleSet::RemoveStyleSheet(SheetType aType, StyleSheet* aSheet) {
+void ServoStyleSet::RemoveStyleSheet(StyleOrigin aOrigin, StyleSheet* aSheet) {
   MOZ_ASSERT(aSheet);
-  MOZ_ASSERT(IsCSSSheetType(aType));
 
-  RemoveSheetOfType(aType, aSheet);
+  aSheet->DropStyleSet(this);
 
   // Maintain a mirrored list of sheets on the servo side.
   Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet);
   SetStylistStyleSheetsDirty();
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetRemoved(*aSheet);
   }
-
-  return NS_OK;
 }
 
-nsresult ServoStyleSet::ReplaceSheets(
-    SheetType aType, const nsTArray<RefPtr<StyleSheet>>& aNewSheets) {
+void ServoStyleSet::ReplaceSheets(
+    StyleOrigin aOrigin, const nsTArray<RefPtr<StyleSheet>>& aNewSheets) {
   // Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
   // stores a flattened list. This makes ReplaceSheets a pretty clunky thing
   // to express. If the need ever arises, we can easily make this more efficent,
   // probably by aligning the representations better between engines.
 
   SetStylistStyleSheetsDirty();
 
   // Remove all the existing sheets first.
-  for (const auto& sheet : mSheets[aType]) {
+  for (size_t count = SheetCount(aOrigin); count--;) {
+    StyleSheet* sheet = SheetAt(aOrigin, count);
     sheet->DropStyleSet(this);
     Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet);
   }
-  mSheets[aType].Clear();
 
   // Add in all the new sheets.
   for (auto& sheet : aNewSheets) {
-    AppendSheetOfType(aType, sheet);
+    sheet->AddStyleSet(this);
     MOZ_ASSERT(sheet->RawContents(),
                "Raw sheet should be in place before replacement.");
     Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
   }
 
   // Just don't bother calling SheetRemoved / SheetAdded, and recreate the rule
   // map when needed.
   mStyleRuleMap = nullptr;
-  return NS_OK;
 }
 
-nsresult ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
-                                               StyleSheet* aNewSheet,
-                                               StyleSheet* aReferenceSheet) {
+void ServoStyleSet::InsertStyleSheetBefore(Origin aOrigin,
+                                           StyleSheet* aNewSheet,
+                                           StyleSheet* aReferenceSheet) {
   MOZ_ASSERT(aNewSheet);
   MOZ_ASSERT(aReferenceSheet);
   MOZ_ASSERT(aNewSheet->IsApplicable());
   MOZ_ASSERT(aNewSheet != aReferenceSheet, "Can't place sheet before itself.");
   MOZ_ASSERT(aNewSheet->RawContents(),
              "Raw sheet should be in place before insertion.");
   MOZ_ASSERT(aReferenceSheet->RawContents(),
              "Reference sheet should have a raw sheet.");
 
   // Servo will remove aNewSheet from its original position as part of the
   // call to Servo_StyleSet_InsertStyleSheetBefore.
-  RemoveSheetOfType(aType, aNewSheet);
-  InsertSheetOfType(aType, aNewSheet, aReferenceSheet);
+  aNewSheet->AddStyleSet(this);
 
   // Maintain a mirrored list of sheets on the servo side.
   Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aNewSheet,
                                         aReferenceSheet);
   SetStylistStyleSheetsDirty();
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(*aNewSheet);
   }
-
-  return NS_OK;
 }
 
-int32_t ServoStyleSet::SheetCount(SheetType aType) const {
-  MOZ_ASSERT(IsCSSSheetType(aType));
-  return mSheets[aType].Length();
+size_t ServoStyleSet::SheetCount(Origin aOrigin) const {
+  return Servo_StyleSet_GetSheetCount(mRawSet.get(), aOrigin);
 }
 
-StyleSheet* ServoStyleSet::StyleSheetAt(SheetType aType, int32_t aIndex) const {
-  MOZ_ASSERT(IsCSSSheetType(aType));
-  return mSheets[aType][aIndex];
+StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const {
+  return const_cast<StyleSheet*>(
+      Servo_StyleSet_GetSheetAt(mRawSet.get(), aOrigin, aIndex));
 }
 
 void ServoStyleSet::AppendAllNonDocumentAuthorSheets(
     nsTArray<StyleSheet*>& aArray) const {
   if (mDocument) {
     mDocument->BindingManager()->AppendAllSheets(aArray);
     EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
       for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
         aArray.AppendElement(aShadowRoot.SheetAt(index));
       }
     });
   }
 }
 
-nsresult ServoStyleSet::RemoveDocStyleSheet(StyleSheet* aSheet) {
-  return RemoveStyleSheet(SheetType::Doc, aSheet);
-}
-
-nsresult ServoStyleSet::AddDocStyleSheet(StyleSheet* aSheet,
-                                         Document* aDocument) {
+void ServoStyleSet::AddDocStyleSheet(StyleSheet* aSheet) {
   MOZ_ASSERT(aSheet->IsApplicable());
   MOZ_ASSERT(aSheet->RawContents(),
              "Raw sheet should be in place by this point.");
 
   RefPtr<StyleSheet> strong(aSheet);
 
-  RemoveSheetOfType(SheetType::Doc, aSheet);
-
-  size_t index = aDocument->FindDocStyleSheetInsertionPoint(
-      mSheets[SheetType::Doc], *aSheet);
+  size_t index = mDocument->FindDocStyleSheetInsertionPoint(*aSheet);
+  aSheet->AddStyleSet(this);
 
-  if (index < mSheets[SheetType::Doc].Length()) {
+  if (index < SheetCount(Origin::Author)) {
     // This case is insert before.
-    StyleSheet* beforeSheet = mSheets[SheetType::Doc][index];
-    InsertSheetOfType(SheetType::Doc, aSheet, beforeSheet);
+    StyleSheet* beforeSheet = SheetAt(Origin::Author, index);
 
     // Maintain a mirrored list of sheets on the servo side.
     Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet, beforeSheet);
     SetStylistStyleSheetsDirty();
   } else {
-    // This case is append.
-    AppendSheetOfType(SheetType::Doc, aSheet);
-
     // Maintain a mirrored list of sheets on the servo side.
     Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
     SetStylistStyleSheetsDirty();
   }
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(*aSheet);
   }
-
-  return NS_OK;
 }
 
 already_AddRefed<ComputedStyle> ServoStyleSet::ProbePseudoElementStyle(
     const Element& aOriginatingElement, PseudoStyleType aType,
     ComputedStyle* aParentStyle) {
   // Runs from frame construction, this should have clean styles already, except
   // with non-lazy FC...
   UpdateStylistIfNeeded();
@@ -924,37 +890,50 @@ void ServoStyleSet::SetStylistStyleSheet
 
 void ServoStyleSet::SetStylistXBLStyleSheetsDirty() {
   mStylistState |= StylistState::XBLStyleSheetsDirty;
   if (nsPresContext* presContext = GetPresContext()) {
     presContext->RestyleManager()->IncrementUndisplayedRestyleGeneration();
   }
 }
 
+static OriginFlags ToOriginFlags(StyleOrigin aOrigin) {
+  switch (aOrigin) {
+    case StyleOrigin::UserAgent:
+      return OriginFlags::UserAgent;
+    case StyleOrigin::User:
+      return OriginFlags::User;
+    default:
+      MOZ_FALLTHROUGH_ASSERT("Unknown origin?");
+    case StyleOrigin::Author:
+      return OriginFlags::Author;
+  }
+}
+
 void ServoStyleSet::RuleAdded(StyleSheet& aSheet, css::Rule& aRule) {
   if (mStyleRuleMap) {
     mStyleRuleMap->RuleAdded(aSheet, aRule);
   }
 
   // FIXME(emilio): Could be more granular based on aRule.
-  MarkOriginsDirty(aSheet.GetOrigin());
+  MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
 }
 
 void ServoStyleSet::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule) {
   if (mStyleRuleMap) {
     mStyleRuleMap->RuleRemoved(aSheet, aRule);
   }
 
   // FIXME(emilio): Could be more granular based on aRule.
-  MarkOriginsDirty(aSheet.GetOrigin());
+  MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
 }
 
 void ServoStyleSet::RuleChanged(StyleSheet& aSheet, css::Rule* aRule) {
   // FIXME(emilio): Could be more granular based on aRule.
-  MarkOriginsDirty(aSheet.GetOrigin());
+  MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
 }
 
 #ifdef DEBUG
 void ServoStyleSet::AssertTreeIsClean() {
   DocumentStyleRootIterator iter(mDocument);
   while (Element* root = iter.GetNextStyleRoot()) {
     Servo_AssertTreeIsClean(root);
   }
@@ -1019,22 +998,19 @@ already_AddRefed<RawServoAnimationValue>
       .Consume();
 }
 
 bool ServoStyleSet::EnsureUniqueInnerOnCSSSheets() {
   using SheetOwner =
       Variant<ServoStyleSet*, nsXBLPrototypeBinding*, ShadowRoot*>;
 
   AutoTArray<Pair<StyleSheet*, SheetOwner>, 32> queue;
-  for (auto& entryArray : mSheets) {
-    for (auto& sheet : entryArray) {
-      StyleSheet* downcasted = sheet;
-      queue.AppendElement(MakePair(downcasted, SheetOwner{this}));
-    }
-  }
+  EnumerateStyleSheets([&](StyleSheet& aSheet) {
+    queue.AppendElement(MakePair(&aSheet, SheetOwner{this}));
+  });
 
   EnumerateShadowRoots(*mDocument, [&](ShadowRoot& aShadowRoot) {
     for (auto index : IntegerRange(aShadowRoot.SheetCount())) {
       queue.AppendElement(
           MakePair(aShadowRoot.SheetAt(index), SheetOwner{&aShadowRoot}));
     }
   });
 
@@ -1272,46 +1248,16 @@ bool ServoStyleSet::ShouldTraverseInPara
 #ifdef MOZ_GECKO_PROFILER
   if (profiler_feature_active(ProfilerFeature::SequentialStyle)) {
     return false;
   }
 #endif
   return true;
 }
 
-void ServoStyleSet::PrependSheetOfType(SheetType aType, StyleSheet* aSheet) {
-  aSheet->AddStyleSet(this);
-  mSheets[aType].InsertElementAt(0, aSheet);
-}
-
-void ServoStyleSet::AppendSheetOfType(SheetType aType, StyleSheet* aSheet) {
-  aSheet->AddStyleSet(this);
-  mSheets[aType].AppendElement(aSheet);
-}
-
-void ServoStyleSet::InsertSheetOfType(SheetType aType, StyleSheet* aSheet,
-                                      StyleSheet* aBeforeSheet) {
-  for (uint32_t i = 0; i < mSheets[aType].Length(); ++i) {
-    if (mSheets[aType][i] == aBeforeSheet) {
-      aSheet->AddStyleSet(this);
-      mSheets[aType].InsertElementAt(i, aSheet);
-      return;
-    }
-  }
-}
-
-void ServoStyleSet::RemoveSheetOfType(SheetType aType, StyleSheet* aSheet) {
-  for (uint32_t i = 0; i < mSheets[aType].Length(); ++i) {
-    if (mSheets[aType][i] == aSheet) {
-      aSheet->DropStyleSet(this);
-      mSheets[aType].RemoveElementAt(i);
-    }
-  }
-}
-
 void ServoStyleSet::RunPostTraversalTasks() {
   MOZ_ASSERT(!IsInServoTraversal());
 
   if (mPostTraversalTasks.IsEmpty()) {
     return;
   }
 
   nsTArray<PostTraversalTask> tasks;
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -9,17 +9,16 @@
 
 #include "mozilla/AtomArray.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/MediaFeatureChange.h"
 #include "mozilla/PostTraversalTask.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/ServoUtils.h"
-#include "mozilla/SheetType.h"
 #include "mozilla/UniquePtr.h"
 #include "MainThreadUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsChangeHint.h"
 #include "nsCoord.h"
 #include "nsAtom.h"
 #include "nsIMemoryReporter.h"
@@ -78,16 +77,18 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Or
 /**
  * The set of style sheets that apply to a document, backed by a Servo
  * Stylist.  A ServoStyleSet contains StyleSheets.
  */
 class ServoStyleSet {
   friend class RestyleManager;
   typedef ServoElementSnapshotTable SnapshotTable;
 
+  using Origin = StyleOrigin;
+
  public:
   static bool IsInServoTraversal() { return mozilla::IsInServoTraversal(); }
 
 #ifdef DEBUG
   // Used for debug assertions. We make this debug-only to prevent callers from
   // accidentally using it instead of IsInServoTraversal, which is cheaper. We
   // can change this if a use-case arises.
   static bool IsCurrentThreadInServoTraversal();
@@ -195,37 +196,31 @@ class ServoStyleSet {
 
 #ifdef MOZ_XUL
   already_AddRefed<ComputedStyle> ResolveXULTreePseudoStyle(
       dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,
       ComputedStyle* aParentStyle, const AtomArray& aInputWord);
 #endif
 
   // manage the set of style sheets in the style set
-  nsresult AppendStyleSheet(SheetType aType, StyleSheet* aSheet);
-  nsresult RemoveStyleSheet(SheetType aType, StyleSheet* aSheet);
-  nsresult ReplaceSheets(SheetType aType,
-                         const nsTArray<RefPtr<StyleSheet>>& aNewSheets);
-  nsresult InsertStyleSheetBefore(SheetType aType, StyleSheet* aNewSheet,
-                                  StyleSheet* aReferenceSheet);
+  void AppendStyleSheet(Origin, StyleSheet*);
+  void RemoveStyleSheet(Origin, StyleSheet*);
+  void ReplaceSheets(Origin, const nsTArray<RefPtr<StyleSheet>>& aNewSheets);
+  void InsertStyleSheetBefore(Origin, StyleSheet*, StyleSheet* aReferenceSheet);
 
-  int32_t SheetCount(SheetType aType) const;
-  StyleSheet* StyleSheetAt(SheetType aType, int32_t aIndex) const;
+  size_t SheetCount(Origin) const;
+  StyleSheet* SheetAt(Origin, size_t aIndex) const;
 
   void AppendAllNonDocumentAuthorSheets(nsTArray<StyleSheet*>& aArray) const;
 
-  template <typename Func>
-  void EnumerateStyleSheetArrays(Func aCallback) const {
-    for (const auto& sheetArray : mSheets) {
-      aCallback(sheetArray);
-    }
+  void RemoveDocStyleSheet(StyleSheet* aSheet) {
+    RemoveStyleSheet(StyleOrigin::Author, aSheet);
   }
 
-  nsresult RemoveDocStyleSheet(StyleSheet* aSheet);
-  nsresult AddDocStyleSheet(StyleSheet* aSheet, dom::Document* aDocument);
+  void AddDocStyleSheet(StyleSheet* aSheet);
 
   // check whether there is ::before/::after style for an element
   already_AddRefed<ComputedStyle> ProbePseudoElementStyle(
       const dom::Element& aOriginatingElement, PseudoStyleType aType,
       ComputedStyle* aParentStyle);
 
   /**
    * Performs a Servo traversal to compute style for all dirty nodes in the
@@ -292,16 +287,27 @@ class ServoStyleSet {
   void ClearCachedStyleData();
 
   /**
    * Notifies the Servo stylesheet that the document's compatibility mode has
    * changed.
    */
   void CompatibilityModeChanged();
 
+  template <typename T>
+  void EnumerateStyleSheets(T aCb) {
+    const StyleOrigin kOrigins[] = {StyleOrigin::UserAgent, StyleOrigin::User,
+                                    StyleOrigin::Author};
+    for (auto origin : kOrigins) {
+      for (size_t i = 0, count = SheetCount(origin); i < count; ++i) {
+        aCb(*SheetAt(origin, i));
+      }
+    }
+  }
+
   /**
    * Resolve style for the given element, and return it as a
    * ComputedStyle.
    *
    * FIXME(emilio): Is there a point in this after bug 1367904?
    */
   inline already_AddRefed<ComputedStyle> ResolveServoStyle(const dom::Element&);
 
@@ -483,63 +489,56 @@ class ServoStyleSet {
    * Update the stylist as needed to ensure style data is up-to-date.
    *
    * This should only be called if StylistNeedsUpdate returns true.
    */
   void UpdateStylist();
 
   void RunPostTraversalTasks();
 
-  void PrependSheetOfType(SheetType aType, StyleSheet* aSheet);
-
-  void AppendSheetOfType(SheetType aType, StyleSheet* aSheet);
-
-  void InsertSheetOfType(SheetType aType, StyleSheet* aSheet,
-                         StyleSheet* aBeforeSheet);
-
-  void RemoveSheetOfType(SheetType aType, StyleSheet* aSheet);
-
-  // The owner document of this style set. Never null, and always outlives the
-  // StyleSet.
-  dom::Document* mDocument;
+  void PrependSheetOfType(Origin, StyleSheet*);
+  void AppendSheetOfType(Origin, StyleSheet*);
+  void InsertSheetOfType(Origin, StyleSheet*, StyleSheet* aBeforeSheet);
+  void RemoveSheetOfType(Origin, StyleSheet*);
 
   const nsPresContext* GetPresContext() const {
     return const_cast<ServoStyleSet*>(this)->GetPresContext();
   }
 
   /**
    * Return the associated pres context if we're the master style set and we
    * have an associated pres shell.
    */
   nsPresContext* GetPresContext();
 
+  // The owner document of this style set. Never null, and always outlives the
+  // StyleSet.
+  dom::Document* mDocument;
   UniquePtr<RawServoStyleSet> mRawSet;
-  EnumeratedArray<SheetType, SheetType::Count, nsTArray<RefPtr<StyleSheet>>>
-      mSheets;
-  bool mAuthorStyleDisabled;
-  StylistState mStylistState;
-  uint64_t mUserFontSetUpdateGeneration;
+
+  // Map from raw Servo style rule to Gecko's wrapper object.
+  // Constructed lazily when requested by devtools.
+  UniquePtr<ServoStyleRuleMap> mStyleRuleMap;
+  uint64_t mUserFontSetUpdateGeneration = 0;
 
-  bool mNeedsRestyleAfterEnsureUniqueInner;
+  // Tasks to perform after a traversal, back on the main thread.
+  //
+  // These are similar to Servo's SequentialTasks, except that they are
+  // posted by C++ code running on style worker threads.
+  nsTArray<PostTraversalTask> mPostTraversalTasks;
 
   // Stores pointers to our cached ComputedStyles for non-inheriting anonymous
   // boxes.
   EnumeratedArray<nsCSSAnonBoxes::NonInheriting,
                   nsCSSAnonBoxes::NonInheriting::_Count, RefPtr<ComputedStyle>>
       mNonInheritingComputedStyles;
 
-  // Tasks to perform after a traversal, back on the main thread.
-  //
-  // These are similar to Servo's SequentialTasks, except that they are
-  // posted by C++ code running on style worker threads.
-  nsTArray<PostTraversalTask> mPostTraversalTasks;
-
-  // Map from raw Servo style rule to Gecko's wrapper object.
-  // Constructed lazily when requested by devtools.
-  UniquePtr<ServoStyleRuleMap> mStyleRuleMap;
+  StylistState mStylistState = StylistState::NotDirty;
+  bool mAuthorStyleDisabled = false;
+  bool mNeedsRestyleAfterEnsureUniqueInner = false;
 };
 
 class UACacheReporter final : public nsIMemoryReporter {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMEMORYREPORTER
 
  private:
   ~UACacheReporter() {}
--- a/layout/style/ServoTypes.h
+++ b/layout/style/ServoTypes.h
@@ -5,30 +5,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* types defined to pass values through Gecko_* and Servo_* FFI functions */
 
 #ifndef mozilla_ServoTypes_h
 #define mozilla_ServoTypes_h
 
 #include "mozilla/RefPtr.h"
-#include "mozilla/SheetType.h"
 #include "mozilla/TypedEnumBits.h"
 #include "nsCoord.h"
 
 struct RawServoFontFaceRule;
 
 namespace mozilla {
+enum class StyleOrigin : uint8_t;
 struct LangGroupFontPrefs;
 }
 
-// used for associating sheet type with specific @font-face rules
+// used for associating origin with specific @font-face rules
 struct nsFontFaceRuleContainer {
   RefPtr<RawServoFontFaceRule> mRule;
-  mozilla::SheetType mSheetType;
+  mozilla::StyleOrigin mOrigin;
 };
 
 namespace mozilla {
 
 // Indicates whether the Servo style system should expect the style on an
 // element to have already been resolved (i.e. via a parallel traversal), or
 // whether it may be lazily computed.
 enum class LazyComputeBehavior {
deleted file mode 100644
--- a/layout/style/SheetType.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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/. */
-
-/* enum to represent a level in the cascade */
-
-#ifndef mozilla_SheetType_h
-#define mozilla_SheetType_h
-
-#include <stdint.h>
-
-namespace mozilla {
-
-// The "origins" of the CSS cascade, from lowest precedence to
-// highest (for non-!important rules).
-//
-// Be sure to update NS_RULE_NODE_LEVEL_MASK when changing the number
-// of sheet types; static assertions enforce this.
-enum class SheetType : uint8_t {
-  Agent,  // CSS
-  User,   // CSS
-  PresHint,
-  Doc,  // CSS
-  StyleAttr,
-  Override,  // CSS
-  Animation,
-  Transition,
-
-  Count,
-  Unknown = 0xff
-};
-
-// Returns whether aSheetType represents a level of the cascade that uses
-// a StyleSheet object.
-inline bool IsCSSSheetType(SheetType aSheetType) {
-  switch (aSheetType) {
-    case SheetType::Agent:
-    case SheetType::User:
-    case SheetType::Doc:
-    case SheetType::Override:
-      return true;
-    default:
-      return false;
-  }
-}
-
-}  // namespace mozilla
-
-#endif  // mozilla_SheetType_h
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -413,23 +413,24 @@ void StyleSheet::GetTitle(nsAString& aTi
 
 void StyleSheet::WillDirty() {
   if (IsComplete()) {
     EnsureUniqueInner();
   }
 }
 
 void StyleSheet::AddStyleSet(ServoStyleSet* aStyleSet) {
-  NS_ASSERTION(!mStyleSets.Contains(aStyleSet), "style set already registered");
+  MOZ_DIAGNOSTIC_ASSERT(!mStyleSets.Contains(aStyleSet),
+                        "style set already registered");
   mStyleSets.AppendElement(aStyleSet);
 }
 
 void StyleSheet::DropStyleSet(ServoStyleSet* aStyleSet) {
-  DebugOnly<bool> found = mStyleSets.RemoveElement(aStyleSet);
-  NS_ASSERTION(found, "didn't find style set");
+  bool found = mStyleSets.RemoveElement(aStyleSet);
+  MOZ_DIAGNOSTIC_ASSERT(found, "didn't find style set");
 }
 
 void StyleSheet::EnsureUniqueInner() {
   MOZ_ASSERT(mInner->mSheets.Length() != 0, "unexpected number of outers");
   mState |= State::ForcedUniqueInner;
 
   if (HasUniqueInner()) {
     // already unique
@@ -986,17 +987,17 @@ void StyleSheet::FinishParse() {
 nsresult StyleSheet::ReparseSheet(const nsAString& aInput) {
   if (!IsComplete()) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   // Allowing to modify UA sheets is dangerous (in the sense that C++ code
   // relies on rules in those sheets), plus they're probably going to be shared
   // across processes in which case this is directly a no-go.
-  if (GetOrigin() == OriginFlags::UserAgent) {
+  if (GetOrigin() == StyleOrigin::UserAgent) {
     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   }
 
   // Hold strong ref to the CSSLoader in case the document update
   // kills the document
   RefPtr<css::Loader> loader;
   if (Document* doc = GetAssociatedDocument()) {
     loader = doc->CSSLoader();
@@ -1171,19 +1172,18 @@ void StyleSheet::DeleteRuleInternal(uint
 nsresult StyleSheet::InsertRuleIntoGroupInternal(const nsAString& aRule,
                                                  css::GroupRule* aGroup,
                                                  uint32_t aIndex) {
   auto rules = static_cast<ServoCSSRuleList*>(aGroup->CssRules());
   MOZ_ASSERT(rules->GetParentRule() == aGroup);
   return rules->InsertRule(aRule, aIndex);
 }
 
-OriginFlags StyleSheet::GetOrigin() {
-  return static_cast<OriginFlags>(
-      Servo_StyleSheet_GetOrigin(Inner().mContents));
+StyleOrigin StyleSheet::GetOrigin() const {
+  return Servo_StyleSheet_GetOrigin(Inner().mContents);
 }
 
 void StyleSheet::SetSharedContents(nsLayoutStylesheetCache::Shm* aSharedMemory,
                                    const ServoCssRules* aSharedRules) {
   MOZ_ASSERT(aSharedMemory);
   MOZ_ASSERT(!IsComplete());
 
   SetURLExtraData();
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -136,17 +136,17 @@ class StyleSheet final : public nsICSSLo
   NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate,
                               nsresult aStatus) final;
 
   // Internal GetCssRules methods which do not have security check and
   // completeness check.
   ServoCSSRuleList* GetCssRulesInternal();
 
   // Returns the stylesheet's Servo origin as an OriginFlags value.
-  mozilla::OriginFlags GetOrigin();
+  mozilla::StyleOrigin GetOrigin() const;
 
   /**
    * The different changes that a stylesheet may go through.
    *
    * Used by the StyleSets in order to handle more efficiently some kinds of
    * changes.
    */
   enum class ChangeType {
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -101,17 +101,16 @@ EXPORTS.mozilla += [
     'ServoElementSnapshot.h',
     'ServoElementSnapshotTable.h',
     'ServoStyleConstsForwards.h',
     'ServoStyleSet.h',
     'ServoStyleSetInlines.h',
     'ServoTraversalStatistics.h',
     'ServoTypes.h',
     'ServoUtils.h',
-    'SheetType.h',
     'StyleAnimationValue.h',
     'StyleColorInlines.h',
     'StyleSheet.h',
     'StyleSheetInfo.h',
     'StyleSheetInlines.h',
     'URLExtraData.h',
     'UserAgentStyleSheetID.h',
     'UserAgentStyleSheetList.h',
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -9,17 +9,16 @@
 #ifndef nsCSSValue_h___
 #define nsCSSValue_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ServoBindingTypes.h"
-#include "mozilla/SheetType.h"
 #include "mozilla/URLExtraData.h"
 #include "mozilla/UniquePtr.h"
 
 #include "nsCSSKeywords.h"
 #include "nsCSSPropertyID.h"
 #include "nsCoord.h"
 #include "nsProxyRelease.h"
 #include "nsRefPtrHashtable.h"
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -9,17 +9,16 @@
  * internal API for computed style data for an element
  */
 
 #ifndef nsStyleStruct_h___
 #define nsStyleStruct_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
-#include "mozilla/SheetType.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/StyleColorInlines.h"
 #include "mozilla/UniquePtr.h"
 #include "nsColor.h"
 #include "nsCoord.h"
 #include "nsMargin.h"
 #include "nsFont.h"
 #include "nsStyleAutoArray.h"
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -8,19 +8,19 @@
 //!
 //! FIXME(emilio): This file should generally just die.
 
 #![allow(unsafe_code)]
 
 use crate::gecko::values::GeckoStyleCoordConvertible;
 use crate::gecko_bindings::bindings;
 use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Components};
-use crate::gecko_bindings::structs::{nsStyleImage, nsresult, SheetType};
+use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
 use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
-use crate::stylesheets::{Origin, RulesMutateError};
+use crate::stylesheets::RulesMutateError;
 use crate::values::computed::image::LineDirection;
 use crate::values::computed::transform::Matrix3D;
 use crate::values::computed::url::ComputedImageUrl;
 use crate::values::computed::{Angle, Gradient, Image};
 use crate::values::computed::{Integer, LengthPercentage};
 use crate::values::computed::{Length, Percentage, TextAlign};
 use crate::values::generics::box_::VerticalAlign;
 use crate::values::generics::grid::{TrackListValue, TrackSize};
@@ -813,26 +813,16 @@ impl From<RulesMutateError> for nsresult
             RulesMutateError::Syntax => nsresult::NS_ERROR_DOM_SYNTAX_ERR,
             RulesMutateError::IndexSize => nsresult::NS_ERROR_DOM_INDEX_SIZE_ERR,
             RulesMutateError::HierarchyRequest => nsresult::NS_ERROR_DOM_HIERARCHY_REQUEST_ERR,
             RulesMutateError::InvalidState => nsresult::NS_ERROR_DOM_INVALID_STATE_ERR,
         }
     }
 }
 
-impl From<Origin> for SheetType {
-    fn from(other: Origin) -> Self {
-        match other {
-            Origin::UserAgent => SheetType::Agent,
-            Origin::Author => SheetType::Doc,
-            Origin::User => SheetType::User,
-        }
-    }
-}
-
 impl TrackSize<LengthPercentage> {
     /// Return TrackSize from given two nsStyleCoord
     pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
         use crate::gecko_bindings::structs::root::nsStyleUnit;
         use crate::values::generics::grid::TrackBreadth;
 
         if gecko_min.unit() == nsStyleUnit::eStyleUnit_None {
             debug_assert!(
--- a/servo/components/style/stylesheet_set.rs
+++ b/servo/components/style/stylesheet_set.rs
@@ -463,17 +463,24 @@ where
 
     /// Returns the number of stylesheets in the set.
     pub fn len(&self) -> usize {
         self.collections
             .iter_origins()
             .fold(0, |s, (item, _)| s + item.len())
     }
 
+    /// Returns the count of stylesheets for a given origin.
+    #[inline]
+    pub fn sheet_count(&self, origin: Origin) -> usize {
+        self.collections.borrow_for_origin(&origin).len()
+    }
+
     /// Returns the `index`th stylesheet in the set for the given origin.
+    #[inline]
     pub fn get(&self, origin: Origin, index: usize) -> Option<&S> {
         self.collections.borrow_for_origin(&origin).get(index)
     }
 
     /// Returns whether the given set has changed from the last flush.
     pub fn has_changed(&self) -> bool {
         self.collections
             .iter_origins()
--- a/servo/components/style/stylesheets/origin.rs
+++ b/servo/components/style/stylesheets/origin.rs
@@ -5,28 +5,27 @@
 //! [CSS cascade origins](https://drafts.csswg.org/css-cascade/#cascading-origins).
 
 use std::marker::PhantomData;
 use std::ops::BitOrAssign;
 
 /// Each style rule has an origin, which determines where it enters the cascade.
 ///
 /// <https://drafts.csswg.org/css-cascade/#cascading-origins>
-#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
 #[repr(u8)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
 pub enum Origin {
     /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
-    UserAgent = 1 << 0,
+    UserAgent = 0x1,
 
     /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user>
-    User = 1 << 1,
+    User = 0x2,
 
     /// <https://drafts.csswg.org/css-cascade/#cascade-origin-author>
-    Author = 1 << 2,
+    Author = 0x4,
 }
 
 impl Origin {
     /// Returns an origin that goes in order for `index`.
     ///
     /// This is used for iterating across origins.
     fn from_index(index: i8) -> Option<Self> {
         Some(match index {
@@ -54,17 +53,17 @@ impl Origin {
             cur: self.to_index(),
             rev: true,
         }
     }
 }
 
 bitflags! {
     /// A set of origins. This is equivalent to Gecko's OriginFlags.
-    #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
+    #[derive(MallocSizeOf)]
     pub struct OriginSet: u8 {
         /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user-agent>
         const ORIGIN_USER_AGENT = Origin::UserAgent as u8;
         /// <https://drafts.csswg.org/css-cascade/#cascade-origin-user>
         const ORIGIN_USER = Origin::User as u8;
         /// <https://drafts.csswg.org/css-cascade/#cascade-origin-author>
         const ORIGIN_AUTHOR = Origin::Author as u8;
     }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -586,16 +586,28 @@ impl Stylist {
     }
 
     /// Remove a given stylesheet to the current set.
     pub fn remove_stylesheet(&mut self, sheet: StylistSheet, guard: &SharedRwLockReadGuard) {
         self.stylesheets
             .remove_stylesheet(Some(&self.device), sheet, guard)
     }
 
+    /// Appends a new stylesheet to the current set.
+    #[inline]
+    pub fn sheet_count(&self, origin: Origin) -> usize {
+        self.stylesheets.sheet_count(origin)
+    }
+
+    /// Appends a new stylesheet to the current set.
+    #[inline]
+    pub fn sheet_at(&self, origin: Origin, index: usize) -> Option<&StylistSheet> {
+        self.stylesheets.get(origin, index)
+    }
+
     /// Returns whether for any of the applicable style rule data a given
     /// condition is true.
     pub fn any_applicable_rule_data<E, F>(&self, element: E, mut f: F) -> bool
     where
         E: TElement,
         F: FnMut(&CascadeData) -> bool,
     {
         if f(&self.cascade_data.user_agent.cascade_data) {
--- a/servo/ports/geckolib/cbindgen.toml
+++ b/servo/ports/geckolib/cbindgen.toml
@@ -98,16 +98,17 @@ include = [
   "BorderSpacing",
   "BorderRadius",
   "NonNegativeLengthOrNumberRect",
   "Perspective",
   "ZIndex",
   "TransformOrigin",
   "WordBreak",
   "Contain",
+  "Origin",
   "RestyleHint",
   "TouchAction",
   "WillChangeBits",
   "TextDecorationLine",
   "TextTransform",
   "MozListReversed",
   "Owned",
   "OwnedOrNull",
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1640,16 +1640,35 @@ pub extern "C" fn Servo_StyleSet_RemoveS
     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.remove_stylesheet(sheet, &guard);
 }
 
 #[no_mangle]
+pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
+    raw_data: &RawServoStyleSet,
+    origin: Origin,
+    index: usize,
+) -> *const DomStyleSheet {
+    let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
+    data.stylist.sheet_at(origin, index).map_or(ptr::null(), |s| s.raw())
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
+    raw_data: &RawServoStyleSet,
+    origin: Origin,
+) -> usize {
+    let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
+    data.stylist.sheet_count(origin)
+}
+
+#[no_mangle]
 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
     raw_data: &RawServoStyleSet,
     doc_element: Option<&RawGeckoElement>,
     snapshots: *const ServoElementSnapshotTable,
 ) {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
@@ -1738,29 +1757,18 @@ pub extern "C" fn Servo_StyleSheet_SizeO
         malloc_size_of.unwrap(),
         Some(malloc_enclosing_size_of.unwrap()),
         None,
     );
     StylesheetContents::as_arc(&sheet).size_of(&guard, &mut ops)
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> u8 {
-    let origin = match StylesheetContents::as_arc(&sheet).origin {
-        Origin::UserAgent => OriginFlags::UserAgent,
-        Origin::User => OriginFlags::User,
-        Origin::Author => OriginFlags::Author,
-    };
-    // 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 (and bindgen doesn't have support for
-    // repr(transparent), so for now just unwrap it.
-    //
-    // See https://github.com/rust-lang/rust-bindgen/issues/1474
-    origin.0
+pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> Origin {
+    StylesheetContents::as_arc(&sheet).origin
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
     sheet: &RawServoStyleSheetContents,
     result: *mut nsAString,
 ) {
     let contents = StylesheetContents::as_arc(&sheet);
@@ -5513,19 +5521,19 @@ pub extern "C" fn Servo_StyleSet_GetFont
     // Reversed iterator because Gecko expects rules to appear sorted
     // UserAgent first, Author last.
     let font_face_iter = data
         .stylist
         .iter_extra_data_origins_rev()
         .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
 
     unsafe { rules.set_len(len) };
-    for (src, dest) in font_face_iter.zip(rules.iter_mut()) {
-        dest.mRule.set_arc_leaky(src.0.clone());
-        dest.mSheetType = src.1.into();
+    for ((rule, origin), dest) in font_face_iter.zip(rules.iter_mut()) {
+        dest.mRule.set_arc_leaky(rule.clone());
+        dest.mOrigin = origin;
     }
 }
 
 // XXX Ideally this should return a Option<&RawServoCounterStyleRule>,
 // but we cannot, because the value from AtomicRefCell::borrow() can only
 // live in this function, and thus anything derived from it cannot get the
 // same lifetime as raw_data in parameter. See bug 1451543.
 #[no_mangle]