Bug 1304792: stylo: WIP implement @import. draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 17 Dec 2016 10:58:56 +0100
changeset 450613 e08073d52373a972ff45789985db2c2be8d84643
parent 450612 12842bada6e12b9f7a31d532c8edc11ef4983336
child 539808 69a9102efd34b5c09944e7a2d174db117217c556
push id38922
push userbmo:emilio+bugs@crisal.io
push dateSat, 17 Dec 2016 10:01:32 +0000
bugs1304792
milestone53.0a1
Bug 1304792: stylo: WIP implement @import.
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
servo/Cargo.lock
servo/components/style/build_gecko.rs
servo/components/style/gecko/conversions.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/gecko_bindings/structs_debug.rs
servo/components/style/gecko_bindings/structs_release.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/stylesheet_loader.rs
--- 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,36 @@ 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(aGeckoParentRule || aServoParentRule, "How did we get imported?");
+  if (aSheet->IsGecko()) {
+    MOZ_ASSERT(aGeckoParentRule, "Really?");
+    // 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 {
+    MOZ_ASSERT(aServoParentRule, "Really?");
+    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 +1770,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 +2193,51 @@ 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());
+
+#ifdef DEBUG
+  if (aParentSheet->IsGecko()) {
+    MOZ_ASSERT(aGeckoParentRule, "How did we get imported?");
+    MOZ_ASSERT(!aServoParentRule, "That makes no sense!");
+  } else {
+    MOZ_ASSERT(aServoParentRule, "How did we get imported?");
+    MOZ_ASSERT(!aGeckoParentRule, "That makes no sense!");
+  }
+#endif
+
   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): Fix GetParentSheet in ServoStyleSheets
+  if (aParentSheet->GetOwningDocument() && aParentSheet->IsGecko()) {
     StyleSheet* topSheet = aParentSheet;
     while (StyleSheet* parent = topSheet->GetParentSheet()) {
       topSheet = parent;
     }
     owningNode = topSheet->GetOwnerNode();
   }
 
   nsISupports* context = owningNode;
@@ -2259,34 +2278,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
@@ -288,17 +288,18 @@ public:
    * @param aRule the @import rule importing this child.  This is used to
    *              properly order the child sheet list of aParentSheet.
    * @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 +480,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)
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -7,23 +7,25 @@
 #include "mozilla/ServoBindings.h"
 
 #include "ChildIterator.h"
 #include "StyleStructContext.h"
 #include "gfxFontFamilyList.h"
 #include "nsAttrValueInlines.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsContentUtils.h"
+#include "nsCSSParser.h"
 #include "nsDOMTokenList.h"
 #include "nsIContentInlines.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPrincipal.h"
+#include "nsNetUtil.h"
 #include "nsNameSpaceManager.h"
 #include "nsRuleNode.h"
 #include "nsString.h"
 #include "nsStyleStruct.h"
 #include "nsStyleUtil.h"
 #include "nsTArray.h"
 
 #include "mozilla/EventStates.h"
