Bug 1499408 - Part 1: Make css::URLValue hold on to a CssUrlData, not just its serialization. r=emilio
authorCameron McCormack <cam@mcc.id.au>
Wed, 17 Oct 2018 12:36:49 +0000
changeset 490052 23ee4dcfdbaf0d4508d76ac9f8cb9bbcf3e61db7
parent 490051 a53e0884fcb170c2cde943ba20aa7fc5ef083e42
child 490053 4ffda0cdc604ee19810a2fcfc255e1838f98c2a1
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersemilio
bugs1499408
milestone64.0a1
Bug 1499408 - Part 1: Make css::URLValue hold on to a CssUrlData, not just its serialization. r=emilio MozReview-Commit-ID: EWcbnVtDJCS Differential Revision: https://phabricator.services.mozilla.com/D8874
layout/style/GeckoBindings.cpp
layout/style/GeckoBindings.h
layout/style/ServoArcTypeList.h
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
servo/components/style/gecko/arc_types.rs
servo/components/style/gecko/url.rs
servo/ports/geckolib/glue.rs
servo/ports/geckolib/stylesheet_loader.rs
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -1376,24 +1376,16 @@ Gecko_CounterStyle_GetName(const Counter
 }
 
 const AnonymousCounterStyle*
 Gecko_CounterStyle_GetAnonymous(const CounterStylePtr* aPtr)
 {
   return aPtr->AsAnonymous();
 }
 
-already_AddRefed<css::URLValue>
-ServoBundledURI::IntoCssUrl(CORSMode aCorsMode)
-{
-  RefPtr<css::URLValue> urlValue =
-    new css::URLValue(mURLString, do_AddRef(mExtraData), aCorsMode);
-  return urlValue.forget();
-}
-
 void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
   MOZ_ASSERT(aImage);
   aImage->SetNull();
 }
 
 void
@@ -2000,19 +1992,22 @@ void
 Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst, const nsStyleSVG* aSrc)
 {
   aDst->mContextProps = aSrc->mContextProps;
   aDst->mContextPropsBits = aSrc->mContextPropsBits;
 }
 
 
 css::URLValue*
