servo: Merge #18516 - Share specified URLs with Gecko (from jdm:stringshare); r=heycam
authorJosh Matthews <josh@joshmatthews.net>
Fri, 15 Sep 2017 12:43:30 -0700
changeset 665706 13ec4ded3b4ed25913047b1bed312ef67011fc1f
parent 665705 1885fa2ee0a84411d02512952134ab5bbb2467a6
child 665707 15ce21d9ddb13cd91088bcd1b01ed86823c595e5
push id80148
push userbmo:emilio@crisal.io
push dateFri, 15 Sep 2017 20:59:22 +0000
reviewersheycam
bugs1397971
milestone57.0a1
servo: Merge #18516 - Share specified URLs with Gecko (from jdm:stringshare); r=heycam This makes use of our Arc offset machinery to allow Gecko to store Arc<String> values and ensure there are used appropriately. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix [bug 1397971](https://bugzilla.mozilla.org/show_bug.cgi?id=1397971). Source-Repo: https://github.com/servo/servo Source-Revision: 70a6b2fa91ed377ce5d0d1696bfb1503be8aa454
servo/components/style/gecko/generated/bindings.rs
servo/components/style/gecko/generated/structs_debug.rs
servo/components/style/gecko/generated/structs_release.rs
servo/components/style/gecko/url.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -14,16 +14,17 @@ use gecko_bindings::structs::mozilla::cs
 use gecko_bindings::structs::mozilla::css::ImageValue;
 use gecko_bindings::structs::mozilla::css::URLValue;
 use gecko_bindings::structs::mozilla::css::URLValueData;
 use gecko_bindings::structs::mozilla::AnonymousCounterStyle;
 use gecko_bindings::structs::mozilla::MallocSizeOf;
 use gecko_bindings::structs::mozilla::OriginFlags;
 use gecko_bindings::structs::mozilla::Side;
 use gecko_bindings::structs::mozilla::UniquePtr;
+use gecko_bindings::structs::ServoRawOffsetArc;
 use gecko_bindings::structs::nsIContent;
 use gecko_bindings::structs::nsIDocument;
 use gecko_bindings::structs::nsIDocument_DocumentTheme;
 use gecko_bindings::structs::RawGeckoAnimationPropertySegment;
 use gecko_bindings::structs::RawGeckoComputedTiming;
 use gecko_bindings::structs::RawGeckoCSSPropertyIDList;
 use gecko_bindings::structs::RawGeckoDocument;
 use gecko_bindings::structs::RawGeckoElement;
@@ -41,16 +42,17 @@ use gecko_bindings::structs::RawServoSty
 use gecko_bindings::structs::RawGeckoPresContext;
 use gecko_bindings::structs::RawGeckoPresContextOwned;
 use gecko_bindings::structs::RawGeckoStyleAnimationList;
 use gecko_bindings::structs::RawGeckoStyleChildrenIterator;
 use gecko_bindings::structs::RawGeckoServoStyleRuleList;
 use gecko_bindings::structs::RawGeckoURLExtraData;
 use gecko_bindings::structs::RawGeckoXBLBinding;
 use gecko_bindings::structs::RefPtr;
+use gecko_bindings::structs::RustString;
 use gecko_bindings::structs::CSSPseudoClassType;
 use gecko_bindings::structs::CSSPseudoElementType;
 use gecko_bindings::structs::ServoTraversalFlags;
 use gecko_bindings::structs::ComputedTimingFunction_BeforeFlag;
 use gecko_bindings::structs::CounterStylePtr;
 use gecko_bindings::structs::FontFamilyList;
 use gecko_bindings::structs::FontFamilyType;
 use gecko_bindings::structs::FontSizePrefs;
