Bug 1470145: Better debugging for stylesheets and URLs. r=xidorn
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 21 Jun 2018 13:09:35 +0200
changeset 477526 a1eb2582c7d29e2d6182e7eadaec56a91d6fe4ff
parent 477525 b67973aeb2af232a387f926e0103a140c98f8865
child 477527 1440edb27dc4460e268387c57459506dbcbfe256
push id9385
push userdluca@mozilla.com
push dateFri, 22 Jun 2018 15:47:18 +0000
treeherdermozilla-beta@82a9a1027e2b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersxidorn
bugs1470145
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1470145: Better debugging for stylesheets and URLs. r=xidorn MozReview-Commit-ID: FIcz2K1ZYX0
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/error_reporting.rs
servo/components/style/gecko/data.rs
servo/components/style/gecko/url.rs
servo/components/style/gecko_bindings/sugar/refptr.rs
servo/components/style/stylesheets/mod.rs
servo/components/style/stylesheets/stylesheet.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/stylesheet_loader.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2142,16 +2142,25 @@ Gecko_GetComputedURLSpec(const URLValueD
     if (NS_SUCCEEDED(rv)) {
       return;
     }
   }
 
   aOut->AssignLiteral("about:invalid");
 }
 
+void
+Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut)
+{
+  // TODO(emilio): Do we have more useful stuff to put here, maybe?
+  if (aURI) {
+    *aOut = aURI->GetSpecOrDefault();
+  }
+}
+
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLValue, CSSURLValue);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray*
 Gecko_NewCSSShadowArray(uint32_t aLen)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -531,16 +531,18 @@ void Gecko_nsStyleSVGPaint_Reset(nsStyle
 void Gecko_nsStyleSVG_SetDashArrayLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* dst, const nsStyleSVG* src);
 void Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* dst, const nsStyleSVG* src);
 
 mozilla::css::URLValue* Gecko_NewURLValue(ServoBundledURI uri);
 size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);
 void Gecko_GetComputedURLSpec(const mozilla::css::URLValueData* url, nsCString* spec);
+void Gecko_nsIURI_Debug(nsIURI*, nsCString* spec);
+
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(RawGeckoURLExtraData, URLExtraData);
 
 void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
--- a/servo/components/style/error_reporting.rs
+++ b/servo/components/style/error_reporting.rs
@@ -2,17 +2,16 @@
  * 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/. */
 
 //! Types used to report parsing errors.
 
 #![deny(missing_docs)]
 
 use cssparser::{BasicParseErrorKind, ParseErrorKind, SourceLocation, Token};
-use log;
 use std::fmt;
 use style_traits::ParseError;
 use stylesheets::UrlExtraData;
 
 /// Errors that can be encountered while parsing CSS.
 #[derive(Debug)]
 pub enum ContextualParseError<'a> {
     /// A property declaration was not recognized.
@@ -224,25 +223,28 @@ pub trait ParseErrorReporter {
 }
 
 /// An error reporter that uses [the `log` crate](https://github.com/rust-lang-nursery/log)
 /// at `info` level.
 ///
 /// This logging is silent by default, and can be enabled with a `RUST_LOG=style=info`
 /// environment variable.
 /// (See [`env_logger`](https://rust-lang-nursery.github.io/log/env_logger/).)
+#[cfg(feature = "servo")]
 pub struct RustLogReporter;
 