@@ -1012,16 +1014,54 @@ 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): Pretty sure there's a way we can avoid the copy here, but
+    // this is going away soon anyway, when we can have a Servo-backed
+    // nsMediaList.
+    nsDependentCSubstring medium_(reinterpret_cast<const char*>(aMediaString),
+                                  aMediaStringLength);
+    nsString medium;
+    medium_.Assign(medium_);
+    nsCSSParser mediumParser(aLoader);
+    mediumParser.ParseMediaList(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;
@@ -89,16 +90,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,17 @@ 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) { 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
@@ -963,17 +963,23 @@ 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();
+    Loader* loader = nullptr;
+    if (nsIDocument* doc = servoSheet->GetOwningDocument()) {
+      loader = doc->CSSLoader();
+    }
+
+    nsresult rv = servoSheet->ParseSheet(loader, 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
 }
 
--- a/servo/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1409,17 +1409,17 @@ name = "leaky-cow"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "libbindgen"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "aster 0.34.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "clang-sys 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2724,17 +2724,17 @@ dependencies = [
  "encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever-atoms 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libbindgen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libbindgen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "nsstring_vendor 0.1.0",
  "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ordered-float 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -3413,17 +3413,17 @@ dependencies = [
 "checksum js 0.1.3 (git+https://github.com/servo/rust-mozjs)" = "<none>"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum khronos_api 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c9d3760673c427d46f91a0350f0a84a52e6bc5a84adf26dc610b6c52436630"
 "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
 "checksum lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "cf186d1a8aa5f5bee5fd662bc9c1b949e0259e1bcc379d1f006847b0080c7417"
 "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
 "checksum leak 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73"
 "checksum leaky-cow 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc"
-"checksum libbindgen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6a46e95efa501b2940e9c81dbb727e557b39b41f77f1170aba6eed5a546e9964"
+"checksum libbindgen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20ea25ae6facd261a97015162a91c707d948cb342599bd6c666f0ff9bf853d0b"
 "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
 "checksum libloading 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "eceb2637ee9a27c7f19764048a9f377e40e3a70a322722f348e6bc7704d565f2"
 "checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71"
 "checksum libz-sys 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "40f2df7730b5d29426c3e44ce4d088d8c5def6471c2c93ba98585b89fb201ce6"
 "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
 "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
 "checksum mac 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1b1db08c0d0ddbb591e65f1da58d1cefccc94a2faa0c55bf979ce215a3e04d5e"
 "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -217,16 +217,17 @@ mod bindings {
             "NS_STYLE_.*",
             "NS_CORNER_.*",
             "NS_RADIUS_.*",
             "BORDER_COLOR_.*",
             "BORDER_STYLE_.*"
         ];
         let whitelist = [
             "RawGecko.*",
+            "mozilla::ServoStyleSheet",
             "mozilla::ServoElementSnapshot.*",
             "mozilla::ConsumeStyleBehavior",
             "mozilla::LazyComputeBehavior",
             "mozilla::css::SheetParsingMode",
             "mozilla::TraversalRootBehavior",
             "mozilla::DisplayItemClip",  // Needed because bindgen generates
                                          // specialization tests for this even
                                          // though it shouldn't.
@@ -503,30 +504,33 @@ mod bindings {
             "nsStyleUnion",
             "nsStyleUnit",
             "nsStyleUserInterface",
             "nsStyleVariables",
             "nsStyleVisibility",
             "nsStyleXUL",
             "nscoord",
             "nsresult",
+            "Loader",
+            "ServoStyleSheet",
         ];
         struct ArrayType {
             cpp_type: &'static str,
             rust_type: &'static str
         }
         let array_types = [
             ArrayType { cpp_type: "uintptr_t", rust_type: "usize" },
         ];
         let servo_nullable_arc_types = [
             "ServoComputedValues",
             "ServoCssRules",
             "RawServoStyleSheet",
             "RawServoDeclarationBlock",
             "RawServoStyleRule",
+            "RawServoImportRule",
         ];
         struct ServoOwnedType {
             name: &'static str,
             opaque: bool,
         }
         let servo_owned_types = [
             ServoOwnedType { name: "RawServoStyleSet", opaque: true },
             ServoOwnedType { name: "StyleChildrenIterator", opaque: true },
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -6,25 +6,25 @@
 //! Ideally, it would be in geckolib itself, but coherence
 //! forces us to keep the traits and implementations here
 
 #![allow(unsafe_code)]
 
 use app_units::Au;
 use gecko::values::{convert_rgba_to_nscolor, StyleCoordHelpers};
 use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue};
-use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, RawServoStyleRule};
+use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, RawServoStyleRule, RawServoImportRule};
 use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules};
 use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage};
 use gecko_bindings::structs::nsresult;
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 use parking_lot::RwLock;
 use properties::{ComputedValues, PropertyDeclarationBlock};
-use stylesheets::{CssRules, RulesMutateError, Stylesheet, StyleRule};
+use stylesheets::{CssRules, RulesMutateError, Stylesheet, StyleRule, ImportRule};
 use values::computed::{CalcLengthOrPercentage, Gradient, Image, LengthOrPercentage, LengthOrPercentageOrAuto};
 
 unsafe impl HasFFI for Stylesheet {
     type FFIType = RawServoStyleSheet;
 }
 unsafe impl HasArcFFI for Stylesheet {}
 unsafe impl HasFFI for ComputedValues {
     type FFIType = ServoComputedValues;
@@ -41,16 +41,21 @@ unsafe impl HasFFI for RwLock<CssRules> 
 }
 unsafe impl HasArcFFI for RwLock<CssRules> {}
 
 unsafe impl HasFFI for RwLock<StyleRule> {
     type FFIType = RawServoStyleRule;
 }
 unsafe impl HasArcFFI for RwLock<StyleRule> {}
 