@@ -993,17 +995,23 @@ extern "C" {
 }
 extern "C" {
     pub fn Gecko_AddRefImageValueArbitraryThread(aPtr: *mut ImageValue);
 }
 extern "C" {
     pub fn Gecko_ReleaseImageValueArbitraryThread(aPtr: *mut ImageValue);
 }
 extern "C" {
-    pub fn Gecko_ImageValue_Create(aURI: ServoBundledURI) -> *mut ImageValue;
+    pub fn Gecko_ImageValue_Create(aURI: ServoBundledURI,
+                                   aURIString: ServoRawOffsetArc<RustString>)
+     -> *mut ImageValue;
+}
+extern "C" {
+    pub fn Gecko_ImageValue_SizeOfIncludingThis(aImageValue: *mut ImageValue)
+     -> usize;
 }
 extern "C" {
     pub fn Gecko_SetLayerImageImageValue(image: *mut nsStyleImage,
                                          aImageValue: *mut ImageValue);
 }
 extern "C" {
     pub fn Gecko_SetImageElement(image: *mut nsStyleImage,
                                  atom: *mut nsIAtom);
--- a/servo/components/style/gecko/generated/structs_debug.rs
+++ b/servo/components/style/gecko/generated/structs_debug.rs
@@ -1722,27 +1722,62 @@ pub mod root {
             #[repr(C)]
             pub struct URLValueData__bindgen_vtable(::std::os::raw::c_void);
             #[repr(C)]
             #[derive(Debug)]
             pub struct URLValueData {
                 pub vtable_: *const URLValueData__bindgen_vtable,
                 pub mRefCnt: root::mozilla::ThreadSafeAutoRefCnt,
                 pub mURI: root::nsMainThreadPtrHandle<root::nsIURI>,
-                pub mString: ::nsstring::nsStringRepr,
                 pub mExtraData: root::RefPtr<root::mozilla::URLExtraData>,
                 pub mURIResolved: bool,
                 pub mIsLocalRef: [u8; 2usize],
                 pub mMightHaveRef: [u8; 2usize],
+                pub mStrings: root::mozilla::css::URLValueData_RustOrGeckoString,
+                pub mUsingRustString: bool,
             }
             pub type URLValueData_HasThreadSafeRefCnt =
                 root::mozilla::TrueType;
+            #[repr(C)]
+            #[derive(Debug)]
+            pub struct URLValueData_RustOrGeckoString {
+                pub mString: root::__BindgenUnionField<::nsstring::nsStringRepr>,
+                pub mRustString: root::__BindgenUnionField<::gecko_bindings::structs::ServoRawOffsetArc<root::RustString>>,
+                pub bindgen_union_field: [u64; 2usize],
+            }
+            #[test]
+            fn bindgen_test_layout_URLValueData_RustOrGeckoString() {
+                assert_eq!(::std::mem::size_of::<URLValueData_RustOrGeckoString>()
+                           , 16usize , concat ! (
+                           "Size of: " , stringify ! (
+                           URLValueData_RustOrGeckoString ) ));
+                assert_eq! (::std::mem::align_of::<URLValueData_RustOrGeckoString>()
+                            , 8usize , concat ! (
+                            "Alignment of " , stringify ! (
+                            URLValueData_RustOrGeckoString ) ));
+                assert_eq! (unsafe {
+                            & (
+                            * ( 0 as * const URLValueData_RustOrGeckoString )
+                            ) . mString as * const _ as usize } , 0usize ,
+                            concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData_RustOrGeckoString ) , "::" ,
+                            stringify ! ( mString ) ));
+                assert_eq! (unsafe {
+                            & (
+                            * ( 0 as * const URLValueData_RustOrGeckoString )
+                            ) . mRustString as * const _ as usize } , 0usize ,
+                            concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData_RustOrGeckoString ) , "::" ,
+                            stringify ! ( mRustString ) ));
+            }
             #[test]
             fn bindgen_test_layout_URLValueData() {
-                assert_eq!(::std::mem::size_of::<URLValueData>() , 56usize ,
+                assert_eq!(::std::mem::size_of::<URLValueData>() , 64usize ,
                            concat ! (
                            "Size of: " , stringify ! ( URLValueData ) ));
                 assert_eq! (::std::mem::align_of::<URLValueData>() , 8usize ,
                             concat ! (
                             "Alignment of " , stringify ! ( URLValueData ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) . mRefCnt as
                             * const _ as usize } , 8usize , concat ! (
@@ -1750,86 +1785,93 @@ pub mod root {
                             URLValueData ) , "::" , stringify ! ( mRefCnt )
                             ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) . mURI as *
                             const _ as usize } , 16usize , concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mURI ) ));
                 assert_eq! (unsafe {
-                            & ( * ( 0 as * const URLValueData ) ) . mString as
-                            * const _ as usize } , 24usize , concat ! (
-                            "Alignment of field: " , stringify ! (
-                            URLValueData ) , "::" , stringify ! ( mString )
-                            ));
-                assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) . mExtraData
-                            as * const _ as usize } , 40usize , concat ! (
+                            as * const _ as usize } , 24usize , concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mExtraData )
                             ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) .
