Bug 1304792: stylo: Implement @import. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 17 Dec 2016 10:58:56 +0100
changeset 327662 ab2e9b88f958292d03d5edd41442c61ecd81b5af
parent 327661 7947d53b3587e86934f37c41d11d89a97a6d39da
child 327663 82fe5697e8faa2d0702b8694ea4b8e588a9368c7
push id85241
push userecoal95@gmail.com
push dateFri, 30 Dec 2016 15:30:55 +0000
treeherdermozilla-inbound@82fe5697e8fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1304792
milestone53.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 1304792: stylo: Implement @import. r=heycam MozReview-Commit-ID: Hw1V66JxIBD Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
layout/style/Loader.cpp
layout/style/Loader.h
layout/style/ServoArcTypeList.h
layout/style/ServoBindingList.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoStyleSheet.cpp
layout/style/ServoStyleSheet.h
layout/style/nsCSSParser.cpp
layout/style/nsLayoutStylesheetCache.cpp
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -48,16 +48,17 @@
 #include "mozilla/css/ImportRule.h"
 #include "nsThreadUtils.h"
 #include "nsGkAtoms.h"
 #include "nsIThreadInternal.h"
 #include "nsINetworkPredictor.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/URL.h"
 #include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/ServoBindings.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/ConsoleReportCollector.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPrototypeCache.h"
 #endif
 
