Bug 1337258 - Support ServoStyleSheets in nsStyleSheetService. r=xidorn draft
authorCameron McCormack <cam@mcc.id.au>
Tue, 21 Feb 2017 10:42:27 +0800
changeset 487151 cb6e075e88c66a89bf6711db4ba913d62fd421ad
parent 487087 d0462b0948e0b1147dcce615bddcc46379bdadb2
child 546401 2c3a29b2c011da8bc94637ac8dd1ec2302f5ca26
push id46156
push userbmo:cam@mcc.id.au
push dateTue, 21 Feb 2017 02:42:54 +0000
reviewersxidorn
bugs1337258
milestone54.0a1
Bug 1337258 - Support ServoStyleSheets in nsStyleSheetService. r=xidorn MozReview-Commit-ID: 4vaHzDBZHFg
dom/base/nsDocument.cpp
dom/base/nsIDocumentInlines.h
dom/ipc/ContentParent.cpp
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsDocumentViewer.cpp
layout/base/nsStyleSheetService.cpp
layout/base/nsStyleSheetService.h
layout/style/test/mochitest.ini
layout/style/test/stylo-failures.md
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2282,23 +2282,19 @@ nsDocument::ResetStylesheetsToURI(nsIURI
     // filled the style set.  (This allows us to avoid calling
     // GetStyleBackendType() too early.)
     RemoveDocStyleSheetsFromStyleSets();
     RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets, SheetType::Agent);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], SheetType::Agent);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], SheetType::User);
     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], SheetType::Doc);
 
-    if (GetStyleBackendType() == StyleBackendType::Gecko) {
-      nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
-      if (sheetService) {
-        RemoveStyleSheetsFromStyleSets(*sheetService->AuthorStyleSheets(), SheetType::Doc);
-      }
-    } else {
-      NS_WARNING("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet");
+    if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
+      RemoveStyleSheetsFromStyleSets(
+        *sheetService->AuthorStyleSheets(GetStyleBackendType()), SheetType::Doc);
     }
 
     mStyleSetFilled = false;
   }
 
   // Release all the sheets
   mStyleSheets.Clear();
   mOnDemandBuiltInUASheets.Clear();
@@ -2355,33 +2351,29 @@ nsDocument::FillStyleSet(StyleSetHandle 
   MOZ_ASSERT(!mStyleSetFilled);
 
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
     if (sheet->IsApplicable()) {
       aStyleSet->AddDocStyleSheet(sheet, this);
     }
   }
 
-  if (aStyleSet->IsGecko()) {
-    nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
-    if (sheetService) {
-      for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
-        aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
-      }
-    }
-
-    // Iterate backwards to maintain order
-    for (StyleSheet* sheet : Reversed(mOnDemandBuiltInUASheets)) {
-      if (sheet->IsApplicable()) {
-        aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
-      }
-    }
-  } else {
-    NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed "
-               "documents. See bug 1290224");
+  if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
+    nsTArray<RefPtr<StyleSheet>>& sheets =
+      *sheetService->AuthorStyleSheets(aStyleSet->BackendType());
+    for (StyleSheet* sheet : sheets) {
+      aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
+    }
+  }
+
+  // Iterate backwards to maintain order
+  for (StyleSheet* sheet : Reversed(mOnDemandBuiltInUASheets)) {
+    if (sheet->IsApplicable()) {
+      aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
+    }
   }
 
   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
                          SheetType::Agent);
   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
                          SheetType::User);
   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
                          SheetType::Doc);
--- a/dom/base/nsIDocumentInlines.h
+++ b/dom/base/nsIDocumentInlines.h
@@ -38,17 +38,18 @@ nsIDocument::FindDocStyleSheetInsertionP
     mozilla::StyleSheet* sheetHandle = sheet;
 
     // 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();