-                            mURIResolved as * const _ as usize } , 48usize ,
+                            mURIResolved as * const _ as usize } , 32usize ,
                             concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mURIResolved
                             ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) .
-                            mIsLocalRef as * const _ as usize } , 49usize ,
+                            mIsLocalRef as * const _ as usize } , 33usize ,
                             concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mIsLocalRef
                             ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) .
-                            mMightHaveRef as * const _ as usize } , 51usize ,
+                            mMightHaveRef as * const _ as usize } , 35usize ,
                             concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! (
                             mMightHaveRef ) ));
+                assert_eq! (unsafe {
+                            & ( * ( 0 as * const URLValueData ) ) . mStrings
+                            as * const _ as usize } , 40usize , concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData ) , "::" , stringify ! ( mStrings )
+                            ));
+                assert_eq! (unsafe {
+                            & ( * ( 0 as * const URLValueData ) ) .
+                            mUsingRustString as * const _ as usize } , 56usize
+                            , concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData ) , "::" , stringify ! (
+                            mUsingRustString ) ));
             }
             #[repr(C)]
             #[derive(Debug)]
             pub struct URLValue {
                 pub _base: root::mozilla::css::URLValueData,
             }
             #[test]
             fn bindgen_test_layout_URLValue() {
-                assert_eq!(::std::mem::size_of::<URLValue>() , 56usize ,
+                assert_eq!(::std::mem::size_of::<URLValue>() , 64usize ,
                            concat ! ( "Size of: " , stringify ! ( URLValue )
                            ));
                 assert_eq! (::std::mem::align_of::<URLValue>() , 8usize ,
                             concat ! (
                             "Alignment of " , stringify ! ( URLValue ) ));
             }
             #[repr(C)]
             #[derive(Debug)]
             pub struct ImageValue {
                 pub _base: root::mozilla::css::URLValueData,
                 pub mRequests: [u64; 6usize],
                 pub mLoadedImage: bool,
             }
             #[test]
             fn bindgen_test_layout_ImageValue() {
-                assert_eq!(::std::mem::size_of::<ImageValue>() , 112usize ,
+                assert_eq!(::std::mem::size_of::<ImageValue>() , 120usize ,
                            concat ! ( "Size of: " , stringify ! ( ImageValue )
                            ));
                 assert_eq! (::std::mem::align_of::<ImageValue>() , 8usize ,
                             concat ! (
                             "Alignment of " , stringify ! ( ImageValue ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const ImageValue ) ) . mRequests as
-                            * const _ as usize } , 56usize , concat ! (
+                            * const _ as usize } , 64usize , concat ! (
                             "Alignment of field: " , stringify ! ( ImageValue
                             ) , "::" , stringify ! ( mRequests ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const ImageValue ) ) . mLoadedImage
-                            as * const _ as usize } , 104usize , concat ! (
+                            as * const _ as usize } , 112usize , concat ! (
                             "Alignment of field: " , stringify ! ( ImageValue
                             ) , "::" , stringify ! ( mLoadedImage ) ));
             }
             #[repr(C)]
             #[derive(Debug)]
             pub struct GridNamedArea {
                 pub mName: ::nsstring::nsStringRepr,
                 pub mColumnStart: u32,
@@ -28796,16 +28838,21 @@ pub mod root {
                                     (8u64 as u8))
                        } |
                            ((mDeferNotifications as u8 as u8) << 4usize) &
                                (16u64 as u8))
                   } | ((mHadListener as u8 as u8) << 5usize) & (32u64 as u8))
              } | ((mHadDispatch as u8 as u8) << 6usize) & (64u64 as u8))
         }
     }