+#[cfg(feature = "servo")]
 impl ParseErrorReporter for RustLogReporter {
     fn report_error(
         &self,
         url: &UrlExtraData,
         location: SourceLocation,
         error: ContextualParseError,
     ) {
+        use log;
         if log_enabled!(log::Level::Info) {
             info!(
                 "Url:\t{}\n{}:{} {}",
                 url.as_str(),
                 location.line,
                 location.column,
                 error
             )
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -12,24 +12,35 @@ use gecko_bindings::structs::{self, RawG
 use gecko_bindings::structs::{StyleSheetInfo, nsIDocument};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
 use invalidation::media_queries::{MediaListKey, ToMediaListKey};
 use malloc_size_of::MallocSizeOfOps;
 use media_queries::{Device, MediaList};
 use properties::ComputedValues;
 use selector_parser::SnapshotMap;
 use servo_arc::Arc;
+use std::fmt;
 use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
 use stylist::Stylist;
 
 /// Little wrapper to a Gecko style sheet.
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Eq, PartialEq)]
 pub struct GeckoStyleSheet(*const DomStyleSheet);
 
+impl fmt::Debug for GeckoStyleSheet {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        let contents = self.contents();
+        formatter.debug_struct("GeckoStyleSheet")
+            .field("origin", &contents.origin)
+            .field("url_data", &*contents.url_data.read())
+            .finish()
+    }
+}
+
 impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
     fn to_media_list_key(&self) -> MediaListKey {
         use std::mem;
         unsafe { MediaListKey::from_raw(mem::transmute(self.0)) }
     }
 }
 
 impl GeckoStyleSheet {
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -1,43 +1,44 @@
 /* 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/. */
 
 //! Common handling for the specified value CSS url() values.
 
 use cssparser::Parser;
 use gecko_bindings::bindings;
-use gecko_bindings::structs::{ServoBundledURI, URLExtraData};
+use gecko_bindings::structs::ServoBundledURI;
 use gecko_bindings::structs::mozilla::css::URLValueData;
 use gecko_bindings::structs::root::{RustString, nsStyleImageRequest};
 use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
 use gecko_bindings::sugar::refptr::RefPtr;
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use nsstring::nsCString;
 use parser::{Parse, ParserContext};
 use servo_arc::{Arc, RawOffsetArc};
 use std::fmt::{self, Write};
 use std::mem;
+use stylesheets::UrlExtraData;
 use style_traits::{CssWriter, ParseError, ToCss};
 use values::computed::{Context, ToComputedValue};
 
 /// A CSS url() value for gecko.
 #[css(function = "url")]
 #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
 pub struct CssUrl {
     /// The URL in unresolved string form.
     ///
     /// Refcounted since cloning this should be cheap and data: uris can be
     /// really large.
     serialization: Arc<String>,
 
     /// The URL extra data.
     #[css(skip)]
-    pub extra_data: RefPtr<URLExtraData>,
+    pub extra_data: UrlExtraData,
 }
 
 impl CssUrl {
     /// Try to parse a URL from a string value that is a valid CSS token for a
     /// URL.
     pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
         CssUrl {
             serialization: Arc::new(url),
@@ -53,17 +54,17 @@ impl CssUrl {
     }
 
     /// Convert from URLValueData to SpecifiedUrl.
     unsafe fn from_url_value_data(url: &URLValueData) -> Self {
         let arc_type =
             &url.mString as *const _ as *const RawOffsetArc<String>;
         CssUrl {
             serialization: Arc::from_raw_offset((*arc_type).clone()),
-            extra_data: url.mExtraData.to_safe(),
+            extra_data: UrlExtraData(url.mExtraData.to_safe()),
         }
     }
 
     /// Returns true if this URL looks like a fragment.
     /// See https://drafts.csswg.org/css-values/#local-urls
     pub fn is_fragment(&self) -> bool {
         self.as_str().chars().next().map_or(false, |c| c == '#')
     }
@@ -83,17 +84,17 @@ impl CssUrl {
     }
 
     /// Create a bundled URI suitable for sending to Gecko
     /// to be constructed into a css::URLValue
     pub fn for_ffi(&self) -> ServoBundledURI {
         let arc_offset = Arc::into_raw_offset(self.serialization.clone());
         ServoBundledURI {
             mURLString: unsafe { mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset) },
-            mExtraData: self.extra_data.get(),
+            mExtraData: self.extra_data.0.get(),
         }
     }
 }
 
 impl Parse for CssUrl {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
--- a/servo/components/style/gecko_bindings/sugar/refptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs
@@ -73,25 +73,16 @@ impl<T: RefCounted> RefPtr<T> {
         let ret = RefPtr {
             ptr: ptr,
             _marker: PhantomData,
         };
         ret.addref();
         ret
     }
 
-    /// Create a reference to RefPtr from a reference to pointer.
-    ///
-    /// The pointer must be valid and non null.
-    ///
-    /// This method doesn't touch refcount.
-    pub unsafe fn from_ptr_ref(ptr: &*mut T) -> &Self {
-        mem::transmute(ptr)
-    }
-
     /// Produces an FFI-compatible RefPtr that can be stored in style structs.
     ///
     /// structs::RefPtr does not have a destructor, so this may leak
     pub fn forget(self) -> structs::RefPtr<T> {
         let ret = structs::RefPtr {
             mRawPtr: self.ptr,
             _phantom_0: PhantomData,
         };
--- a/servo/components/style/stylesheets/mod.rs
+++ b/servo/components/style/stylesheets/mod.rs
@@ -56,32 +56,62 @@ pub use self::supports_rule::SupportsRul
 pub use self::viewport_rule::ViewportRule;
 
 /// Extra data that the backend may need to resolve url values.
 #[cfg(not(feature = "gecko"))]
 pub type UrlExtraData = ::servo_url::ServoUrl;
 
 /// Extra data that the backend may need to resolve url values.
 #[cfg(feature = "gecko")]
-pub type UrlExtraData =
-    ::gecko_bindings::sugar::refptr::RefPtr<::gecko_bindings::structs::URLExtraData>;
+#[derive(Clone, PartialEq)]
+pub struct UrlExtraData(
+    pub ::gecko_bindings::sugar::refptr::RefPtr<::gecko_bindings::structs::URLExtraData>
+);
 
 #[cfg(feature = "gecko")]
 impl UrlExtraData {
-    /// Returns a string for the url.
-    ///
-    /// Unimplemented currently.
-    pub fn as_str(&self) -> &str {
-        // TODO
-        "(stylo: not supported)"
+    /// True if this URL scheme is chrome.
+    #[inline]
+    pub fn is_chrome(&self) -> bool {
+        self.0.mIsChrome
     }
 
-    /// True if this URL scheme is chrome.
-    pub fn is_chrome(&self) -> bool {
-        self.mIsChrome
+    /// Create a reference to this `UrlExtraData` from a reference to pointer.
+    ///
+    /// The pointer must be valid and non null.
+    ///
+    /// This method doesn't touch refcount.
+    #[inline]
+    pub unsafe fn from_ptr_ref(ptr: &*mut ::gecko_bindings::structs::URLExtraData) -> &Self {
+        ::std::mem::transmute(ptr)
+    }
+}
+
+#[cfg(feature = "gecko")]
+impl fmt::Debug for UrlExtraData {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        use gecko_bindings::{structs, bindings};
+
+        struct DebugURI(*mut structs::nsIURI);
+        impl fmt::Debug for DebugURI {
+            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                use nsstring::nsCString;
+                let mut spec = nsCString::new();
+                unsafe {
+                    bindings::Gecko_nsIURI_Debug(self.0, &mut spec);
+                }
+                spec.fmt(formatter)
+            }
+        }
+
+        formatter.debug_struct("URLExtraData")
+            .field("is_chrome", &self.is_chrome())
+            .field("base", &DebugURI(self.0.mBaseURI.raw::<structs::nsIURI>()))
+            .field("referrer", &DebugURI(self.0.mReferrer.raw::<structs::nsIURI>()))
+            .finish()
     }
 }
 
 // XXX We probably need to figure out whether we should mark Eq here.
 // It is currently marked so because properties::UnparsedValue wants Eq.
 #[cfg(feature = "gecko")]
 impl Eq for UrlExtraData {}
 
--- a/servo/components/style/stylesheets/stylesheet.rs
+++ b/servo/components/style/stylesheets/stylesheet.rs
@@ -171,17 +171,17 @@ macro_rules! rule_filter {
                     }
                 }
             }
         )+
     }
 }
 
 /// A trait to represent a given stylesheet in a document.