-Gecko_URLValue_Create(ServoBundledURI aURI, mozilla::CORSMode aCORSMode)
+Gecko_URLValue_Create(RawServoCssUrlDataStrong aCssUrl,
+                      URLExtraData* aExtraData,
+                      CORSMode aCORSMode)
 {
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl(aCORSMode);
+  RefPtr<css::URLValue> url =
+    new css::URLValue(aCssUrl.Consume(), aExtraData, aCORSMode);
   return url.forget().take();
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(GeckoURLValueMallocSizeOf)
 
 size_t
 Gecko_URLValue_SizeOfIncludingThis(URLValue* aURL)
 {
@@ -2586,38 +2581,42 @@ LoadImportSheet(css::Loader* aLoader,
   return sheet.forget();
 }
 
 StyleSheet*
 Gecko_LoadStyleSheet(css::Loader* aLoader,
                      StyleSheet* aParent,
                      SheetLoadData* aParentLoadData,
                      css::LoaderReusableStyleSheets* aReusableSheets,
-                     ServoBundledURI aServoURL,
+                     RawServoCssUrlDataStrong aCssUrl,
+                     URLExtraData* aExtraData,
                      RawServoMediaListStrong aMediaList)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The CORS mode in the URLValue is irrelevant here.
   // (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
-  RefPtr<css::URLValue> url = aServoURL.IntoCssUrl(CORS_NONE);
+  RefPtr<css::URLValue> url =
+    new css::URLValue(aCssUrl.Consume(), aExtraData, CORS_NONE);
   return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
                          url, aMediaList.Consume()).take();
 }
 
 void
 Gecko_LoadStyleSheetAsync(css::SheetLoadDataHolder* aParentData,
-                          ServoBundledURI aServoURL,
+                          RawServoCssUrlDataStrong aCssUrl,
+                          URLExtraData* aExtraData,
                           RawServoMediaListStrong aMediaList,
                           RawServoImportRuleStrong aImportRule)
 {
   RefPtr<SheetLoadDataHolder> loadData = aParentData;
   // The CORS mode in the URLValue is irrelevant here.
   // (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
-  RefPtr<css::URLValue> urlVal = aServoURL.IntoCssUrl(CORS_NONE);
+  RefPtr<css::URLValue> urlVal =
+    new css::URLValue(aCssUrl.Consume(), aExtraData, CORS_NONE);
   RefPtr<RawServoMediaList> mediaList = aMediaList.Consume();
   RefPtr<RawServoImportRule> importRule = aImportRule.Consume();
   NS_DispatchToMainThread(NS_NewRunnableFunction(__func__,
                                                  [data = std::move(loadData),
                                                   url = std::move(urlVal),
                                                   media = std::move(mediaList),
                                                   import = std::move(importRule)]() mutable {
     MOZ_ASSERT(NS_IsMainThread());
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -56,26 +56,16 @@ const bool GECKO_IS_NIGHTLY = false;
   static_assert(class_::HasThreadSafeRefCnt::value,                           \
                 "NS_DECL_THREADSAFE_FFI_REFCOUNTING can only be used with "   \
                 "classes that have thread-safe refcounting");                 \
   void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr)                     \
   { NS_ADDREF(aPtr); }                                                        \
   void Gecko_Release##name_##ArbitraryThread(class_* aPtr)                    \
   { NS_RELEASE(aPtr); }
 
-class ServoBundledURI
-{
-public:
-  // NOTE(emilio): Not calling IntoCssUrl will cause to leak the
-  // string, so don't do that :)
-  already_AddRefed<mozilla::css::URLValue> IntoCssUrl(mozilla::CORSMode);
-  mozilla::ServoRawOffsetArc<RustString> mURLString;
-  mozilla::URLExtraData* mExtraData;
-};
-
 extern "C" {
 
 // Debugging stuff.
 void Gecko_Element_DebugListAttributes(RawGeckoElementBorrowed, nsCString*);
 
 void Gecko_Snapshot_DebugListAttributes(
   const mozilla::ServoElementSnapshot*,
   nsCString*);
@@ -134,22 +124,24 @@ void Gecko_StyleSheet_FinishAsyncParse(
   RawServoStyleSheetContentsStrong sheet_contents,
   StyleUseCountersOwnedOrNull use_counters);
 
 mozilla::StyleSheet* Gecko_LoadStyleSheet(
   mozilla::css::Loader* loader,
   mozilla::StyleSheet* parent,
   mozilla::css::SheetLoadData* parent_load_data,
   mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
-  ServoBundledURI url,
+  RawServoCssUrlDataStrong url,
+  RawGeckoURLExtraData* url_extra_data,
   RawServoMediaListStrong media_list);
 
 void Gecko_LoadStyleSheetAsync(
   mozilla::css::SheetLoadDataHolder* parent_data,
-  ServoBundledURI url,
+  RawServoCssUrlDataStrong url,
+  RawGeckoURLExtraData* url_extra_data,
   RawServoMediaListStrong media_list,
   RawServoImportRuleStrong import_rule);
 
 // Selector Matching.
 uint64_t Gecko_ElementState(RawGeckoElementBorrowed element);
 bool Gecko_IsRootElement(RawGeckoElementBorrowed element);
 
 bool Gecko_MatchLang(
@@ -646,17 +638,18 @@ void Gecko_nsStyleSVG_CopyDashArray(nsSt
 
 void Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* svg, uint32_t len);
 
 void Gecko_nsStyleSVG_CopyContextProperties(
   nsStyleSVG* dst,
   const nsStyleSVG* src);
 
 mozilla::css::URLValue* Gecko_URLValue_Create(
-  ServoBundledURI uri,
+  RawServoCssUrlDataStrong url,
+  RawGeckoURLExtraData* extra_data,
   mozilla::CORSMode aCORSMode);
 
 size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);
 
 void Gecko_GetComputedURLSpec(
   const mozilla::css::URLValue* url,
   nsCString* spec);
 
--- a/layout/style/ServoArcTypeList.h
+++ b/layout/style/ServoArcTypeList.h
@@ -33,8 +33,9 @@ SERVO_ARC_TYPE(MediaRule, RawServoMediaR
 SERVO_ARC_TYPE(NamespaceRule, RawServoNamespaceRule)
 SERVO_ARC_TYPE(PageRule, RawServoPageRule)
 SERVO_ARC_TYPE(SupportsRule, RawServoSupportsRule)
 SERVO_ARC_TYPE(DocumentRule, RawServoMozDocumentRule)
 SERVO_ARC_TYPE(FontFeatureValuesRule, RawServoFontFeatureValuesRule)
 SERVO_ARC_TYPE(RuleNode, RawServoRuleNode)
 SERVO_ARC_TYPE(FontFaceRule, RawServoFontFaceRule)
 SERVO_ARC_TYPE(CounterStyleRule, RawServoCounterStyleRule)
+SERVO_ARC_TYPE(CssUrlData, RawServoCssUrlData)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -1085,24 +1085,21 @@ void Servo_GetPropertyValue(
 
 void Servo_ProcessInvalidations(
   RawServoStyleSetBorrowed set,
   RawGeckoElementBorrowed element,
   const mozilla::ServoElementSnapshotTable* snapshots);
 
 bool Servo_HasPendingRestyleAncestor(RawGeckoElementBorrowed element);
 
-void Servo_GetArcStringData(
-  const RustString*,
+void Servo_CssUrlData_GetSerialization(
+  RawServoCssUrlDataBorrowed url,
   uint8_t const** chars,
   uint32_t* len);
 
-void Servo_ReleaseArcStringData(
-  const mozilla::ServoRawOffsetArc<RustString>* string);
-
 // CSS parsing utility functions.
 
 bool Servo_IsValidCSSColor(const nsAString* value);
 
 bool Servo_ComputeColor(
   RawServoStyleSetBorrowedOrNull set,
   nscolor current_color,
   const nsAString* value,
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -307,17 +307,16 @@ whitelist-types = [
     "nsStyleUI",
     "nsStyleVisibility",
     "nsStyleXUL",
     "nsTArrayHeader",
     "Position",
     "PropertyValuePair",
     "Runnable",
     "ServoAttrSnapshot",
-    "ServoBundledURI",
     "ServoComputedData",
     "ServoComputedDataBorrowed",
     "ServoElementSnapshot",
     "ComputedStyleStrong",
     "ComputedStyleBorrowed",
     "ComputedStyleBorrowedOrNull",
     "SheetParsingMode",
     "StaticRefPtr",
@@ -445,17 +444,16 @@ structs-types = [
     "mozilla::StyleComputedFontStyleDescriptor",
     "mozilla::StyleComputedFontWeightRange",
     "mozilla::StyleFontDisplay",
     "mozilla::StyleUnicodeRange",
     "mozilla::StyleFontLanguageOverride",
     "mozilla::StyleFontFaceSourceListComponent",
     "gfxFontFeature",
     "mozilla::gfx::FontVariation",
-    "ServoRawOffsetArc",
     "mozilla::DeclarationBlockMutationClosure",
     "nsAttrValue",
     "nsIContent",
     "nsINode",
     "nsIDocument",
     "nsIDocument_DocumentTheme",
     "nsSimpleContentList",
     "mozilla::MediumFeaturesChangedResult",
@@ -481,30 +479,28 @@ structs-types = [
     "RawGeckoStyleAnimationList",
     "RawGeckoStyleChildrenIterator",
     "RawGeckoServoStyleRuleList",
     "RawGeckoURLExtraData",
     "RawGeckoXBLBinding",
     "RawServoSelectorList",
     "RawServoSourceSizeList",
     "RefPtr",
-    "RustString",
     "StyleUseCounters",
     "CSSPseudoElementType",
     "ServoTraversalFlags",
     "ComputedTimingFunction_BeforeFlag",
     "CounterStylePtr",
     "FontFamilyType",
     "mozilla::FontSizePrefs",
     "GeckoFontMetrics",
     "IterationCompositeOperation",
     "Keyframe",
     "PropertyValuePair",
     "SeenPtrs",
-    "ServoBundledURI",
     "ServoElementSnapshot",
     "ServoElementSnapshotTable",
     "ServoStyleSetSizes",
     "SheetParsingMode",
     "StyleBasicShapeType",
     "StyleShapeSource",
     "StyleTransition",
     "gfxFontFeatureValueSet",
@@ -588,16 +584,17 @@ structs-types = [
     "DocumentMatchingFunction",
     "StyleAnimation",
     "StyleRuleInclusion",
     "nsStyleTransformMatrix::MatrixTransformOperator",
     "RawGeckoGfxMatrix4x4",
     "FontFamilyName",
     "mozilla::SharedFontList",
     "RawServoAnimationValueMap",
+    "RawServoCssUrlData",
 ]
 array-types = [
     { cpp-type = "uintptr_t", rust-type = "usize" },
 ]
 servo-immutable-borrow-types = [
     "RawServoDeclarationBlockStrong",
 ]
 servo-borrow-types = [
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -813,18 +813,16 @@ nsCSSValue::Array::SizeOfIncludingThis(m
   return n;
 }
 
 css::URLValue::~URLValue()
 {
   if (mLoadID != 0) {
     ImageLoader::DeregisterCSSImageFromAllLoaders(this);
   }
-
-  Servo_ReleaseArcStringData(&mString);
 }
 
 bool
 css::URLValue::Equals(const URLValue& aOther) const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool eq;
@@ -859,17 +857,17 @@ css::URLValue::DefinitelyEqualURIsAndPri
          DefinitelyEqualURIs(aOther);
 }
 
 nsDependentCSubstring
 css::URLValue::GetString() const
 {
   const uint8_t* chars;
   uint32_t len;
-  Servo_GetArcStringData(mString.mPtr, &chars, &len);
+  Servo_CssUrlData_GetSerialization(mCssUrl, &chars, &len);
   return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
 }
 
 nsIURI*
 css::URLValue::GetURI() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -36,17 +36,17 @@ class imgRequestProxy;
 class nsAtom;
 class nsIContent;
 class nsIDocument;
 class nsIPrincipal;
 class nsIURI;
 class nsPresContext;
 template <class T>
 class nsPtrHashKey;
-struct RustString;
+struct RawServoCssUrlData;
 
 namespace mozilla {
 class CSSStyleSheet;
 } // namespace mozilla
 
 // Deletes a linked list iteratively to avoid blowing up the stack (bug 456196).
 #define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_)                        \
   {                                                                            \
@@ -91,29 +91,27 @@ class CSSStyleSheet;
   }
 
 namespace mozilla {
 namespace css {
 
 struct URLValue final
 {
 public:
-  // aString and aExtraData must not be null.
-  //
-  // Construct with a base URI; this will create the actual URI lazily from
-  // aString and aExtraData.
-  URLValue(ServoRawOffsetArc<RustString> aString,
-           already_AddRefed<URLExtraData> aExtraData,
+  // aCssUrl and aExtraData must not be null.
+  URLValue(already_AddRefed<RawServoCssUrlData> aCssUrl,
+           URLExtraData* aExtraData,
            CORSMode aCORSMode)
-    : mExtraData(std::move(aExtraData))
+    : mExtraData(aExtraData)
     , mURIResolved(false)
-    , mString(aString)
+    , mCssUrl(aCssUrl)
     , mCORSMode(aCORSMode)
   {
     MOZ_ASSERT(mExtraData);
+    MOZ_ASSERT(mCssUrl);
   }
 
   // Returns true iff all fields of the two URLValue objects are equal.
   //
   // Only safe to call on the main thread, since this will call Equals on the
   // nsIURI and nsIPrincipal objects stored on the URLValue objects.
   bool Equals(const URLValue& aOther) const;
 
@@ -166,17 +164,17 @@ public:
   RefPtr<URLExtraData> mExtraData;
 
 private:
   mutable bool mURIResolved;
 
   // mIsLocalRef is set when url starts with a U+0023 number sign(#) character.
   mutable Maybe<bool> mIsLocalRef;
 
-  mozilla::ServoRawOffsetArc<RustString> mString;
+  RefPtr<RawServoCssUrlData> mCssUrl;
 
   const CORSMode mCORSMode;
 
   // A unique, non-reused ID value for this URLValue over the life of the
   // process.  This value is only valid after LoadImage has been called.
   //
   // We use this as a key in some tables in ImageLoader.  This is better than
   // using the pointer value of the ImageValue object, since we can sometimes
--- a/servo/components/style/gecko/arc_types.rs
+++ b/servo/components/style/gecko/arc_types.rs
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! This file lists all arc FFI types and defines corresponding addref
 //! and release functions. This list corresponds to ServoArcTypeList.h
 //! file in Gecko.
 
 #![allow(non_snake_case, missing_docs)]
 
+use gecko::url::CssUrlData;
 use gecko_bindings::bindings::RawServoCounterStyleRule;
 use gecko_bindings::bindings::RawServoFontFeatureValuesRule;
 use gecko_bindings::bindings::RawServoImportRule;
 use gecko_bindings::bindings::RawServoKeyframe;
 use gecko_bindings::bindings::RawServoKeyframesRule;
 use gecko_bindings::bindings::RawServoMediaRule;
 use gecko_bindings::bindings::RawServoMozDocumentRule;
 use gecko_bindings::bindings::RawServoNamespaceRule;
@@ -22,16 +23,17 @@ use gecko_bindings::bindings::RawServoRu
 use gecko_bindings::bindings::RawServoSupportsRule;
 use gecko_bindings::bindings::ServoCssRules;
 use gecko_bindings::structs::RawServoAnimationValue;
 use gecko_bindings::structs::RawServoDeclarationBlock;
 use gecko_bindings::structs::RawServoFontFaceRule;
 use gecko_bindings::structs::RawServoMediaList;
 use gecko_bindings::structs::RawServoStyleRule;
 use gecko_bindings::structs::RawServoStyleSheetContents;
+use gecko_bindings::structs::RawServoCssUrlData;
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI, Strong};
 use media_queries::MediaList;
 use properties::{ComputedValues, PropertyDeclarationBlock};
 use properties::animated_properties::AnimationValue;
 use rule_tree::StrongRuleNode;
 use servo_arc::{Arc, ArcBorrow};
 use shared_lock::Locked;
 use std::{mem, ptr};
@@ -105,16 +107,19 @@ impl_arc_ffi!(Locked<FontFeatureValuesRu
               [Servo_FontFeatureValuesRule_AddRef, Servo_FontFeatureValuesRule_Release]);
 
 impl_arc_ffi!(Locked<FontFaceRule> => RawServoFontFaceRule
               [Servo_FontFaceRule_AddRef, Servo_FontFaceRule_Release]);
 
 impl_arc_ffi!(Locked<CounterStyleRule> => RawServoCounterStyleRule
               [Servo_CounterStyleRule_AddRef, Servo_CounterStyleRule_Release]);
 
+impl_arc_ffi!(CssUrlData => RawServoCssUrlData
+              [Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]);
+
 // RuleNode is a Arc-like type but it does not use Arc.
 
 impl StrongRuleNode {
     pub fn into_strong(self) -> RawServoRuleNodeStrong {
         let ptr = self.ptr();
         mem::forget(self);
         unsafe { mem::transmute(ptr) }
     }
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -1,100 +1,82 @@
 /* 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;
-use gecko_bindings::structs::root::{RustString, nsStyleImageRequest};
+use gecko_bindings::structs::root::nsStyleImageRequest;
 use gecko_bindings::structs::root::mozilla::CORSMode;
 use gecko_bindings::structs::root::mozilla::css::URLValue;
+use gecko_bindings::sugar::ownership::{HasArcFFI, FFIArcHelpers};
 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 servo_arc::Arc;
 use std::fmt::{self, Write};
-use std::mem;
 use style_traits::{CssWriter, ParseError, ToCss};
 use stylesheets::UrlExtraData;
 use values::computed::{Context, ToComputedValue};
 
 /// A CSS url() value for gecko.
 #[css(function = "url")]
 #[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
-pub struct CssUrl {
+pub struct CssUrl(pub Arc<CssUrlData>);
+
+/// Data shared between CssUrls.
+#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss)]
+pub struct CssUrlData {
     /// The URL in unresolved string form.
-    ///
-    /// Refcounted since cloning this should be cheap and data: uris can be
-    /// really large.
-    serialization: Arc<String>,
+    serialization: String,
 
     /// The URL extra data.
     #[css(skip)]
     pub extra_data: UrlExtraData,
 }
 
 impl CssUrl {
     /// 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),
+        CssUrl(Arc::new(CssUrlData {
+            serialization: url,
             extra_data: context.url_data.clone(),
-        }
+        }))
     }
 
     /// Returns true if the URL is definitely invalid. We don't eagerly resolve
     /// URLs in gecko, so we just return false here.
     /// use its |resolved| status.
     pub fn is_invalid(&self) -> bool {
         false
     }
 
-    /// Convert from URLValue to CssUrl.
-    unsafe fn from_url_value(url: &URLValue) -> Self {
-        let arc_type = &url.mString as *const _ as *const RawOffsetArc<String>;
-        CssUrl {
-            serialization: Arc::from_raw_offset((*arc_type).clone()),
-            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 == '#')
     }
 
     /// Return the unresolved url as string, or the empty string if it's
     /// invalid.
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        self.0.as_str()
+    }
+}
+
+impl CssUrlData {
+    /// Return the unresolved url as string, or the empty string if it's
+    /// invalid.
     pub fn as_str(&self) -> &str {
         &*self.serialization
     }
-
-    /// Little helper for Gecko's ffi.
-    pub fn as_slice_components(&self) -> (*const u8, usize) {
-        (
-            self.serialization.as_str().as_ptr(),
-            self.serialization.as_str().len(),
-        )
-    }
-
-    /// 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.0.get(),
-        }
-    }
 }
 
 impl Parse for CssUrl {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         let url = input.expect_url()?;
@@ -129,17 +111,21 @@ pub struct SpecifiedUrl {
 impl SpecifiedUrl {
     /// Parse a URL from a string value.
     pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
         Self::from_css_url(CssUrl::parse_from_string(url, context))
     }
 
     fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self {
         let url_value = unsafe {
-            let ptr = bindings::Gecko_URLValue_Create(url.for_ffi(), cors);
+            let ptr = bindings::Gecko_URLValue_Create(
+                url.0.clone().into_strong(),
+                url.0.extra_data.0.get(),
+                cors,
+            );
             // We do not expect Gecko_URLValue_Create returns null.
             debug_assert!(!ptr.is_null());
             RefPtr::from_addrefed(ptr)
         };
         Self { url, url_value }
     }
 
     fn from_css_url(url: CssUrl) -> Self {
@@ -275,17 +261,18 @@ impl ToCss for ComputedUrl {
             bindings::Gecko_GetComputedURLSpec,
         )
     }
 }
 
 impl ComputedUrl {
     /// Convert from RefPtr<URLValue> to ComputedUrl.
     pub unsafe fn from_url_value(url_value: RefPtr<URLValue>) -> Self {
-        let url = CssUrl::from_url_value(&*url_value);
+        let css_url = &*url_value.mCssUrl.mRawPtr;
+        let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
         ComputedUrl(SpecifiedUrl { url, url_value })
     }
 
     /// Get a raw pointer to the URLValue held by this ComputedUrl, for FFI.
     pub fn url_value_ptr(&self) -> *mut URLValue {
         self.0.url_value.get()
     }
 }
@@ -306,17 +293,18 @@ impl ToCss for ComputedImageUrl {
         )
     }
 }
 
 impl ComputedImageUrl {
     /// Convert from nsStyleImageReques to ComputedImageUrl.
     pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
         let url_value = image_request.mImageValue.to_safe();
-        let url = CssUrl::from_url_value(&*url_value);
+        let css_url = &*url_value.mCssUrl.mRawPtr;
+        let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
         ComputedImageUrl(SpecifiedImageUrl(SpecifiedUrl { url, url_value }))
     }
 
     /// Get a raw pointer to the URLValue held by this ComputedImageUrl, for FFI.
     pub fn url_value_ptr(&self) -> *mut URLValue {
         (self.0).0.url_value.get()
     }
 }
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -27,16 +27,17 @@ use style::driver;
 use style::element_state::{DocumentState, ElementState};
 use style::error_reporting::{ContextualParseError, ParseErrorReporter};
 use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
 use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
 use style::gecko::global_style_data::{GLOBAL_STYLE_DATA, GlobalStyleData, STYLE_THREAD_POOL};
 use style::gecko::restyle_damage::GeckoRestyleDamage;
 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
 use style::gecko::traversal::RecalcStyleOnly;
+use style::gecko::url::CssUrlData;
 use style::gecko::wrapper::{GeckoElement, GeckoNode};
 use style::gecko_bindings::bindings;
 use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoElementBorrowedOrNull, RawGeckoNodeBorrowed};
 use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut};
 use style::gecko_bindings::bindings::RawGeckoPresContextBorrowed;
 use style::gecko_bindings::bindings::{RawServoAuthorStyles, RawServoAuthorStylesBorrowed};
 use style::gecko_bindings::bindings::{RawServoAuthorStylesBorrowedMut, RawServoAuthorStylesOwned};
 use style::gecko_bindings::bindings::{RawServoCounterStyleRule, RawServoCounterStyleRuleBorrowed};
@@ -75,27 +76,28 @@ use style::gecko_bindings::bindings::Raw
 use style::gecko_bindings::bindings::RawGeckoFontFaceRuleListBorrowedMut;
 use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowedMut;
 use style::gecko_bindings::bindings::RawGeckoServoStyleRuleListBorrowedMut;
 use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed;
 use style::gecko_bindings::bindings::RawServoAnimationValueBorrowedOrNull;
 use style::gecko_bindings::bindings::RawServoAnimationValueMapBorrowedMut;
 use style::gecko_bindings::bindings::RawServoAnimationValueStrong;
 use style::gecko_bindings::bindings::RawServoAnimationValueTableBorrowed;
+use style::gecko_bindings::bindings::RawServoCssUrlDataBorrowed;
 use style::gecko_bindings::bindings::RawServoDeclarationBlockBorrowedOrNull;
 use style::gecko_bindings::bindings::RawServoStyleRuleBorrowed;
 use style::gecko_bindings::bindings::RawServoStyleSet;
 use style::gecko_bindings::bindings::nsCSSValueBorrowedMut;
 use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t;
 use style::gecko_bindings::bindings::nsTimingFunctionBorrowed;
 use style::gecko_bindings::bindings::nsTimingFunctionBorrowedMut;
 use style::gecko_bindings::structs;
 use style::gecko_bindings::structs::{CallerType, CSSPseudoElementType, CompositeOperation};
 use style::gecko_bindings::structs::{DeclarationBlockMutationClosure, Loader, LoaderReusableStyleSheets};
-use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong, RustString};
+use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong};
 use style::gecko_bindings::structs::{SheetParsingMode, nsAtom, nsCSSPropertyID};
 use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder};
 use style::gecko_bindings::structs::{nsCSSFontDesc, nsCSSCounterDesc};
 use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair};
 use style::gecko_bindings::structs::AtomArray;
 use style::gecko_bindings::structs::IterationCompositeOperation;
 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
 use style::gecko_bindings::structs::OriginFlags;
@@ -5455,29 +5457,23 @@ pub extern "C" fn Servo_GetCustomPropert
 
     let name = unsafe { name.as_mut().unwrap() };
     name.assign(&*property_name.as_slice());
 
     true
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn Servo_ReleaseArcStringData(string: *const RawOffsetArc<RustString>) {
-    let string = string as *const RawOffsetArc<String>;
-    // Cause RawOffsetArc::drop to run, releasing the strong reference to the string data.
-    let _ = ptr::read(string);
-}
-
-#[no_mangle]
-pub unsafe extern "C" fn Servo_GetArcStringData(
-    string: *const RustString,
+pub unsafe extern "C" fn Servo_CssUrlData_GetSerialization(
+    url: RawServoCssUrlDataBorrowed,
     utf8_chars: *mut *const u8,
     utf8_len: *mut u32,
 ) {
-    let string = &*(string as *const String);
+    let url_data = CssUrlData::as_arc(&url);
+    let string = url_data.as_str();
     *utf8_len = string.len() as u32;
     *utf8_chars = string.as_ptr();
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ProcessInvalidations(
     set: RawServoStyleSetBorrowed,
     element: RawGeckoElementBorrowed,
--- a/servo/ports/geckolib/stylesheet_loader.rs
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -50,17 +50,18 @@ impl StyleStylesheetLoader for Styleshee
         // but the Url it points to or the allocating backing the String inside that Url won’t,
         // so this raw pointer will still be valid.
 
         let child_sheet = unsafe {
             Gecko_LoadStyleSheet(self.0,
                                  self.1,
                                  self.2,
                                  self.3,
-                                 url.for_ffi(),
+                                 url.0.clone().into_strong(),
+                                 url.0.extra_data.0.get(),
                                  media.into_strong())
         };
 
         debug_assert!(!child_sheet.is_null(),
                       "Import rules should always have a strong sheet");
         let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) };
         let stylesheet = ImportSheet::new(sheet);
         Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet }))
@@ -141,23 +142,25 @@ impl StyleStylesheetLoader for AsyncStyl
     fn request_stylesheet(
         &self,
         url: CssUrl,
         source_location: SourceLocation,
         _context: &ParserContext,
         lock: &SharedRwLock,
         media: Arc<Locked<MediaList>>,
     ) -> Arc<Locked<ImportRule>> {
+        let extra_data = url.0.extra_data.0.get();
         let stylesheet = ImportSheet::new_pending(self.origin, self.quirks_mode);
         let rule = Arc::new(lock.wrap(ImportRule { url: url.clone(), source_location, stylesheet }));
 
         unsafe {
             bindings::Gecko_LoadStyleSheetAsync(
                 self.load_data.get(),
-                url.for_ffi(),
+                url.0.into_strong(),
+                extra_data,
                 media.into_strong(),
                 rule.clone().into_strong()
             );
         }
 
         rule
     }
 }