+    #[repr(C)]
+    #[derive(Debug, Copy, Clone)]
+    pub struct RustString {
+        _unused: [u8; 0],
+    }
     #[repr(u32)]
     #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
     pub enum nsCSSUnit {
         eCSSUnit_Null = 0,
         eCSSUnit_Auto = 1,
         eCSSUnit_Inherit = 2,
         eCSSUnit_Initial = 3,
         eCSSUnit_Unset = 4,
--- a/servo/components/style/gecko/generated/structs_release.rs
+++ b/servo/components/style/gecko/generated/structs_release.rs
@@ -1686,27 +1686,62 @@ pub mod root {
             #[repr(C)]
             pub struct URLValueData__bindgen_vtable(::std::os::raw::c_void);
             #[repr(C)]
             #[derive(Debug)]
             pub struct URLValueData {
                 pub vtable_: *const URLValueData__bindgen_vtable,
                 pub mRefCnt: root::mozilla::ThreadSafeAutoRefCnt,
                 pub mURI: root::nsMainThreadPtrHandle<root::nsIURI>,
-                pub mString: ::nsstring::nsStringRepr,
                 pub mExtraData: root::RefPtr<root::mozilla::URLExtraData>,
                 pub mURIResolved: bool,
                 pub mIsLocalRef: [u8; 2usize],
                 pub mMightHaveRef: [u8; 2usize],
+                pub mStrings: root::mozilla::css::URLValueData_RustOrGeckoString,
+                pub mUsingRustString: bool,
             }
             pub type URLValueData_HasThreadSafeRefCnt =
                 root::mozilla::TrueType;
+            #[repr(C)]
+            #[derive(Debug)]
+            pub struct URLValueData_RustOrGeckoString {
+                pub mString: root::__BindgenUnionField<::nsstring::nsStringRepr>,
+                pub mRustString: root::__BindgenUnionField<::gecko_bindings::structs::ServoRawOffsetArc<root::RustString>>,
+                pub bindgen_union_field: [u64; 2usize],
+            }
+            #[test]
+            fn bindgen_test_layout_URLValueData_RustOrGeckoString() {
+                assert_eq!(::std::mem::size_of::<URLValueData_RustOrGeckoString>()
+                           , 16usize , concat ! (
+                           "Size of: " , stringify ! (
+                           URLValueData_RustOrGeckoString ) ));
+                assert_eq! (::std::mem::align_of::<URLValueData_RustOrGeckoString>()
+                            , 8usize , concat ! (
+                            "Alignment of " , stringify ! (
+                            URLValueData_RustOrGeckoString ) ));
+                assert_eq! (unsafe {
+                            & (
+                            * ( 0 as * const URLValueData_RustOrGeckoString )
+                            ) . mString as * const _ as usize } , 0usize ,
+                            concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData_RustOrGeckoString ) , "::" ,
+                            stringify ! ( mString ) ));
+                assert_eq! (unsafe {
+                            & (
+                            * ( 0 as * const URLValueData_RustOrGeckoString )
+                            ) . mRustString as * const _ as usize } , 0usize ,
+                            concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData_RustOrGeckoString ) , "::" ,
+                            stringify ! ( mRustString ) ));
+            }
             #[test]
             fn bindgen_test_layout_URLValueData() {
-                assert_eq!(::std::mem::size_of::<URLValueData>() , 56usize ,
+                assert_eq!(::std::mem::size_of::<URLValueData>() , 64usize ,
                            concat ! (
                            "Size of: " , stringify ! ( URLValueData ) ));
                 assert_eq! (::std::mem::align_of::<URLValueData>() , 8usize ,
                             concat ! (
                             "Alignment of " , stringify ! ( URLValueData ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) . mRefCnt as
                             * const _ as usize } , 8usize , concat ! (
@@ -1714,86 +1749,93 @@ pub mod root {
                             URLValueData ) , "::" , stringify ! ( mRefCnt )
                             ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) . mURI as *
                             const _ as usize } , 16usize , concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mURI ) ));
                 assert_eq! (unsafe {
-                            & ( * ( 0 as * const URLValueData ) ) . mString as
-                            * const _ as usize } , 24usize , concat ! (
-                            "Alignment of field: " , stringify ! (
-                            URLValueData ) , "::" , stringify ! ( mString )
-                            ));
-                assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) . mExtraData
-                            as * const _ as usize } , 40usize , concat ! (
+                            as * const _ as usize } , 24usize , concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mExtraData )
                             ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) .