@@ -1400,35 +1401,35 @@ Loader::InsertSheetInDoc(StyleSheet* aSh
  * to put it anyway.  So just append for now.  (In the future if we
  * want to insert the sheet at the correct position, we'll need to
  * restore CSSStyleSheet::InsertStyleSheetAt, which was removed in
  * bug 1220506.)
  */
 nsresult
 Loader::InsertChildSheet(StyleSheet* aSheet,
                          StyleSheet* aParentSheet,
-                         ImportRule* aParentRule)
+                         ImportRule* aGeckoParentRule,
+                         RawServoImportRule* aServoParentRule)
 {
   LOG(("css::Loader::InsertChildSheet"));
-  NS_PRECONDITION(aSheet, "Nothing to insert");
-  NS_PRECONDITION(aParentSheet, "Need a parent to insert into");
-  NS_PRECONDITION(aParentSheet, "How did we get imported?");
-
-  // XXXheycam The InsertChildSheet API doesn't work with ServoStyleSheets,
-  // since they won't have Gecko ImportRules in them.
-  if (aSheet->IsServo()) {
-    return NS_ERROR_FAILURE;
+  MOZ_ASSERT(aSheet, "Nothing to insert");
+  MOZ_ASSERT(aParentSheet, "Need a parent to insert into");
+  MOZ_ASSERT_IF(aSheet->IsGecko(), aGeckoParentRule && !aServoParentRule);
+  MOZ_ASSERT_IF(aSheet->IsServo(), aServoParentRule && !aGeckoParentRule);
+  if (aSheet->IsGecko()) {
+    // child sheets should always start out enabled, even if they got
+    // cloned off of top-level sheets which were disabled
+    aSheet->AsGecko()->SetEnabled(true);
+    aGeckoParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
+  } else {
+    RefPtr<RawServoStyleSheet> sheet =
+      Servo_ImportRule_GetSheet(aServoParentRule).Consume();
+    aSheet->AsServo()->SetSheetForImport(sheet);
   }
-
-  // child sheets should always start out enabled, even if they got
-  // cloned off of top-level sheets which were disabled
-  aSheet->AsGecko()->SetEnabled(true);
-
   aParentSheet->AppendStyleSheet(aSheet);
-  aParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
 
   LOG(("  Inserting into parent sheet"));
   return NS_OK;
 }
 
 /**
  * LoadSheet handles the actual load of a sheet.  If the load is
  * supposed to be synchronous it just opens a channel synchronously
@@ -1768,17 +1769,18 @@ Loader::ParseSheet(const nsAString& aInp
 
   if (aLoadData->mSheet->IsGecko()) {
     nsCSSParser parser(this, aLoadData->mSheet->AsGecko());
     rv = parser.ParseSheet(aInput, sheetURI, baseURI,
                            aLoadData->mSheet->Principal(),
                            aLoadData->mLineNumber);
   } else {
     rv =
-      aLoadData->mSheet->AsServo()->ParseSheet(aInput, sheetURI, baseURI,
+      aLoadData->mSheet->AsServo()->ParseSheet(this,
+                                               aInput, sheetURI, baseURI,
                                                aLoadData->mSheet->Principal(),
                                                aLoadData->mLineNumber);
   }
 
   mParsingDatas.RemoveElementAt(mParsingDatas.Length() - 1);
 
   if (NS_FAILED(rv)) {
     LOG_ERROR(("  Low-level error in parser!"));
@@ -2190,35 +2192,45 @@ HaveAncestorDataWithURI(SheetLoadData *a
 
   return false;
 }
 
 nsresult
 Loader::LoadChildSheet(StyleSheet* aParentSheet,
                        nsIURI* aURL,
                        nsMediaList* aMedia,
-                       ImportRule* aParentRule,
+                       ImportRule* aGeckoParentRule,
+                       RawServoImportRule* aServoParentRule,
                        LoaderReusableStyleSheets* aReusableSheets)
 {
   LOG(("css::Loader::LoadChildSheet"));
   NS_PRECONDITION(aURL, "Must have a URI to load");
   NS_PRECONDITION(aParentSheet, "Must have a parent sheet");
 
+  // Servo doesn't support reusable sheets.
+  MOZ_ASSERT_IF(aReusableSheets, aParentSheet->IsGecko());
+  MOZ_ASSERT_IF(aParentSheet->IsGecko(), aGeckoParentRule && !aServoParentRule);
+  MOZ_ASSERT_IF(aParentSheet->IsServo(), aServoParentRule && !aGeckoParentRule);
+
   if (!mEnabled) {
     LOG_WARN(("  Not enabled"));
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   LOG_URI("  Child uri: '%s'", aURL);
 
   nsCOMPtr<nsINode> owningNode;
 
   // check for an owning document: if none, don't bother walking up the parent
   // sheets
-  if (aParentSheet->GetOwningDocument()) {
+  //
+  // FIXME(emilio): Figure out whether this walk up is necessary (try seems
+  // green without it), and fix the parenting of stylesheets in the servo case
+  // if that's the case.
+  if (aParentSheet->GetOwningDocument() && aParentSheet->IsGecko()) {
     StyleSheet* topSheet = aParentSheet;
     while (StyleSheet* parent = topSheet->GetParentSheet()) {
       topSheet = parent;
     }
     owningNode = topSheet->GetOwnerNode();
   }
 
   nsISupports* context = owningNode;
@@ -2259,34 +2271,35 @@ Loader::LoadChildSheet(StyleSheet* aPare
 
   // Now that we know it's safe to load this (passes security check and not a
   // loop) do so.
   RefPtr<StyleSheet> sheet;
   RefPtr<CSSStyleSheet> reusableSheet;
   StyleSheetState state;
   if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, reusableSheet)) {
     sheet = reusableSheet;
-    aParentRule->SetSheet(reusableSheet);
+    aGeckoParentRule->SetSheet(reusableSheet);
     state = eSheetComplete;
   } else {
     bool isAlternate;
     const nsSubstring& empty = EmptyString();
     // For now, use CORS_NONE for child sheets
     rv = CreateSheet(aURL, nullptr, principal,
                      aParentSheet->ParsingMode(),
                      CORS_NONE, aParentSheet->GetReferrerPolicy(),
                      EmptyString(), // integrity is only checked on main sheet
                      parentData ? parentData->mSyncLoad : false,
                      false, empty, state, &isAlternate, &sheet);
     NS_ENSURE_SUCCESS(rv, rv);
 
     PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
   }
 
-  rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
+  rv = InsertChildSheet(sheet, aParentSheet, aGeckoParentRule,
+                        aServoParentRule);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete"));
     // We're completely done.  No need to notify, even, since the
     // @import rule addition/modification will trigger the right style
     // changes automatically.
     return NS_OK;
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -280,25 +280,29 @@ public:
    * complete aParentSheet will be QIed to nsICSSLoaderObserver and
    * asynchronously notified, just like for LoadStyleLink.  Note that if the
    * child sheet is already complete when this method returns, no
    * nsICSSLoaderObserver notification will be sent.
    *
    * @param aParentSheet the parent of this child sheet
    * @param aURL the URL of the child sheet
    * @param aMedia the already-parsed media list for the child sheet
-   * @param aRule the @import rule importing this child.  This is used to
-   *              properly order the child sheet list of aParentSheet.
+   * @param aGeckoParentRule the @import rule importing this child, when using
+   *                         Gecko's style system. This is used to properly
+   *                         order the child sheet list of aParentSheet.
+   * @param aServoParentRule the @import rule importing this child, when using
+   *                         Servo's style system.
    * @param aSavedSheets any saved style sheets which could be reused
    *              for this load
    */
   nsresult LoadChildSheet(StyleSheet* aParentSheet,
                           nsIURI* aURL,
                           nsMediaList* aMedia,
-                          ImportRule* aRule,
+                          ImportRule* aGeckoParentRule,
+                          RawServoImportRule* aServoParentRule,
                           LoaderReusableStyleSheets* aSavedSheets);
 
   /**
    * Synchronously load and return the stylesheet at aURL.  Any child sheets
    * will also be loaded synchronously.  Note that synchronous loads over some
    * protocols may involve spinning up a new event loop, so use of this method
    * does NOT guarantee not receiving any events before the sheet loads.  This
    * method can be used to load sheets not associated with a document.
@@ -479,17 +483,18 @@ private:
                     bool isAlternate);
 
   nsresult InsertSheetInDoc(StyleSheet* aSheet,
                             nsIContent* aLinkingContent,
                             nsIDocument* aDocument);
 
   nsresult InsertChildSheet(StyleSheet* aSheet,
                             StyleSheet* aParentSheet,
-                            ImportRule* aParentRule);
+                            ImportRule* aGeckoParentRule,
+                            RawServoImportRule* aServoParentRule);
 
   nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
                                         bool aIsPreload,
                                         SheetParsingMode aParsingMode,
                                         bool aUseSystemPrincipal,
                                         nsIPrincipal* aOriginPrincipal,
                                         const nsCString& aCharset,
                                         RefPtr<StyleSheet>* aSheet,
--- a/layout/style/ServoArcTypeList.h
+++ b/layout/style/ServoArcTypeList.h
@@ -6,8 +6,9 @@
 
 /* a list of all Servo Arc types used in stylo bindings for preprocessing */
 
 SERVO_ARC_TYPE(CssRules, ServoCssRules)
 SERVO_ARC_TYPE(StyleSheet, RawServoStyleSheet)
 SERVO_ARC_TYPE(ComputedValues, ServoComputedValues)
 SERVO_ARC_TYPE(DeclarationBlock, RawServoDeclarationBlock)
 SERVO_ARC_TYPE(StyleRule, RawServoStyleRule)
+SERVO_ARC_TYPE(ImportRule, RawServoImportRule)
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -21,22 +21,36 @@
 // Element data
 SERVO_BINDING_FUNC(Servo_Element_ClearData, void, RawGeckoElementBorrowed node)
 SERVO_BINDING_FUNC(Servo_Element_ShouldTraverse, bool, RawGeckoElementBorrowed node)
 
 // Styleset and Stylesheet management
 SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetStrong,
                    mozilla::css::SheetParsingMode parsing_mode)
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
+                   mozilla::css::Loader* loader,
+                   mozilla::ServoStyleSheet* gecko_stylesheet,
                    const nsACString* data,
                    mozilla::css::SheetParsingMode parsing_mode,
                    const nsACString* base_url,
                    ThreadSafeURIHolder* base,
                    ThreadSafeURIHolder* referrer,
                    ThreadSafePrincipalHolder* principal)