-pub trait StylesheetInDocument {
+pub trait StylesheetInDocument : ::std::fmt::Debug {
     /// Get the stylesheet origin.
     fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin;
 
     /// Get the stylesheet quirks mode.
     fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode;
 
     /// Get whether this stylesheet is enabled.
     fn enabled(&self) -> bool;
@@ -258,17 +258,17 @@ impl StylesheetInDocument for Stylesheet
     #[inline]
     fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
         self.contents.rules(guard)
     }
 }
 
 /// A simple wrapper over an `Arc<Stylesheet>`, with pointer comparison, and
 /// suitable for its use in a `StylesheetSet`.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
 pub struct DocumentStyleSheet(
     #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] pub Arc<Stylesheet>,
 );
 
 impl PartialEq for DocumentStyleSheet {
     fn eq(&self, other: &Self) -> bool {
         Arc::ptr_eq(&self.0, &other.0)
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -138,17 +138,17 @@ use style::rule_cache::RuleCacheConditio
 use style::rule_tree::{CascadeLevel, StrongRuleNode};
 use style::selector_parser::{PseudoElementCascadeType, SelectorImpl};
 use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
 use style::string_cache::{Atom, WeakAtom};
 use style::style_adjuster::StyleAdjuster;
 use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, CounterStyleRule};
 use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, ImportRule};
 use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule};