+unsafe impl HasFFI for RwLock<ImportRule> {
+    type FFIType = RawServoImportRule;
+}
+unsafe impl HasArcFFI for RwLock<ImportRule> {}
+
 impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
     fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
         let has_percentage = other.percentage.is_some();
         nsStyleCoord_CalcValue {
             mLength: other.length.0,
             mPercent: other.percentage.unwrap_or(0.0),
             mHasPercent: has_percentage,
         }
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -138,16 +138,18 @@ unsafe impl Sync for nsStyleVariables {}
 use gecko_bindings::structs::nsStyleVisibility;
 unsafe impl Send for nsStyleVisibility {}
 unsafe impl Sync for nsStyleVisibility {}
 use gecko_bindings::structs::nsStyleXUL;
 unsafe impl Send for nsStyleXUL {}
 unsafe impl Sync for nsStyleXUL {}
 use gecko_bindings::structs::nscoord;
 use gecko_bindings::structs::nsresult;
+use gecko_bindings::structs::Loader;
+use gecko_bindings::structs::ServoStyleSheet;
 pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>;
 pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoComputedValues>;
 pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;
 pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;
 enum ServoComputedValuesVoid { }
 pub struct ServoComputedValues(ServoComputedValuesVoid);
 pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoCssRules>;
 pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;
@@ -164,16 +166,21 @@ pub type RawServoDeclarationBlockBorrowe
 pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;
 enum RawServoDeclarationBlockVoid { }
 pub struct RawServoDeclarationBlock(RawServoDeclarationBlockVoid);
 pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoStyleRule>;
 pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;
 pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;
 enum RawServoStyleRuleVoid { }
 pub struct RawServoStyleRule(RawServoStyleRuleVoid);
+pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoImportRule>;
+pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule;
+pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>;
+enum RawServoImportRuleVoid { }
+pub struct RawServoImportRule(RawServoImportRuleVoid);
 pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
 pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
 pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;
 pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;
 pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;
 pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;
 enum RawServoStyleSetVoid { }
 pub struct RawServoStyleSet(RawServoStyleSetVoid);
