servo: Merge #14793 - stylo: Support at-import (from emilio:stylo-at-import); r=heycam,Manishearth
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 30 Dec 2016 19:12:55 -0800
changeset 340451 0fdf16676d2756ffa2d54f5cbc7fd6cb752f1835
parent 340450 228278d0d319013c0ae6169ca1f3ccf8b8ca915a
child 340452 29665644bcb8aa09ca9ea4648caf97a677860d6a
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam, Manishearth
servo: Merge #14793 - stylo: Support at-import (from emilio:stylo-at-import); r=heycam,Manishearth Reviewed upstream by @heycam and @Manishearth in: https://bugzilla.mozilla.org/show_bug.cgi?id=1304792 Source-Repo: https://github.com/servo/servo Source-Revision: 569e61e7ff6231ff62b8dc402c3e33b6072af6d8
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/components/style/gecko_bindings/sugar/ownership.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/stylesheet_loader.rs
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -246,16 +246,17 @@ mod bindings {
             "NS_STYLE_.*",
             "NS_CORNER_.*",
             "NS_RADIUS_.*",
             "BORDER_COLOR_.*",
             "BORDER_STYLE_.*"
         ];
         let whitelist = [
             "RawGecko.*",
+            "mozilla::ServoStyleSheet",
             "mozilla::ServoElementSnapshot.*",
             "mozilla::ConsumeStyleBehavior",
             "mozilla::css::SheetParsingMode",
             "mozilla::TraversalRootBehavior",
             "mozilla::DisplayItemClip",  // Needed because bindgen generates
                                          // specialization tests for this even
                                          // though it shouldn't.
             "mozilla::StyleShapeRadius",
@@ -522,30 +523,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,
@@ -310,16 +323,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: RawServoImportRuleBorrowed,
+                                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)
@@ -965,27 +985,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
@@ -1000,16 +1000,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 =
@@ -2357,16 +2358,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,
         }
@@ -2588,17 +2597,17 @@ pub mod root {
         }
         impl Clone for FramePropertyDescriptorUntyped {
             fn clone(&self) -> Self { *self }
         }
         /**
  * The FramePropertyTable is optimized for storing 0 or 1 properties on
  * a given frame. Storing very large numbers of properties on a single
  * frame will not be efficient.
- * 
+ *
  * Property values are passed as void* but do not actually have to be
  * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to
  * store int32_t values. Null/zero values can be stored and retrieved.
  * Of course, the destructor function (if any) must handle such values
  * correctly.
  */
         #[repr(C)]
         #[derive(Debug)]
--- a/servo/components/style/gecko_bindings/structs_release.rs
+++ b/servo/components/style/gecko_bindings/structs_release.rs
@@ -1000,16 +1000,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 =
@@ -2340,16 +2341,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,
         }
@@ -2571,17 +2580,17 @@ pub mod root {
         }
         impl Clone for FramePropertyDescriptorUntyped {
             fn clone(&self) -> Self { *self }
         }
         /**
  * The FramePropertyTable is optimized for storing 0 or 1 properties on
  * a given frame. Storing very large numbers of properties on a single
  * frame will not be efficient.
- * 
+ *
  * Property values are passed as void* but do not actually have to be
  * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to
  * store int32_t values. Null/zero values can be stored and retrieved.
  * Of course, the destructor function (if any) must handle such values
  * correctly.
  */
         #[repr(C)]
         #[derive(Debug)]
--- a/servo/components/style/gecko_bindings/sugar/ownership.rs
+++ b/servo/components/style/gecko_bindings/sugar/ownership.rs
@@ -104,16 +104,22 @@ pub unsafe trait HasArcFFI : HasFFI {
     /// &GeckoType -> &Arc<ServoType>
     fn as_arc<'a>(ptr: &'a &Self::FFIType) -> &'a Arc<Self> {
         debug_assert!(!(ptr as *const _).is_null());
         unsafe {
             transmute::<&&Self::FFIType, &Arc<Self>>(ptr)
         }
     }
 
+    fn arc_as_borrowed<'a>(arc: &'a Arc<Self>) -> &'a &Self::FFIType {
+        unsafe {
+            transmute::<&Arc<Self>, &&Self::FFIType>(arc)
+        }
+    }
+
     #[inline]
     fn arc_from_borrowed<'a>(ptr: &'a Option<&Self::FFIType>) -> Option<&'a Arc<Self>> {
         unsafe {
             if let Some(ref reference) = *ptr {
                 Some(transmute::<&&Self::FFIType, &Arc<_>>(reference))
             } else {
                 None
             }
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -31,36 +31,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, nsCSSPropertyID};
 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::{resolve_style, DomTraversal};
 use style_traits::ToCss;
 use stylesheet_loader::StylesheetLoader;
 
 /*
  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
@@ -220,27 +224,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() };
 
@@ -252,26 +257,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,
                                                   flush: bool) {
     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;
@@ -453,16 +504,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 {
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let atom = Atom::from(pseudo_tag);
     let pseudo = PseudoElement::from_atom_unchecked(atom, /* anon_box = */ true);
 
@@ -828,16 +889,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,47 @@
 /* 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::sync::Arc;
+use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
+use style::gecko_bindings::structs::{Loader, ServoStyleSheet};
+use style::gecko_bindings::sugar::ownership::HasArcFFI;
 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()
+            .expect("Import only loads valid URLs");
+
+        // 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,
+                                 HasArcFFI::arc_as_borrowed(import_rule),
+                                 spec_bytes,
+                                 spec_len as u32,
+                                 media.as_bytes().as_ptr(),
+                                 media.len() as u32);
+        }
     }
 }