-use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
+use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule, UrlExtraData};
 use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
 use style::stylesheets::import_rule::ImportSheet;
 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
 use style::stylesheets::supports_rule::parse_condition_or_declaration;
 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::DomTraversal;
@@ -184,54 +184,52 @@ impl ClosureHelper for DeclarationBlockM
  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
  * depend on but good enough for our purposes.
  */
 
 // A dummy url data for where we don't pass url data in.
 // We need to get rid of this sooner than later.
-static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut URLExtraData;
-
-#[no_mangle]
-pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) {
+static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) {
     use style::gecko_bindings::sugar::origin_flags;
 
     // Pretend that we're a Servo Layout thread, to make some assertions happy.
     thread_state::initialize(thread_state::ThreadState::LAYOUT);
 
     // Perform some debug-only runtime assertions.
     restyle_hints::assert_restyle_hints_match();
     origin_flags::assert_flags_match();
     parser::assert_parsing_mode_match();
     traversal_flags::assert_traversal_flags_match();
     specified::font::assert_variant_east_asian_matches();
     specified::font::assert_variant_ligatures_matches();
     specified::box_::assert_touch_action_matches();
 
-    // Initialize the dummy url data
-    unsafe { DUMMY_URL_DATA = dummy_url_data; }
+    DUMMY_URL_DATA = dummy_url_data;
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_InitializeCooperativeThread() {
     // Pretend that we're a Servo Layout thread to make some assertions happy.
     thread_state::initialize(thread_state::ThreadState::LAYOUT);
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_Shutdown() {
-    // The dummy url will be released after shutdown, so clear the
-    // reference to avoid use-after-free.
-    unsafe { DUMMY_URL_DATA = ptr::null_mut(); }
+pub unsafe extern "C" fn Servo_Shutdown() {
+    DUMMY_URL_DATA = ptr::null_mut();
     Stylist::shutdown();
 }
 
-unsafe fn dummy_url_data() -> &'static RefPtr<URLExtraData> {
-    RefPtr::from_ptr_ref(&DUMMY_URL_DATA)
+#[inline(always)]
+unsafe fn dummy_url_data() -> &'static UrlExtraData {
+    UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
 }
 
 #[allow(dead_code)]
 fn is_main_thread() -> bool {
     unsafe { bindings::Gecko_IsMainThread() }
 }
 
 #[allow(dead_code)]
@@ -1176,17 +1174,17 @@ pub extern "C" fn Servo_StyleSheet_FromU
     line_number_offset: u32,
     quirks_mode: nsCompatibility,
     reusable_sheets: *mut LoaderReusableStyleSheets,
 ) -> RawServoStyleSheetContentsStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let input: &str = unsafe { (*bytes).as_str_unchecked() };
 
     let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
-    let url_data = unsafe { RefPtr::from_ptr_ref(&extra_data) };
+    let url_data = unsafe { UrlExtraData::from_ptr_ref(&extra_data) };
     let loader = if loader.is_null() {
         None
     } else {
         Some(StylesheetLoader::new(loader, stylesheet, load_data, reusable_sheets))
     };
 
     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
     let loader: Option<&StyleStylesheetLoader> = match loader {
@@ -1203,33 +1201,33 @@ pub extern "C" fn Servo_StyleSheet_FromU
         loader,
         reporter.as_ref().map(|r| r as &ParseErrorReporter),
         quirks_mode.into(),
         line_number_offset,
     )).into_strong()
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
+pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
     load_data: *mut SheetLoadDataHolder,
     extra_data: *mut URLExtraData,
     bytes: *const nsACString,
     mode: SheetParsingMode,
     line_number_offset: u32,
     quirks_mode: nsCompatibility,
 ) {
-    let (load_data, extra_data, bytes) = unsafe {
-        let mut b = nsCString::new();
-        b.assign(&*bytes);
-        (RefPtr::new(load_data), RefPtr::new(extra_data), b)
-    };
+    let load_data = RefPtr::new(load_data);
+    let extra_data = UrlExtraData(RefPtr::new(extra_data));
+
+    let mut sheet_bytes = nsCString::new();
+    sheet_bytes.assign(&*bytes);
     let async_parser = AsyncStylesheetParser::new(
         load_data,
         extra_data,
-        bytes,
+        sheet_bytes,
         mode_to_origin(mode),
         quirks_mode.into(),
         line_number_offset
     );
 
     if let Some(thread_pool) = STYLE_THREAD_POOL.style_thread_pool.as_ref() {
         thread_pool.spawn(|| {
             async_parser.parse();
@@ -2508,17 +2506,17 @@ pub unsafe extern "C" fn Servo_FontFaceR
     rule: RawServoFontFaceRuleBorrowed,
     desc: nsCSSFontDesc,
     value: *const nsACString,
     data: *mut URLExtraData,
 ) -> bool {
     let value = value.as_ref().unwrap().as_str_unchecked();
     let mut input = ParserInput::new(&value);
     let mut parser = Parser::new(&mut input);
-    let url_data = RefPtr::from_ptr_ref(&data);
+    let url_data = UrlExtraData::from_ptr_ref(&data);
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::FontFace),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
     );
@@ -3219,17 +3217,17 @@ fn parse_property_into(
     value: *const nsACString,
     data: *mut URLExtraData,
     parsing_mode: structs::ParsingMode,
     quirks_mode: QuirksMode,
     reporter: Option<&ParseErrorReporter>,
 ) -> Result<(), ()> {
     use style_traits::ParsingMode;
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
-    let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
+    let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
     let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
 
     parse_one_declaration_into(
         declarations,
         property_id,
         value,
         url_data,
         reporter,
@@ -3279,17 +3277,17 @@ pub extern "C" fn Servo_ParseProperty(
 pub extern "C" fn Servo_ParseEasing(
     easing: *const nsAString,
     data: *mut URLExtraData,
     output: nsTimingFunctionBorrowedMut
 ) -> bool {
     use style::properties::longhands::transition_timing_function;
 
     // FIXME Dummy URL data would work fine here.
-    let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
+    let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
     );
@@ -3372,17 +3370,17 @@ pub extern "C" fn Servo_ParseStyleAttrib
     data: *const nsACString,
     raw_extra_data: *mut URLExtraData,
     quirks_mode: nsCompatibility,
     loader: *mut Loader,
 ) -> RawServoDeclarationBlockStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let value = unsafe { data.as_ref().unwrap().as_str_unchecked() };
     let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
-    let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
+    let url_data = unsafe { UrlExtraData::from_ptr_ref(&raw_extra_data) };
     Arc::new(global_style_data.shared_lock.wrap(
         parse_style_attribute(
             value,
             url_data,
             reporter.as_ref().map(|r| r as &ParseErrorReporter),
             quirks_mode.into(),
         )
     )).into_strong()
@@ -4211,17 +4209,17 @@ pub extern "C" fn Servo_DeclarationBlock
     raw_extra_data: *mut URLExtraData,
 ) {
     use style::properties::PropertyDeclaration;
     use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
     use style::values::Either;
     use style::values::generics::image::Image;
     use style::values::specified::url::SpecifiedImageUrl;
 
-    let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
+    let url_data = unsafe { UrlExtraData::from_ptr_ref(&raw_extra_data) };
     let string = unsafe { (*value).to_string() };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::Style),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
@@ -5534,17 +5532,17 @@ pub extern "C" fn Servo_ParseFontShortha
 ) -> bool {
     use style::properties::shorthands::font;
     use style::values::generics::font::FontStyle as GenericFontStyle;
     use style::values::specified::font::{FontFamily, FontWeight, FontStyle, SpecifiedFontStyle};
 
     let string = unsafe { (*value).to_string() };
     let mut input = ParserInput::new(&string);
     let mut parser = Parser::new(&mut input);
-    let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
+    let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::FontFace),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
     );
--- a/servo/ports/geckolib/stylesheet_loader.rs
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -7,24 +7,23 @@ use nsstring::nsCString;
 use servo_arc::Arc;
 use style::context::QuirksMode;
 use style::gecko::data::GeckoStyleSheet;
 use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
 use style::gecko_bindings::bindings;
 use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
 use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
 use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder};