@@ -232,16 +239,22 @@ extern "C" {
 }
 extern "C" {
     pub fn Servo_StyleRule_AddRef(ptr: RawServoStyleRuleBorrowed);
 }
 extern "C" {
     pub fn Servo_StyleRule_Release(ptr: RawServoStyleRuleBorrowed);
 }
 extern "C" {
+    pub fn Servo_ImportRule_AddRef(ptr: RawServoImportRuleBorrowed);
+}
+extern "C" {
+    pub fn Servo_ImportRule_Release(ptr: RawServoImportRuleBorrowed);
+}
+extern "C" {
     pub fn Servo_StyleSet_Drop(ptr: RawServoStyleSetOwned);
 }
 extern "C" {
     pub fn Gecko_EnsureTArrayCapacity(aArray: *mut ::std::os::raw::c_void,
                                       aCapacity: usize, aElementSize: usize);
 }
 extern "C" {
     pub fn Gecko_ClearPODTArray(aArray: *mut ::std::os::raw::c_void,
@@ -307,16 +320,23 @@ extern "C" {
     pub fn Gecko_GetNextSiblingElement(element: RawGeckoElementBorrowed)
      -> RawGeckoElementBorrowedOrNull;
 }
 extern "C" {
     pub fn Gecko_GetDocumentElement(document: RawGeckoDocumentBorrowed)
      -> RawGeckoElementBorrowedOrNull;
 }
 extern "C" {
+    pub fn Gecko_LoadStyleSheet(loader: *mut Loader,
+                                parent: *mut ServoStyleSheet,
+                                import_rule: RawServoImportRuleStrong,
+                                url_bytes: *const u8, url_length: u32,
+                                media_bytes: *const u8, media_length: u32);
+}
+extern "C" {
     pub fn Gecko_MaybeCreateStyleChildrenIterator(node: RawGeckoNodeBorrowed)
      -> StyleChildrenIteratorOwnedOrNull;
 }
 extern "C" {
     pub fn Gecko_DropStyleChildrenIterator(it: StyleChildrenIteratorOwned);
 }
 extern "C" {
     pub fn Gecko_GetNextStyleChild(it: StyleChildrenIteratorBorrowedMut)
@@ -962,27 +982,46 @@ extern "C" {
     pub fn Servo_Element_ShouldTraverse(node: RawGeckoElementBorrowed)
      -> bool;
 }
 extern "C" {
     pub fn Servo_StyleSheet_Empty(parsing_mode: SheetParsingMode)
      -> RawServoStyleSheetStrong;
 }
 extern "C" {
-    pub fn Servo_StyleSheet_FromUTF8Bytes(data: *const nsACString_internal,
+    pub fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
+                                          gecko_stylesheet:
+                                              *mut ServoStyleSheet,
+                                          data: *const nsACString_internal,
                                           parsing_mode: SheetParsingMode,
                                           base_url:
                                               *const nsACString_internal,
                                           base: *mut ThreadSafeURIHolder,
                                           referrer: *mut ThreadSafeURIHolder,
                                           principal:
                                               *mut ThreadSafePrincipalHolder)
      -> RawServoStyleSheetStrong;
 }
 extern "C" {
+    pub fn Servo_ImportRule_GetSheet(import_rule: RawServoImportRuleBorrowed)
+     -> RawServoStyleSheetStrong;
+}
+extern "C" {
+    pub fn Servo_StyleSheet_ClearAndUpdate(stylesheet:
+                                               RawServoStyleSheetBorrowed,
+                                           loader: *mut Loader,
+                                           gecko_stylesheet:
+                                               *mut ServoStyleSheet,
+                                           data: *const nsACString_internal,
+                                           base: *mut ThreadSafeURIHolder,
+                                           referrer: *mut ThreadSafeURIHolder,
+                                           principal:
+                                               *mut ThreadSafePrincipalHolder);
+}
+extern "C" {
     pub fn Servo_StyleSheet_HasRules(sheet: RawServoStyleSheetBorrowed)
      -> bool;
 }
 extern "C" {
     pub fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed)
      -> ServoCssRulesStrong;
 }
 extern "C" {
--- a/servo/components/style/gecko_bindings/structs_debug.rs
+++ b/servo/components/style/gecko_bindings/structs_debug.rs
@@ -1009,16 +1009,17 @@ pub mod root {
     pub const NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY: ::std::os::raw::c_uint = 2;
     pub const NS_STYLE_ORIENTATION_PORTRAIT: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_ORIENTATION_LANDSCAPE: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_SCAN_PROGRESSIVE: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_SCAN_INTERLACE: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_DISPLAY_MODE_BROWSER: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_DISPLAY_MODE_MINIMAL_UI: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_DISPLAY_MODE_STANDALONE: ::std::os::raw::c_uint = 2;
+    pub const NS_STYLE_DISPLAY_MODE_FULLSCREEN: ::std::os::raw::c_uint = 3;
     pub const NS_STYLE_INHERIT_MASK: ::std::os::raw::c_uint = 16777215;
     pub const NS_STYLE_HAS_TEXT_DECORATION_LINES: ::std::os::raw::c_uint =
         16777216;
     pub const NS_STYLE_HAS_PSEUDO_ELEMENT_DATA: ::std::os::raw::c_uint =
         33554432;
     pub const NS_STYLE_RELEVANT_LINK_VISITED: ::std::os::raw::c_uint =
         67108864;
     pub const NS_STYLE_IS_STYLE_IF_VISITED: ::std::os::raw::c_uint =
@@ -2366,16 +2367,24 @@ pub mod root {
             pub static mut StyleSheet__cycleCollectorGlobal:
                        root::mozilla::StyleSheet_cycleCollection;
         }
         #[test]
         fn bindgen_test_layout_StyleSheet() {
             assert_eq!(::std::mem::size_of::<StyleSheet>() , 88usize);
             assert_eq!(::std::mem::align_of::<StyleSheet>() , 8usize);
         }
+        #[repr(C)]
+        #[derive(Debug, Copy)]
+        pub struct ServoStyleSheet {
+            pub _address: u8,
+        }
+        impl Clone for ServoStyleSheet {
+            fn clone(&self) -> Self { *self }
+        }
         #[repr(u32)]
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub enum Side {
             eSideTop = 0,
             eSideRight = 1,
             eSideBottom = 2,
             eSideLeft = 3,
         }
@@ -8642,73 +8651,73 @@ pub mod root {
     #[repr(C)]
     #[derive(Debug, Copy)]
     pub struct nsDOMMutationObserver {
         pub _address: u8,
     }
     impl Clone for nsDOMMutationObserver {
         fn clone(&self) -> Self { *self }
     }
-    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_LISTENERMANAGER;
-    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_PROPERTIES;
-    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_IS_ANONYMOUS_ROOT;
-    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
-    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_IS_NATIVE_ANONYMOUS_ROOT;
-    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_FORCE_XBL_BINDINGS;
-    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_MAY_BE_IN_BINDING_MNGR;
-    pub const NODE_IS_EDITABLE: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_IS_EDITABLE;
-    pub const NODE_MAY_HAVE_CLASS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_MAY_HAVE_CLASS;
-    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_IS_IN_SHADOW_TREE;
-    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_EMPTY_SELECTOR;
-    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_SLOW_SELECTOR;
-    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_EDGE_CHILD_SELECTOR;
-    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
-    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_ALL_SELECTOR_FLAGS;
-    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_NEEDS_FRAME;
-    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_DESCENDANTS_NEED_FRAMES;
-    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_ACCESSKEY;
-    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_DIRECTION_RTL;
-    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_HAS_DIRECTION_LTR;
-    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_ALL_DIRECTION_FLAGS;
-    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_CHROME_ONLY_ACCESS;
-    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
-    pub const NODE_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_SHARED_RESTYLE_BIT_1;
-    pub const NODE_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_SHARED_RESTYLE_BIT_2;
-    pub const NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_SHARED_RESTYLE_BIT_1;
-    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_72 =
-        _bindgen_ty_72::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_LISTENERMANAGER;
+    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_PROPERTIES;
+    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_IS_ANONYMOUS_ROOT;
+    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_FORCE_XBL_BINDINGS;
+    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_MAY_BE_IN_BINDING_MNGR;
+    pub const NODE_IS_EDITABLE: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_IS_EDITABLE;
+    pub const NODE_MAY_HAVE_CLASS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_MAY_HAVE_CLASS;
+    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_IS_IN_SHADOW_TREE;
+    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_EMPTY_SELECTOR;
+    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_SLOW_SELECTOR;
+    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_EDGE_CHILD_SELECTOR;
+    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_ALL_SELECTOR_FLAGS;
+    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_NEEDS_FRAME;
+    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_DESCENDANTS_NEED_FRAMES;
+    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_ACCESSKEY;
+    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_DIRECTION_RTL;
+    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_HAS_DIRECTION_LTR;
+    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_ALL_DIRECTION_FLAGS;
+    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_CHROME_ONLY_ACCESS;
+    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+    pub const NODE_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_SHARED_RESTYLE_BIT_1;
+    pub const NODE_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_SHARED_RESTYLE_BIT_2;
+    pub const NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_SHARED_RESTYLE_BIT_1;
+    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_68 =
+        _bindgen_ty_68::NODE_TYPE_SPECIFIC_BITS_OFFSET;
     #[repr(u32)]
     #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-    pub enum _bindgen_ty_72 {
+    pub enum _bindgen_ty_68 {
         NODE_HAS_LISTENERMANAGER = 4,
         NODE_HAS_PROPERTIES = 8,
         NODE_IS_ANONYMOUS_ROOT = 16,
         NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = 32,
         NODE_IS_NATIVE_ANONYMOUS_ROOT = 64,
         NODE_FORCE_XBL_BINDINGS = 128,
         NODE_MAY_BE_IN_BINDING_MNGR = 256,
         NODE_IS_EDITABLE = 512,
--- a/servo/components/style/gecko_bindings/structs_release.rs
+++ b/servo/components/style/gecko_bindings/structs_release.rs
@@ -1009,16 +1009,17 @@ pub mod root {
     pub const NS_STYLE_SCROLL_SNAP_TYPE_PROXIMITY: ::std::os::raw::c_uint = 2;
     pub const NS_STYLE_ORIENTATION_PORTRAIT: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_ORIENTATION_LANDSCAPE: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_SCAN_PROGRESSIVE: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_SCAN_INTERLACE: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_DISPLAY_MODE_BROWSER: ::std::os::raw::c_uint = 0;
     pub const NS_STYLE_DISPLAY_MODE_MINIMAL_UI: ::std::os::raw::c_uint = 1;
     pub const NS_STYLE_DISPLAY_MODE_STANDALONE: ::std::os::raw::c_uint = 2;
+    pub const NS_STYLE_DISPLAY_MODE_FULLSCREEN: ::std::os::raw::c_uint = 3;
     pub const NS_STYLE_INHERIT_MASK: ::std::os::raw::c_uint = 16777215;
     pub const NS_STYLE_HAS_TEXT_DECORATION_LINES: ::std::os::raw::c_uint =
         16777216;
     pub const NS_STYLE_HAS_PSEUDO_ELEMENT_DATA: ::std::os::raw::c_uint =
         33554432;
     pub const NS_STYLE_RELEVANT_LINK_VISITED: ::std::os::raw::c_uint =
         67108864;
     pub const NS_STYLE_IS_STYLE_IF_VISITED: ::std::os::raw::c_uint =
@@ -2349,16 +2350,24 @@ pub mod root {
             pub static mut StyleSheet__cycleCollectorGlobal:
                        root::mozilla::StyleSheet_cycleCollection;
         }
         #[test]
         fn bindgen_test_layout_StyleSheet() {
             assert_eq!(::std::mem::size_of::<StyleSheet>() , 80usize);
             assert_eq!(::std::mem::align_of::<StyleSheet>() , 8usize);
         }
+        #[repr(C)]
+        #[derive(Debug, Copy)]
+        pub struct ServoStyleSheet {
+            pub _address: u8,
+        }
+        impl Clone for ServoStyleSheet {
+            fn clone(&self) -> Self { *self }
+        }
         #[repr(u32)]
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub enum Side {
             eSideTop = 0,
             eSideRight = 1,
             eSideBottom = 2,
             eSideLeft = 3,
         }
@@ -8579,73 +8588,73 @@ pub mod root {
     #[repr(C)]
     #[derive(Debug, Copy)]
     pub struct nsDOMMutationObserver {
         pub _address: u8,
     }
     impl Clone for nsDOMMutationObserver {
         fn clone(&self) -> Self { *self }
     }
-    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_LISTENERMANAGER;
-    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_PROPERTIES;
-    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_IS_ANONYMOUS_ROOT;
-    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
-    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_IS_NATIVE_ANONYMOUS_ROOT;
-    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_FORCE_XBL_BINDINGS;
-    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_MAY_BE_IN_BINDING_MNGR;
-    pub const NODE_IS_EDITABLE: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_IS_EDITABLE;
-    pub const NODE_MAY_HAVE_CLASS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_MAY_HAVE_CLASS;
-    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_IS_IN_SHADOW_TREE;
-    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_EMPTY_SELECTOR;
-    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_SLOW_SELECTOR;
-    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_EDGE_CHILD_SELECTOR;
-    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
-    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_ALL_SELECTOR_FLAGS;
-    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_NEEDS_FRAME;
-    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_DESCENDANTS_NEED_FRAMES;
-    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_ACCESSKEY;
-    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_DIRECTION_RTL;
-    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_HAS_DIRECTION_LTR;
-    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_ALL_DIRECTION_FLAGS;
-    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_CHROME_ONLY_ACCESS;
-    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
-    pub const NODE_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_SHARED_RESTYLE_BIT_1;
-    pub const NODE_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_SHARED_RESTYLE_BIT_2;
-    pub const NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_SHARED_RESTYLE_BIT_1;
-    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_66 =
-        _bindgen_ty_66::NODE_TYPE_SPECIFIC_BITS_OFFSET;
+    pub const NODE_HAS_LISTENERMANAGER: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_LISTENERMANAGER;
+    pub const NODE_HAS_PROPERTIES: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_PROPERTIES;
+    pub const NODE_IS_ANONYMOUS_ROOT: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_IS_ANONYMOUS_ROOT;
+    pub const NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
+    pub const NODE_IS_NATIVE_ANONYMOUS_ROOT: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_IS_NATIVE_ANONYMOUS_ROOT;
+    pub const NODE_FORCE_XBL_BINDINGS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_FORCE_XBL_BINDINGS;
+    pub const NODE_MAY_BE_IN_BINDING_MNGR: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_MAY_BE_IN_BINDING_MNGR;
+    pub const NODE_IS_EDITABLE: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_IS_EDITABLE;
+    pub const NODE_MAY_HAVE_CLASS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_MAY_HAVE_CLASS;
+    pub const NODE_IS_IN_SHADOW_TREE: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_IS_IN_SHADOW_TREE;
+    pub const NODE_HAS_EMPTY_SELECTOR: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_EMPTY_SELECTOR;
+    pub const NODE_HAS_SLOW_SELECTOR: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_SLOW_SELECTOR;
+    pub const NODE_HAS_EDGE_CHILD_SELECTOR: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_EDGE_CHILD_SELECTOR;
+    pub const NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
+    pub const NODE_ALL_SELECTOR_FLAGS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_ALL_SELECTOR_FLAGS;
+    pub const NODE_NEEDS_FRAME: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_NEEDS_FRAME;
+    pub const NODE_DESCENDANTS_NEED_FRAMES: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_DESCENDANTS_NEED_FRAMES;
+    pub const NODE_HAS_ACCESSKEY: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_ACCESSKEY;
+    pub const NODE_HAS_DIRECTION_RTL: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_DIRECTION_RTL;
+    pub const NODE_HAS_DIRECTION_LTR: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_HAS_DIRECTION_LTR;
+    pub const NODE_ALL_DIRECTION_FLAGS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_ALL_DIRECTION_FLAGS;
+    pub const NODE_CHROME_ONLY_ACCESS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_CHROME_ONLY_ACCESS;
+    pub const NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS;
+    pub const NODE_SHARED_RESTYLE_BIT_1: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_SHARED_RESTYLE_BIT_1;
+    pub const NODE_SHARED_RESTYLE_BIT_2: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_SHARED_RESTYLE_BIT_2;
+    pub const NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_SHARED_RESTYLE_BIT_1;
+    pub const NODE_TYPE_SPECIFIC_BITS_OFFSET: root::_bindgen_ty_62 =
+        _bindgen_ty_62::NODE_TYPE_SPECIFIC_BITS_OFFSET;
     #[repr(u32)]
     #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-    pub enum _bindgen_ty_66 {
+    pub enum _bindgen_ty_62 {
         NODE_HAS_LISTENERMANAGER = 4,
         NODE_HAS_PROPERTIES = 8,
         NODE_IS_ANONYMOUS_ROOT = 16,
         NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = 32,
         NODE_IS_NATIVE_ANONYMOUS_ROOT = 64,
         NODE_FORCE_XBL_BINDINGS = 128,
         NODE_MAY_BE_IN_BINDING_MNGR = 256,
         NODE_IS_EDITABLE = 512,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -30,36 +30,40 @@ use style::gecko::wrapper::GeckoElement;
 use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
 use style::gecko_bindings::bindings::{RawServoStyleRuleBorrowed, RawServoStyleRuleStrong};
 use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
 use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed};
 use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong};
 use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
 use style::gecko_bindings::bindings::{nsACString, nsAString};
 use style::gecko_bindings::bindings::RawGeckoElementBorrowed;
+use style::gecko_bindings::bindings::RawServoImportRuleBorrowed;
 use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
 use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t;
 use style::gecko_bindings::structs;
 use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom};
 use style::gecko_bindings::structs::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
 use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint};
+use style::gecko_bindings::structs::Loader;
+use style::gecko_bindings::structs::ServoStyleSheet;
 use style::gecko_bindings::structs::nsresult;
 use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI};
 use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
 use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
 use style::parallel;
 use style::parser::{ParserContext, ParserContextExtraData};
 use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration};
 use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock, PropertyId};
 use style::properties::{apply_declarations, parse_one_declaration};
 use style::restyle_hints::RestyleHint;
 use style::selector_parser::PseudoElementCascadeType;
 use style::sequential;
 use style::string_cache::Atom;
-use style::stylesheets::{CssRule, CssRules, Origin, Stylesheet, StyleRule};
+use style::stylesheets::{CssRule, CssRules, Origin, Stylesheet, StyleRule, ImportRule};
+use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::{recalc_style_at, DomTraversal, PerLevelTraversalData};
 use style_traits::ToCss;
 use stylesheet_loader::StylesheetLoader;
 
 /*
  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
@@ -227,27 +231,28 @@ pub extern "C" fn Servo_Element_ShouldTr
 pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetStrong {
     let url = ServoUrl::parse("about:blank").unwrap();
     let extra_data = ParserContextExtraData::default();
     let origin = match mode {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
     };
-    let loader = StylesheetLoader::new();
     let sheet = Arc::new(Stylesheet::from_str(
-        "", url, origin, Default::default(), Some(&loader),
+        "", url, origin, Default::default(), None,
         Box::new(StdoutErrorReporter), extra_data));
     unsafe {
         transmute(sheet)
     }
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(data: *const nsACString,
+pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
+                                                 stylesheet: *mut ServoStyleSheet,
+                                                 data: *const nsACString,
                                                  mode: SheetParsingMode,
                                                  base_url: *const nsACString,
                                                  base: *mut ThreadSafeURIHolder,
                                                  referrer: *mut ThreadSafeURIHolder,
                                                  principal: *mut ThreadSafePrincipalHolder)
                                                  -> RawServoStyleSheetStrong {
     let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
 
@@ -259,26 +264,72 @@ pub extern "C" fn Servo_StyleSheet_FromU
 
     let base_str = unsafe { base_url.as_ref().unwrap().as_str_unchecked() };
     let url = ServoUrl::parse(base_str).unwrap();
     let extra_data = unsafe { ParserContextExtraData {
         base: Some(GeckoArcURI::new(base)),
         referrer: Some(GeckoArcURI::new(referrer)),
         principal: Some(GeckoArcPrincipal::new(principal)),
     }};
-    let loader = StylesheetLoader::new();
+    let loader = if loader.is_null() {
+        None
+    } else {
+        Some(StylesheetLoader::new(loader, stylesheet))
+    };
+
+    // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
+    let loader: Option<&StyleStylesheetLoader> = match loader {
+        None => None,
+        Some(ref s) => Some(s),
+    };
+
     let sheet = Arc::new(Stylesheet::from_str(
-        input, url, origin, Default::default(), Some(&loader),
+        input, url, origin, Default::default(), loader,
         Box::new(StdoutErrorReporter), extra_data));
     unsafe {
         transmute(sheet)
     }
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheetBorrowed,
+                                                  loader: *mut Loader,
+                                                  gecko_stylesheet: *mut ServoStyleSheet,
+                                                  data: *const nsACString,
+                                                  base: *mut ThreadSafeURIHolder,
+                                                  referrer: *mut ThreadSafeURIHolder,
+                                                  principal: *mut ThreadSafePrincipalHolder)
+{
+    let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
+    let extra_data = unsafe { ParserContextExtraData {
+        base: Some(GeckoArcURI::new(base)),
+        referrer: Some(GeckoArcURI::new(referrer)),
+        principal: Some(GeckoArcPrincipal::new(principal)),
+    }};
+
+    let loader = if loader.is_null() {
+        None
+    } else {
+        Some(StylesheetLoader::new(loader, gecko_stylesheet))
+    };
+
+    // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
+    let loader: Option<&StyleStylesheetLoader> = match loader {
+        None => None,
+        Some(ref s) => Some(s),
+    };
+
+    let sheet = Stylesheet::as_arc(&stylesheet);
+    sheet.rules.write().0.clear();
+
+    Stylesheet::update_from_str(&sheet, input, loader,
+                                Box::new(StdoutErrorReporter), extra_data);
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed,
                                                   raw_sheet: RawServoStyleSheetBorrowed) {
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let sheet = HasArcFFI::as_arc(&raw_sheet);
     data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
     data.stylesheets.push(sheet.clone());
     data.stylesheets_changed = true;
 }
@@ -432,16 +483,26 @@ pub extern "C" fn Servo_StyleRule_GetCss
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
     let rule = RwLock::<StyleRule>::as_arc(&rule);
     rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_ImportRule_AddRef(rule: RawServoImportRuleBorrowed) -> () {
+    unsafe { RwLock::<ImportRule>::addref(rule) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_ImportRule_Release(rule: RawServoImportRuleBorrowed) -> () {
+    unsafe { RwLock::<ImportRule>::release(rule) };
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: ServoComputedValuesBorrowedOrNull,
                                                          pseudo_tag: *mut nsIAtom,
                                                          raw_data: RawServoStyleSetBorrowed)
      -> ServoComputedValuesStrong {
     // The stylist consumes stylesheets lazily.
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     data.flush_stylesheets();
 
@@ -776,16 +837,24 @@ pub extern "C" fn Servo_NoteExplicitHint
         restyle_data.hint.insert(&restyle_hint.into());
         restyle_data.damage |= damage;
     } else {
         debug!("(Element not styled, discarding hints)");
     }
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_ImportRule_GetSheet(import_rule:
+                                            RawServoImportRuleBorrowed)
+                                            -> RawServoStyleSheetStrong {
+    let import_rule = RwLock::<ImportRule>::as_arc(&import_rule);
+    unsafe { transmute(import_rule.read().stylesheet.clone()) }
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_CheckChangeHint(element: RawGeckoElementBorrowed) -> nsChangeHint
 {
     let element = GeckoElement(element);
     if element.get_data().is_none() {
         error!("Trying to get change hint from unstyled element");
         return nsChangeHint(0);
     }
 
--- a/servo/ports/geckolib/stylesheet_loader.rs
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -1,21 +1,46 @@
 /* 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/. */
 
 use parking_lot::RwLock;
+use std::mem;
 use std::sync::Arc;
+use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
+use style::gecko_bindings::structs::{Loader, ServoStyleSheet};
 use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader};
+use style_traits::ToCss;
 
-pub struct StylesheetLoader;
+pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet);
 
 impl StylesheetLoader {
-    pub fn new() -> Self {
-        StylesheetLoader
+    pub fn new(loader: *mut Loader, parent: *mut ServoStyleSheet) -> Self {
+        StylesheetLoader(loader, parent)
     }
 }
 
 impl StyleStylesheetLoader for StylesheetLoader {
-    fn request_stylesheet(&self, _import: &Arc<RwLock<ImportRule>>) {
-        // FIXME(emilio): Implement `@import` in stylo.
+    fn request_stylesheet(&self, import_rule: &Arc<RwLock<ImportRule>>) {
+        let import = import_rule.read();
+        let (spec_bytes, spec_len) = import.url.as_slice_components();
+
+        // TODO(emilio): We probably want to share media representation with
+        // Gecko in Stylo.
+        //
+        // This also allows us to get rid of a bunch of extra work to evaluate
+        // and ensure parity, and shouldn't be much Gecko work given we always
+        // evaluate them on the main thread.
+        //
+        // Meanwhile, this works.
+        let media = import.stylesheet.media.read().to_css_string();
+
+        unsafe {
+            Gecko_LoadStyleSheet(self.0,
+                                 self.1,
+                                 mem::transmute(import_rule.clone()),
+                                 spec_bytes,
+                                 spec_len as u32,
+                                 media.as_bytes().as_ptr(),
+                                 media.len() as u32);
+        }
     }
 }