+        auto& authorSheets =
+          *sheetService->AuthorStyleSheets(GetStyleBackendType());
         if (authorSheets.IndexOf(sheetHandle) != authorSheets.NoIndex) {
           break;
         }
       }
       if (sheetHandle == GetFirstAdditionalAuthorSheet()) {
         break;
       }
     }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2114,30 +2114,37 @@ ContentParent::InitInternal(ProcessPrior
       gpm->AddListener(this);
     }
   }
 
   nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
   if (sheetService) {
     // This looks like a lot of work, but in a normal browser session we just
     // send two loads.
-
-    for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
+    //
+    // The URIs of the Gecko and Servo sheets should be the same, so it
+    // shouldn't matter which we look at.  (The Servo sheets don't exist
+    // in non-MOZ-STYLO builds, though, so look at the Gecko ones.)
+
+    for (StyleSheet* sheet :
+           *sheetService->AgentStyleSheets(StyleBackendType::Gecko)) {
       URIParams uri;
       SerializeURI(sheet->GetSheetURI(), uri);
       Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
     }
 
-    for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
+    for (StyleSheet* sheet :
+           *sheetService->UserStyleSheets(StyleBackendType::Gecko)) {
       URIParams uri;
       SerializeURI(sheet->GetSheetURI(), uri);
       Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
     }
 
-    for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
+    for (StyleSheet* sheet :
+           *sheetService->AuthorStyleSheets(StyleBackendType::Gecko)) {
       URIParams uri;
       SerializeURI(sheet->GetSheetURI(), uri);
       Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
     }
   }
 
 #ifdef MOZ_CONTENT_SANDBOX
   bool shouldSandbox = true;
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -1472,35 +1472,31 @@ PresShell::RemovePreferenceStyles()
 {
   if (mPrefStyleSheet) {
     mStyleSet->RemoveStyleSheet(SheetType::User, mPrefStyleSheet);
     mPrefStyleSheet = nullptr;
   }
 }
 
 void
-PresShell::AddUserSheet(nsISupports* aSheet)
-{
-  if (mStyleSet->IsServo()) {
-    NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet");
-    return;
-  }
-
+PresShell::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, but before other user sheets; see nsIStyleSheetService.idl
   // for the ordering.  Just remove and readd all the nsStyleSheetService
   // sheets.
   nsCOMPtr<nsIStyleSheetService> dummy =
     do_GetService(NS_STYLESHEETSERVICE_CONTRACTID);
 
   mStyleSet->BeginUpdate();
 
   nsStyleSheetService* sheetService = nsStyleSheetService::gInstance;
-  nsTArray<RefPtr<StyleSheet>>& userSheets = *sheetService->UserStyleSheets();
+  nsTArray<RefPtr<StyleSheet>>& userSheets =
+    *sheetService->UserStyleSheets(mStyleSet->BackendType());
   // Iterate forwards when removing so the searches for RemoveStyleSheet are as
   // short as possible.
   for (StyleSheet* sheet : userSheets) {
     mStyleSet->RemoveStyleSheet(SheetType::User, sheet);
   }
 
   // Now iterate backwards, so that the order of userSheets will be the same as
   // the order of sheets from it in the style set.
@@ -1509,64 +1505,44 @@ PresShell::AddUserSheet(nsISupports* aSh
   }
 
   mStyleSet->EndUpdate();
 
   RestyleForCSSRuleChanges();
 }
 
 void
-PresShell::AddAgentSheet(nsISupports* aSheet)
+PresShell::AddAgentSheet(StyleSheet* aSheet)
 {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does
   // wrt ordering.
-  // XXXheycam This needs to work with ServoStyleSheets too.
-  RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
-  if (!sheet) {
-    NS_ERROR("stylo: AddAgentSheet needs to support ServoStyleSheets");
-    return;
-  }
-
-  mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+  mStyleSet->AppendStyleSheet(SheetType::Agent, aSheet);
   RestyleForCSSRuleChanges();
 }
 
 void