+SERVO_BINDING_FUNC(Servo_ImportRule_GetSheet,
+                   RawServoStyleSheetStrong,
+                   const RawServoImportRuleBorrowed import_rule)
+SERVO_BINDING_FUNC(Servo_StyleSheet_ClearAndUpdate,
+                   void,
+                   RawServoStyleSheetBorrowed stylesheet,
+                   mozilla::css::Loader* loader,
+                   mozilla::ServoStyleSheet* gecko_stylesheet,
+                   const nsACString* data,
+                   ThreadSafeURIHolder* base,
+                   ThreadSafeURIHolder* referrer,
+                   ThreadSafePrincipalHolder* principal)
 SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned)
 SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
 SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void,
                    RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet, bool flush)
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -5,26 +5,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoBindings.h"
 
 #include "ChildIterator.h"
 #include "StyleStructContext.h"
 #include "gfxFontFamilyList.h"
 #include "nsAttrValueInlines.h"
+#include "nsCSSParser.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsContentUtils.h"
 #include "nsDOMTokenList.h"
 #include "nsIContentInlines.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPrincipal.h"
 #include "nsNameSpaceManager.h"
+#include "nsNetUtil.h"
 #include "nsRuleNode.h"
 #include "nsString.h"
 #include "nsStyleStruct.h"
 #include "nsStyleUtil.h"
 #include "nsTArray.h"
 
 #include "mozilla/EventStates.h"
 #include "mozilla/ServoElementSnapshot.h"