-                            mURIResolved as * const _ as usize } , 48usize ,
+                            mURIResolved as * const _ as usize } , 32usize ,
                             concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mURIResolved
                             ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) .
-                            mIsLocalRef as * const _ as usize } , 49usize ,
+                            mIsLocalRef as * const _ as usize } , 33usize ,
                             concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! ( mIsLocalRef
                             ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const URLValueData ) ) .
-                            mMightHaveRef as * const _ as usize } , 51usize ,
+                            mMightHaveRef as * const _ as usize } , 35usize ,
                             concat ! (
                             "Alignment of field: " , stringify ! (
                             URLValueData ) , "::" , stringify ! (
                             mMightHaveRef ) ));
+                assert_eq! (unsafe {
+                            & ( * ( 0 as * const URLValueData ) ) . mStrings
+                            as * const _ as usize } , 40usize , concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData ) , "::" , stringify ! ( mStrings )
+                            ));
+                assert_eq! (unsafe {
+                            & ( * ( 0 as * const URLValueData ) ) .
+                            mUsingRustString as * const _ as usize } , 56usize
+                            , concat ! (
+                            "Alignment of field: " , stringify ! (
+                            URLValueData ) , "::" , stringify ! (
+                            mUsingRustString ) ));
             }
             #[repr(C)]
             #[derive(Debug)]
             pub struct URLValue {
                 pub _base: root::mozilla::css::URLValueData,
             }
             #[test]
             fn bindgen_test_layout_URLValue() {
-                assert_eq!(::std::mem::size_of::<URLValue>() , 56usize ,
+                assert_eq!(::std::mem::size_of::<URLValue>() , 64usize ,
                            concat ! ( "Size of: " , stringify ! ( URLValue )
                            ));
                 assert_eq! (::std::mem::align_of::<URLValue>() , 8usize ,
                             concat ! (
                             "Alignment of " , stringify ! ( URLValue ) ));
             }
             #[repr(C)]
             #[derive(Debug)]
             pub struct ImageValue {
                 pub _base: root::mozilla::css::URLValueData,
                 pub mRequests: [u64; 5usize],
                 pub mLoadedImage: bool,
             }
             #[test]
             fn bindgen_test_layout_ImageValue() {
-                assert_eq!(::std::mem::size_of::<ImageValue>() , 104usize ,
+                assert_eq!(::std::mem::size_of::<ImageValue>() , 112usize ,
                            concat ! ( "Size of: " , stringify ! ( ImageValue )
                            ));
                 assert_eq! (::std::mem::align_of::<ImageValue>() , 8usize ,
                             concat ! (
                             "Alignment of " , stringify ! ( ImageValue ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const ImageValue ) ) . mRequests as
-                            * const _ as usize } , 56usize , concat ! (
+                            * const _ as usize } , 64usize , concat ! (
                             "Alignment of field: " , stringify ! ( ImageValue
                             ) , "::" , stringify ! ( mRequests ) ));
                 assert_eq! (unsafe {
                             & ( * ( 0 as * const ImageValue ) ) . mLoadedImage
-                            as * const _ as usize } , 96usize , concat ! (
+                            as * const _ as usize } , 104usize , concat ! (
                             "Alignment of field: " , stringify ! ( ImageValue
                             ) , "::" , stringify ! ( mLoadedImage ) ));
             }
             #[repr(C)]
             #[derive(Debug)]
             pub struct GridNamedArea {
                 pub mName: ::nsstring::nsStringRepr,
                 pub mColumnStart: u32,
@@ -28441,16 +28483,21 @@ pub mod root {
                                     (8u64 as u8))
                        } |
                            ((mDeferNotifications as u8 as u8) << 4usize) &
                                (16u64 as u8))
                   } | ((mHadListener as u8 as u8) << 5usize) & (32u64 as u8))
              } | ((mHadDispatch as u8 as u8) << 6usize) & (64u64 as u8))
         }
     }