-PresShell::AddAuthorSheet(nsISupports* aSheet)
-{
-  // XXXheycam This needs to work with ServoStyleSheets too.
-  RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
-  if (!sheet) {
-    NS_ERROR("stylo: AddAuthorSheet needs to support ServoStyleSheets");
-    return;
-  }
-
+PresShell::AddAuthorSheet(StyleSheet* aSheet)
+{
   // Document specific "additional" Author sheets should be stronger than the
   // ones added with the StyleSheetService.
   StyleSheet* firstAuthorSheet =
     mDocument->GetFirstAdditionalAuthorSheet();
   if (firstAuthorSheet) {
-    mStyleSet->InsertStyleSheetBefore(SheetType::Doc, sheet, firstAuthorSheet);
+    mStyleSet->InsertStyleSheetBefore(SheetType::Doc, aSheet, firstAuthorSheet);
   } else {
-    mStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
+    mStyleSet->AppendStyleSheet(SheetType::Doc, aSheet);
   }
 
   RestyleForCSSRuleChanges();
 }
 
 void
-PresShell::RemoveSheet(SheetType aType, nsISupports* aSheet)
-{
-  RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
-  if (!sheet) {
-    NS_ERROR("stylo: RemoveSheet needs to support ServoStyleSheets");
-    return;
-  }
-
-  mStyleSet->RemoveStyleSheet(aType, sheet);
+PresShell::RemoveSheet(SheetType aType, StyleSheet* aSheet)
+{
+  mStyleSet->RemoveStyleSheet(aType, aSheet);
   RestyleForCSSRuleChanges();
 }
 
 NS_IMETHODIMP
 PresShell::SetDisplaySelection(int16_t aToggle)
 {
   mSelection->SetDisplaySelection(aToggle);
   return NS_OK;
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -563,20 +563,20 @@ protected:
                       const mozilla::LayoutDeviceIntPoint aPoint,
                       mozilla::LayoutDeviceIntRect* aScreenRect,
                       uint32_t aFlags);
 
   /**
    * Methods to handle changes to user and UA sheet lists that we get
    * notified about.
    */
-  void AddUserSheet(nsISupports* aSheet);
-  void AddAgentSheet(nsISupports* aSheet);
-  void AddAuthorSheet(nsISupports* aSheet);
-  void RemoveSheet(mozilla::SheetType aType, nsISupports* aSheet);
+  void AddUserSheet(StyleSheet* aSheet);
+  void AddAgentSheet(StyleSheet* aSheet);
+  void AddAuthorSheet(StyleSheet* aSheet);
+  void RemoveSheet(mozilla::SheetType aType, StyleSheet* aSheet);
 
   // Hide a view if it is a popup
   void HideViewIfPopup(nsView* aView);
 
   // Utility method to restore the root scrollframe state
   void RestoreRootScrollPosition();
 
   void MaybeReleaseCapturingContent();
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2398,29 +2398,25 @@ nsDocumentViewer::CreateStyleSet(nsIDocu
   } else {
     // SVG documents may have scrollbars and need the scrollbar styling.
     sheet = cache->MinimalXULSheet();
     if (sheet) {
       styleSet->PrependStyleSheet(SheetType::Agent, sheet);
     }
   }
 
-  if (styleSet->IsGecko()) {
-    nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
-    if (sheetService) {
-      for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
-        styleSet->AppendStyleSheet(SheetType::Agent, sheet);
-      }
-      for (StyleSheet* sheet : Reversed(*sheetService->UserStyleSheets())) {
-        styleSet->PrependStyleSheet(SheetType::User, sheet);
-      }
+  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
+  if (sheetService) {
+    for (StyleSheet* sheet : *sheetService->AgentStyleSheets(backendType)) {
+      styleSet->AppendStyleSheet(SheetType::Agent, sheet);
     }
-  } else {
-    NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed "
-               "documents. See bug 1290224");
+    for (StyleSheet* sheet :
+           Reversed(*sheetService->UserStyleSheets(backendType))) {
+      styleSet->PrependStyleSheet(SheetType::User, sheet);
+    }
   }
 
   // Caller will handle calling EndUpdate, per contract.
   return styleSet;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::ClearHistoryEntry()
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -77,26 +77,41 @@ nsStyleSheetService::RegisterFromEnumera
 
     nsCOMPtr<nsIURI> uri;
     NS_NewURI(getter_AddRefs(uri), spec);
     if (uri)
       LoadAndRegisterSheetInternal(uri, aSheetType);
   }
 }
 