-use style::gecko_bindings::structs::URLExtraData;
 use style::gecko_bindings::sugar::ownership::FFIArcHelpers;
 use style::gecko_bindings::sugar::refptr::RefPtr;
 use style::media_queries::MediaList;
 use style::parser::ParserContext;
 use style::shared_lock::{Locked, SharedRwLock};
 use style::stylesheets::{ImportRule, Origin, StylesheetLoader as StyleStylesheetLoader};
-use style::stylesheets::StylesheetContents;
+use style::stylesheets::{StylesheetContents, UrlExtraData};
 use style::stylesheets::import_rule::ImportSheet;
 use style::values::CssUrl;
 
 pub struct StylesheetLoader(*mut Loader, *mut DomStyleSheet, *mut SheetLoadData, *mut LoaderReusableStyleSheets);
 
 impl StylesheetLoader {
     pub fn new(
         loader: *mut Loader,
@@ -64,27 +63,27 @@ impl StyleStylesheetLoader for Styleshee
         let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) };
         let stylesheet = ImportSheet::new(sheet);
         Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet }))
     }
 }
 
 pub struct AsyncStylesheetParser {
     load_data: RefPtr<SheetLoadDataHolder>,
-    extra_data: RefPtr<URLExtraData>,
+    extra_data: UrlExtraData,
     bytes: nsCString,
     origin: Origin,
     quirks_mode: QuirksMode,
     line_number_offset: u32,
 }
 
 impl AsyncStylesheetParser {
     pub fn new(
         load_data: RefPtr<SheetLoadDataHolder>,
-        extra_data: RefPtr<URLExtraData>,
+        extra_data: UrlExtraData,
         bytes: nsCString,
         origin: Origin,
         quirks_mode: QuirksMode,
         line_number_offset: u32,
     ) -> Self {
         AsyncStylesheetParser {
             load_data,
             extra_data,