+    #[repr(C)]
+    #[derive(Debug, Copy, Clone)]
+    pub struct RustString {
+        _unused: [u8; 0],
+    }
     #[repr(u32)]
     #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
     pub enum nsCSSUnit {
         eCSSUnit_Null = 0,
         eCSSUnit_Auto = 1,
         eCSSUnit_Inherit = 2,
         eCSSUnit_Initial = 3,
         eCSSUnit_Unset = 4,
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -1,41 +1,40 @@
 /* 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 gecko_bindings::structs::{ServoBundledURI, URLExtraData};
 use gecko_bindings::structs::mozilla::css::URLValueData;
+use gecko_bindings::structs::root::{nsStyleImageRequest, RustString};
 use gecko_bindings::structs::root::mozilla::css::ImageValue;
-use gecko_bindings::structs::root::nsStyleImageRequest;
 use gecko_bindings::sugar::refptr::RefPtr;
+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use parser::ParserContext;
-use servo_arc::Arc;
+use servo_arc::{Arc, RawOffsetArc};
 use std::fmt;
+use std::mem;
 use style_traits::{ToCss, ParseError};
 
 /// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls.
-#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct SpecifiedUrl {
     /// The URL in unresolved string form.
     ///
     /// Refcounted since cloning this should be cheap and data: uris can be
     /// really large.
-    #[ignore_malloc_size_of = "XXX: do this once bug 1397971 lands"]
     serialization: Arc<String>,
 
     /// The URL extra data.
-    #[ignore_malloc_size_of = "RefPtr is tricky, and there aren't many of these in practise"]
     pub extra_data: RefPtr<URLExtraData>,
 
     /// Cache ImageValue, if any, so that we can reuse it while rematching a
     /// a property with this specified url value.
-    #[ignore_malloc_size_of = "XXX: do this once bug 1397971 lands"]
     pub image_value: Option<RefPtr<ImageValue>>,
 }
 trivial_to_computed_value!(SpecifiedUrl);
 
 impl SpecifiedUrl {
     /// Try to parse a URL from a string value that is a valid CSS token for a
     /// URL.
     ///
@@ -56,17 +55,24 @@ impl SpecifiedUrl {
     pub fn is_invalid(&self) -> bool {
         false
     }
 
     /// Convert from URLValueData to SpecifiedUrl.
     pub unsafe fn from_url_value_data(url: &URLValueData)
                                        -> Result<SpecifiedUrl, ()> {
         Ok(SpecifiedUrl {
-            serialization: Arc::new(url.mString.to_string()),
+            serialization: if url.mUsingRustString {
+                let arc_type = url.mStrings.mRustString.as_ref()
+                    as *const _ as
+                    *const RawOffsetArc<String>;
+                Arc::from_raw_offset((*arc_type).clone())
+            } else {
+                Arc::new(url.mStrings.mString.as_ref().to_string())
+            },
             extra_data: url.mExtraData.to_safe(),
             image_value: None,
         })
     }
 
     /// Convert from nsStyleImageRequest to SpecifiedUrl.
     pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result<SpecifiedUrl, ()> {
         if image_request.mImageValue.mRawPtr.is_null() {
@@ -112,24 +118,49 @@ impl SpecifiedUrl {
 
     /// Build and carry an image value on request.
     pub fn build_image_value(&mut self) {
         use gecko_bindings::bindings::Gecko_ImageValue_Create;
 
         debug_assert_eq!(self.image_value, None);
         self.image_value = {
             unsafe {
-                let ptr = Gecko_ImageValue_Create(self.for_ffi());
+                let arc_offset = Arc::into_raw_offset(self.serialization.clone());
+                let ptr = Gecko_ImageValue_Create(
+                    self.for_ffi(),
+                    mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset));
                 // We do not expect Gecko_ImageValue_Create returns null.
                 debug_assert!(!ptr.is_null());
                 Some(RefPtr::from_addrefed(ptr))
             }
         }
     }
 }
 
 impl ToCss for SpecifiedUrl {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         dest.write_str("url(")?;
         self.serialization.to_css(dest)?;
         dest.write_str(")")
     }
 }
+
+impl MallocSizeOf for SpecifiedUrl {
+    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
+        use gecko_bindings::bindings::Gecko_ImageValue_SizeOfIncludingThis;
+
+        let mut n = 0;
+
+        // XXX: measure `serialization` once bug 1397971 lands
+
+        // We ignore `extra_data`, because RefPtr is tricky, and there aren't
+        // many of them in practise (sharing is common).
+
+        if let Some(ref image_value) = self.image_value {
+            // Although this is a RefPtr, this is the primary reference because
+            // SpecifiedUrl is responsible for creating the image_value. So we
+            // measure unconditionally here.
+            n += unsafe { Gecko_ImageValue_SizeOfIncludingThis(image_value.clone().get()) };
+        }
+
+        n
+    }
+}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -8,16 +8,17 @@ use env_logger::LogBuilder;
 use malloc_size_of::MallocSizeOfOps;
 use selectors::Element;
 use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
 use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
 use std::cell::RefCell;
 use std::env;
 use std::fmt::Write;
 use std::iter;
+use std::mem;
 use std::ptr;
 use style::applicable_declarations::ApplicableDeclarationBlock;
 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
 use style::context::ThreadLocalStyleContext;
 use style::data::ElementStyles;
 use style::dom::{ShowSubtreeData, TElement, TNode};
 use style::driver;
 use style::element_state::ElementState;
@@ -72,17 +73,17 @@ use style::gecko_bindings::bindings::Raw
 use style::gecko_bindings::bindings::RawServoStyleSet;
 use style::gecko_bindings::bindings::ServoStyleContextBorrowedOrNull;
 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::{CSSPseudoElementType, CompositeOperation};
 use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
-use style::gecko_bindings::structs::{RawServoStyleRule, ServoStyleContextStrong};
+use style::gecko_bindings::structs::{RawServoStyleRule, ServoStyleContextStrong, RustString};
 use style::gecko_bindings::structs::{ServoStyleSheet, SheetParsingMode, nsIAtom, nsCSSPropertyID};
 use style::gecko_bindings::structs::{nsCSSFontFaceRule, nsCSSCounterStyleRule};
 use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair};
 use style::gecko_bindings::structs::IterationCompositeOperation;
 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
 use style::gecko_bindings::structs::OriginFlags;
 use style::gecko_bindings::structs::OriginFlags_Author;
 use style::gecko_bindings::structs::OriginFlags_User;
@@ -3830,16 +3831,41 @@ 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_CloneArcStringData(string: *const RawOffsetArc<RustString>)
+                                                  -> RawOffsetArc<RustString> {
+    let string = string as *const RawOffsetArc<String>;
+    let cloned = (*string).clone();
+    mem::transmute::<_, RawOffsetArc<RustString>>(cloned)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_GetArcStringData(string: *const RustString,
+                                                utf8_chars: *mut *const u8,
+                                                utf8_len: *mut u32)
+{
+    let string = &*(string as *const String);
+    *utf8_len = string.len() as u32;
+    *utf8_chars = string.as_ptr();
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_ProcessInvalidations(set: RawServoStyleSetBorrowed,
                                              element: RawGeckoElementBorrowed,
                                              snapshots: *const ServoElementSnapshotTable) {
     debug_assert!(!snapshots.is_null());
 
     let element = GeckoElement(element);
     debug_assert!(element.has_snapshot());
     debug_assert!(!element.handled_snapshot());