@@ -1022,16 +1024,51 @@ Gecko_CSSValue_SetFunction(nsCSSValueBor
 }
 
 nsCSSValueBorrowedMut
 Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut aCSSValue, int32_t aIndex)
 {
   return &aCSSValue->GetArrayValue()->Item(aIndex);
 }
 
+void
+Gecko_LoadStyleSheet(css::Loader* aLoader,
+                     ServoStyleSheet* aParent,
+                     RawServoImportRuleStrong aImportRule,
+                     const uint8_t* aURLString,
+                     uint32_t aURLStringLength,
+                     const uint8_t* aMediaString,
+                     uint32_t aMediaStringLength)
+{
+  MOZ_ASSERT(aLoader, "Should've catched this before");
+  MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
+  MOZ_ASSERT(aURLString, "Invalid URLs shouldn't be loaded!");
+  RefPtr<nsMediaList> media = new nsMediaList();
+  if (aMediaStringLength) {
+    MOZ_ASSERT(aMediaString);
+    // TODO(emilio, bug 1325878): This is not great, though this is going away
+    // soon anyway, when we can have a Servo-backed nsMediaList.
+    nsDependentCSubstring medium(reinterpret_cast<const char*>(aMediaString),
+                                 aMediaStringLength);
+    nsCSSParser mediumParser(aLoader);
+    mediumParser.ParseMediaList(
+        NS_ConvertUTF8toUTF16(medium), nullptr, 0, media);
+  }
+
+  nsDependentCSubstring urlSpec(reinterpret_cast<const char*>(aURLString),
+                                aURLStringLength);
+
+  // Servo's loader guarantees that the URL is valid.
+  nsCOMPtr<nsIURI> uri;
+  MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), urlSpec));
+
+  RefPtr<RawServoImportRule> import = aImportRule.Consume();
+  aLoader->LoadChildSheet(aParent, uri, media, nullptr, import, nullptr);
+}
+
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
 
 #define STYLE_STRUCT(name, checkdata_cb)                                      \
                                                                               \
 void                                                                          \
 Gecko_Construct_nsStyle##name(nsStyle##name* ptr)                             \
 {                                                                             \
   new (ptr) nsStyle##name(StyleStructContext::ServoContext());                \
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -24,16 +24,17 @@
  * Functions beginning with Servo_ are implemented in Servo and invoked from Gecko.
  */
 
 class nsIAtom;
 class nsIPrincipal;
 class nsIURI;
 struct nsFont;
 namespace mozilla {
+  class ServoStyleSheet;
   class FontFamilyList;
   enum FontFamilyType : uint32_t;
 }
 using mozilla::FontFamilyList;
 using mozilla::FontFamilyType;
 using mozilla::ServoElementSnapshot;
 struct nsStyleList;
 struct nsStyleImage;
@@ -90,16 +91,23 @@ RawGeckoNodeBorrowedOrNull Gecko_GetLast
 RawGeckoNodeBorrowedOrNull Gecko_GetPrevSibling(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetNextSibling(RawGeckoNodeBorrowed node);
 RawGeckoElementBorrowedOrNull Gecko_GetParentElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetFirstChildElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetPrevSiblingElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetNextSiblingElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetDocumentElement(RawGeckoDocumentBorrowed document);
+void Gecko_LoadStyleSheet(mozilla::css::Loader* loader,
+                          mozilla::ServoStyleSheet* parent,
+                          RawServoImportRuleStrong import_rule,
+                          const uint8_t* url_bytes,
+                          uint32_t url_length,
+                          const uint8_t* media_bytes,
+                          uint32_t media_length);
 
 // By default, Servo walks the DOM by traversing the siblings of the DOM-view
 // first child. This generally works, but misses anonymous children, which we
 // want to traverse during styling. To support these cases, we create an
 // optional heap-allocated iterator for nodes that need it. If the creation
 // method returns null, Servo falls back to the aforementioned simpler (and
 // faster) sibling traversal.
 StyleChildrenIteratorOwnedOrNull Gecko_MaybeCreateStyleChildrenIterator(RawGeckoNodeBorrowed node);
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -57,43 +57,46 @@ ServoStyleSheet::GetParentSheet() const
   // to fix SetOwningDocument to propagate the owning document down
   // to the children.
   MOZ_CRASH("stylo: not implemented");
 }
 
 void
 ServoStyleSheet::AppendStyleSheet(ServoStyleSheet* aSheet)
 {
-  // XXXheycam: When we implement support for child sheets, we'll have
-  // to fix SetOwningDocument to propagate the owning document down
-  // to the children.
-  MOZ_CRASH("stylo: not implemented");
+  aSheet->mDocument = mDocument;
 }
 
 nsresult
-ServoStyleSheet::ParseSheet(const nsAString& aInput,
+ServoStyleSheet::ParseSheet(css::Loader* aLoader,
+                            const nsAString& aInput,
                             nsIURI* aSheetURI,
                             nsIURI* aBaseURI,
                             nsIPrincipal* aSheetPrincipal,
                             uint32_t aLineNumber)
 {
-  DropSheet();
-
   RefPtr<ThreadSafeURIHolder> base = new ThreadSafeURIHolder(aBaseURI);
   RefPtr<ThreadSafeURIHolder> referrer = new ThreadSafeURIHolder(aSheetURI);
   RefPtr<ThreadSafePrincipalHolder> principal =
     new ThreadSafePrincipalHolder(aSheetPrincipal);
 
   nsCString baseString;
   nsresult rv = aBaseURI->GetSpec(baseString);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF16toUTF8 input(aInput);
-  mSheet = Servo_StyleSheet_FromUTF8Bytes(&input, mParsingMode, &baseString,
-                                          base, referrer, principal).Consume();
+  if (!mSheet) {
+    mSheet =
+      Servo_StyleSheet_FromUTF8Bytes(aLoader, this, &input, mParsingMode,
+                                     &baseString, base, referrer,
+                                     principal).Consume();
+  } else {
+    Servo_StyleSheet_ClearAndUpdate(mSheet, aLoader, this, &input, base,
+                                    referrer, principal);
+  }
 
   return NS_OK;
 }
 
 void
 ServoStyleSheet::LoadFailed()
 {
   mSheet = Servo_StyleSheet_Empty(mParsingMode).Consume();
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -13,16 +13,20 @@
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInfo.h"
 #include "nsStringFwd.h"
 
 namespace mozilla {
 
 class ServoCSSRuleList;
 
+namespace css {
+class Loader;
+}
+
 /**
  * CSS style sheet object that is a wrapper for a Servo Stylesheet.
  */
 class ServoStyleSheet : public StyleSheet
 {
 public:
   ServoStyleSheet(css::SheetParsingMode aParsingMode,
                   CORSMode aCORSMode,
@@ -31,17 +35,18 @@ public:
 
   bool HasRules() const;
 
   void SetOwningDocument(nsIDocument* aDocument);
 
   ServoStyleSheet* GetParentSheet() const;
   void AppendStyleSheet(ServoStyleSheet* aSheet);
 
-  MOZ_MUST_USE nsresult ParseSheet(const nsAString& aInput,
+  MOZ_MUST_USE nsresult ParseSheet(css::Loader* aLoader,
+                                   const nsAString& aInput,
                                    nsIURI* aSheetURI,
                                    nsIURI* aBaseURI,
                                    nsIPrincipal* aSheetPrincipal,
                                    uint32_t aLineNumber);
 
   /**
    * Called instead of ParseSheet to initialize the Servo stylesheet object
    * for a failed load. Either ParseSheet or LoadFailed must be called before
@@ -51,16 +56,20 @@ public:
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
 #ifdef DEBUG
   void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
 #endif
 
   RawServoStyleSheet* RawSheet() const { return mSheet; }
+  void SetSheetForImport(RawServoStyleSheet* aSheet) {
+    MOZ_ASSERT(!mSheet);
+    mSheet = aSheet;
+  }
 
   // WebIDL StyleSheet API
   nsMediaList* Media() final;
 
   // WebIDL CSSStyleSheet API
   // Can't be inline because we can't include ImportRule here.  And can't be
   // called GetOwnerRule because that would be ambiguous with the ImportRule
   // version.
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -3810,17 +3810,19 @@ CSSParserImpl::ProcessImport(const nsStr
       // import url is bad
       REPORT_UNEXPECTED_P(PEImportBadURI, aURLSpec);
       OUTPUT_ERROR();
     }
     return;
   }
 
   if (mChildLoader) {
-    mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule, mReusableSheets);
+    mChildLoader->LoadChildSheet(mSheet, url, aMedia, rule,
+                                 /* aServoParentRule = */ nullptr,
+                                 mReusableSheets);
   }
 }
 
 // Parse the {} part of an @media or @-moz-document rule.
 bool
 CSSParserImpl::ParseGroupRule(css::GroupRule* aRule,
                               RuleAppendFunc aAppendFunc,
                               void* aData)
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -966,17 +966,20 @@ nsLayoutStylesheetCache::BuildPreference
 
   NS_ASSERTION(sheetText.Length() <= kPreallocSize,
                "kPreallocSize should be big enough to build preference style "
                "sheet without reallocation");
 
   if (sheet->IsGecko()) {
     sheet->AsGecko()->ReparseSheet(sheetText);
   } else {
-    nsresult rv = sheet->AsServo()->ParseSheet(sheetText, uri, uri, nullptr, 0);
+    ServoStyleSheet* servoSheet = sheet->AsServo();
+    // NB: The pref sheet never has @import rules.
+    nsresult rv =
+      servoSheet->ParseSheet(nullptr, sheetText, uri, uri, nullptr, 0);
     // Parsing the about:PreferenceStyleSheet URI can only fail on OOM. If we
     // are OOM before we parsed any documents we might as well abort.
     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   }
 
 #undef NS_GET_R_G_B
 }