+static bool
+SheetHasURI(StyleSheet* aSheet, nsIURI* aSheetURI)
+{
+  MOZ_ASSERT(aSheetURI);
+
+  bool result;
+  nsIURI* uri = aSheet->GetSheetURI();
+  return uri &&
+         NS_SUCCEEDED(uri->Equals(aSheetURI, &result)) &&
+         result;
+}
+
 int32_t
-nsStyleSheetService::FindSheetByURI(const nsTArray<RefPtr<StyleSheet>>& aSheets,
+nsStyleSheetService::FindSheetByURI(uint32_t aSheetType,
                                     nsIURI* aSheetURI)
 {
-  for (int32_t i = aSheets.Length() - 1; i >= 0; i-- ) {
-    bool bEqual;
-    nsIURI* uri = aSheets[i]->GetSheetURI();
-    if (uri
-        && NS_SUCCEEDED(uri->Equals(aSheetURI, &bEqual))
-        && bEqual) {
+  MOZ_ASSERT(mGeckoSheets[aSheetType].Length() ==
+               mServoSheets[aSheetType].Length());
+
+  SheetArray& sheets = mGeckoSheets[aSheetType];
+  for (int32_t i = sheets.Length() - 1; i >= 0; i-- ) {
+    if (SheetHasURI(sheets[i], aSheetURI)) {
+#ifdef MOZ_STYLO
+      MOZ_ASSERT(SheetHasURI(mServoSheets[aSheetType][i], aSheetURI));
+#endif
       return i;
     }
   }
 
   return -1;
 }
 
 nsresult
@@ -155,31 +170,32 @@ nsStyleSheetService::LoadAndRegisterShee
         u"the sheet, if it's a data URI.";
       consoleService->LogStringMessage(message);
     }
   }
 
   rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
   if (NS_SUCCEEDED(rv)) {
     // We're guaranteed that the new sheet is the last sheet in
-    // mSheets[aSheetType]
+    // m{Gecko,Servo}Sheets[aSheetType]
+
+    MOZ_ASSERT(mGeckoSheets[aSheetType].Length() ==
+                 mServoSheets[aSheetType].Length());
+
+    RefPtr<StyleSheet> geckoSheet = mGeckoSheets[aSheetType].LastElement();
+    RefPtr<StyleSheet> servoSheet = mServoSheets[aSheetType].LastElement();
 
-    // XXXheycam Once the nsStyleSheetService can hold ServoStyleSheets too,
-    // we'll need to include them in the notification.
-    RefPtr<StyleSheet> sheet = mSheets[aSheetType].LastElement();
-    if (sheet->IsGecko()) {
-      // Hold on to a copy of the registered PresShells.
-      nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
-      for (nsIPresShell* presShell : toNotify) {
-        if (presShell->StyleSet() && presShell->StyleSet()->IsGecko()) {
-          presShell->NotifyStyleSheetServiceSheetAdded(sheet, aSheetType);
-        }
+    // Hold on to a copy of the registered PresShells.
+    nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
+    for (nsIPresShell* presShell : toNotify) {
+      if (presShell->StyleSet()) {
+        StyleSheet* sheet = presShell->StyleSet()->IsGecko() ? geckoSheet
+                                                             : servoSheet;
+        presShell->NotifyStyleSheetServiceSheetAdded(sheet, aSheetType);
       }
-    } else {
-      NS_ERROR("stylo: can't notify observers of ServoStyleSheets");
     }
 
     if (XRE_IsParentProcess()) {
       nsTArray<dom::ContentParent*> children;
       dom::ContentParent::GetAll(children);
 
       if (children.IsEmpty()) {
         return rv;
@@ -191,16 +207,26 @@ nsStyleSheetService::LoadAndRegisterShee
       for (uint32_t i = 0; i < children.Length(); i++) {
         Unused << children[i]->SendLoadAndRegisterSheet(uri, aSheetType);
       }
     }
   }
   return rv;
 }
 
+static nsresult
+LoadSheet(nsIURI* aURI,
+          css::SheetParsingMode aParsingMode,
+          StyleBackendType aType,
+          RefPtr<StyleSheet>* aResult)
+{
+  RefPtr<css::Loader> loader = new css::Loader(aType);
+  return loader->LoadSheetSync(aURI, aParsingMode, true, aResult);
+}
+
 nsresult
 nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
                                                   uint32_t aSheetType)
 {
   NS_ENSURE_ARG_POINTER(aSheetURI);
 
   css::SheetParsingMode parsingMode;
   switch (aSheetType) {
@@ -216,40 +242,48 @@ nsStyleSheetService::LoadAndRegisterShee
       parsingMode = css::eAuthorSheetFeatures;
       break;
 
     default:
       NS_WARNING("invalid sheet type argument");
       return NS_ERROR_INVALID_ARG;
   }
 
-  // XXXheycam We'll need to load and register both a Gecko- and Servo-backed
-  // style sheet.
-  RefPtr<css::Loader> loader = new css::Loader(StyleBackendType::Gecko);
+  nsresult rv;
+
+  RefPtr<StyleSheet> geckoSheet;
+  RefPtr<StyleSheet> servoSheet;
+
+  rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Gecko, &geckoSheet);
+  NS_ENSURE_SUCCESS(rv, rv);
+  MOZ_ASSERT(geckoSheet);
 
-  RefPtr<StyleSheet> sheet;
-  nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
+#ifdef MOZ_STYLO
+  rv = LoadSheet(aSheetURI, parsingMode, StyleBackendType::Servo, &servoSheet);
   NS_ENSURE_SUCCESS(rv, rv);
+  MOZ_ASSERT(servoSheet);
+#endif
 
-  mSheets[aSheetType].AppendElement(sheet);
+  mGeckoSheets[aSheetType].AppendElement(geckoSheet);
+  mServoSheets[aSheetType].AppendElement(servoSheet);
 
-  return rv;
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStyleSheetService::SheetRegistered(nsIURI *sheetURI,
                                      uint32_t aSheetType, bool *_retval)
 {
   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
                 aSheetType == USER_SHEET ||
                 aSheetType == AUTHOR_SHEET);
   NS_ENSURE_ARG_POINTER(sheetURI);
   NS_PRECONDITION(_retval, "Null out param");
 
-  *_retval = (FindSheetByURI(mSheets[aSheetType], sheetURI) >= 0);
+  *_retval = (FindSheetByURI(aSheetType, sheetURI) >= 0);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStyleSheetService::PreloadSheet(nsIURI* aSheetURI, uint32_t aSheetType,
                                   nsIPreloadedStyleSheet** aSheet)
 {
@@ -289,33 +323,36 @@ nsStyleSheetService::PreloadSheet(nsIURI
 NS_IMETHODIMP
 nsStyleSheetService::UnregisterSheet(nsIURI *aSheetURI, uint32_t aSheetType)
 {
   NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
                 aSheetType == USER_SHEET ||
                 aSheetType == AUTHOR_SHEET);
   NS_ENSURE_ARG_POINTER(aSheetURI);
 
-  int32_t foundIndex = FindSheetByURI(mSheets[aSheetType], aSheetURI);
+  MOZ_ASSERT(mGeckoSheets[aSheetType].Length() ==
+               mServoSheets[aSheetType].Length());
+
+  int32_t foundIndex = FindSheetByURI(aSheetType, aSheetURI);
   NS_ENSURE_TRUE(foundIndex >= 0, NS_ERROR_INVALID_ARG);
-  RefPtr<StyleSheet> sheet = mSheets[aSheetType][foundIndex];
-  mSheets[aSheetType].RemoveElementAt(foundIndex);
+
+  RefPtr<StyleSheet> geckoSheet = mGeckoSheets[aSheetType][foundIndex];
+  RefPtr<StyleSheet> servoSheet = mServoSheets[aSheetType][foundIndex];
 
-  // XXXheycam Once the nsStyleSheetService can hold ServoStyleSheets too,
-  // we'll need to include them in the notification.
-  if (sheet->IsGecko()) {
-    // Hold on to a copy of the registered PresShells.
-    nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
-    for (nsIPresShell* presShell : toNotify) {
-      if (presShell->StyleSet() && presShell->StyleSet()->IsGecko()) {
-        presShell->NotifyStyleSheetServiceSheetRemoved(sheet, aSheetType);
-      }
+  mGeckoSheets[aSheetType].RemoveElementAt(foundIndex);
+  mServoSheets[aSheetType].RemoveElementAt(foundIndex);
+
+  // Hold on to a copy of the registered PresShells.
+  nsTArray<nsCOMPtr<nsIPresShell>> toNotify(mPresShells);
+  for (nsIPresShell* presShell : toNotify) {
+    if (presShell->StyleSet()) {
+      StyleSheet* sheet = presShell->StyleSet()->IsGecko() ? geckoSheet
+                                                           : servoSheet;
+      presShell->NotifyStyleSheetServiceSheetRemoved(sheet, aSheetType);
     }
-  } else {
-    NS_ERROR("stylo: can't notify observers of ServoStyleSheets");
   }
 
   if (XRE_IsParentProcess()) {
     nsTArray<dom::ContentParent*> children;
     dom::ContentParent::GetAll(children);
 
     if (children.IsEmpty()) {
       return NS_OK;
@@ -360,20 +397,24 @@ nsStyleSheetService::CollectReports(nsIH
 
   return NS_OK;
 }
 
 size_t
 nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
-  for (auto& sheetArray : mSheets) {
-    n += sheetArray.ShallowSizeOfExcludingThis(aMallocSizeOf);
-    for (StyleSheet* sheet : sheetArray) {
-      n += sheet->SizeOfIncludingThis(aMallocSizeOf);
+  for (auto* sheetArrays : { &mGeckoSheets, &mServoSheets }) {
+    for (auto& sheetArray : *sheetArrays) {
+      n += sheetArray.ShallowSizeOfExcludingThis(aMallocSizeOf);
+      for (StyleSheet* sheet : sheetArray) {
+        if (sheet) {
+          n += sheet->SizeOfIncludingThis(aMallocSizeOf);
+        }
+      }
     }
   }
   return n;
 }
 
 void
 nsStyleSheetService::RegisterPresShell(nsIPresShell* aPresShell)
 {
--- a/layout/base/nsStyleSheetService.h
+++ b/layout/base/nsStyleSheetService.h
@@ -8,16 +8,17 @@
 
 #ifndef nsStyleSheetService_h_
 #define nsStyleSheetService_h_
 
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsIStyleSheetService.h"
+#include "mozilla/Array.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/StyleSheet.h"
 
 class nsICategoryManager;
 class nsIMemoryReporter;
 class nsIPresShell;
 class nsISimpleEnumerator;
@@ -28,62 +29,70 @@ class nsISimpleEnumerator;
 
 #define NS_STYLESHEETSERVICE_CONTRACTID \
   "@mozilla.org/content/style-sheet-service;1"
 
 class nsStyleSheetService final
   : public nsIStyleSheetService
   , public nsIMemoryReporter
 {
- public:
+public:
+  typedef nsTArray<RefPtr<mozilla::StyleSheet>> SheetArray;
+
   nsStyleSheetService();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTYLESHEETSERVICE
   NS_DECL_NSIMEMORYREPORTER
 
   nsresult Init();
 
-  nsTArray<RefPtr<mozilla::StyleSheet>>* AgentStyleSheets()
+  SheetArray* AgentStyleSheets(mozilla::StyleBackendType aType)
   {
-    return &mSheets[AGENT_SHEET];
+    return &Sheets(aType)[AGENT_SHEET];
   }
-  nsTArray<RefPtr<mozilla::StyleSheet>>* UserStyleSheets()
+  SheetArray* UserStyleSheets(mozilla::StyleBackendType aType)
   {
-    return &mSheets[USER_SHEET];
+    return &Sheets(aType)[USER_SHEET];
   }
-  nsTArray<RefPtr<mozilla::StyleSheet>>* AuthorStyleSheets()
+  SheetArray* AuthorStyleSheets(mozilla::StyleBackendType aType)
   {
-    return &mSheets[AUTHOR_SHEET];
+    return &Sheets(aType)[AUTHOR_SHEET];
   }
 
   void RegisterPresShell(nsIPresShell* aPresShell);
   void UnregisterPresShell(nsIPresShell* aPresShell);
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   static nsStyleSheetService *GetInstance();
   static nsStyleSheetService *gInstance;
 
- private:
+private:
   ~nsStyleSheetService();
 
   void RegisterFromEnumerator(nsICategoryManager  *aManager,
                                           const char          *aCategory,
                                           nsISimpleEnumerator *aEnumerator,
                                           uint32_t             aSheetType);
 
-  int32_t FindSheetByURI(const nsTArray<RefPtr<mozilla::StyleSheet>>& aSheets,
-                         nsIURI* aSheetURI);
+  int32_t FindSheetByURI(uint32_t aSheetType, nsIURI* aSheetURI);
 
   // Like LoadAndRegisterSheet, but doesn't notify.  If successful, the
   // new sheet will be the last sheet in mSheets[aSheetType].
   nsresult LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
                                         uint32_t aSheetType);
 
-  nsTArray<RefPtr<mozilla::StyleSheet>> mSheets[3];
+  mozilla::Array<SheetArray, 3>& Sheets(mozilla::StyleBackendType aType)
+  {
+    return aType == mozilla::StyleBackendType::Gecko ? mGeckoSheets
+                                                     : mServoSheets;
+  }
+
+  mozilla::Array<SheetArray, 3> mGeckoSheets;
+  mozilla::Array<SheetArray, 3> mServoSheets;
 
   // Registered PresShells that will be notified when sheets are added and
   // removed from the style sheet service.
   nsTArray<nsCOMPtr<nsIPresShell>> mPresShells;
 };
 
 #endif
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -33,17 +33,16 @@ support-files =
   visited-lying-inner.html
   visited-pref-iframe.html
   xbl_bindings.xml
 
 [test_acid3_test46.html]
 [test_addSheet.html]
 support-files = additional_sheets_helper.html
 [test_additional_sheets.html]
-skip-if = stylo # bug 1337258
 support-files = additional_sheets_helper.html
 [test_align_justify_computed_values.html]
 [test_align_shorthand_serialization.html]
 skip-if = stylo # bug 1339656
 [test_all_shorthand.html]
 [test_animations.html]
 skip-if = (toolkit == 'android' || stylo) # bug 1339318 for stylo
 [test_animations_async_tests.html]
--- a/layout/style/test/stylo-failures.md
+++ b/layout/style/test/stylo-failures.md
@@ -565,16 +565,17 @@ Any line which doesn't follow the format
 * test_property_syntax_errors.html `'background'`: whether background shorthand should accept "text" [40]
 * test_inherit_computation.html `weight style`: whether font-synthesis should be reset by font w3c/csswg-drafts#1032 [8]
 
 ## Unknown / Unsure
 
 * border-width/padding failure
   * test_compute_data_with_start_struct.html `-width` [4]
   * ... `padding-` [4]
+* test_additional_sheets.html: one sub-test cascade order is wrong [1]
 * test_selectors.html `:nth-child`: &lt;an+b&gt; parsing difference [14]
 * test_selectors_on_anonymous_content.html: xbl and :nth-child [1]
 * test_variables.html `url`: url in custom property [1]
 * test_pseudoelement_state.html: doesn't seem to work at all, but only range-thumb fails... [4]
 
 ## Ignore
 
 * Ignore for now since should be mostly identical to test_value_storage.html