Bug 1495994 - Part 4: Merge css::{URLValueData, ImageValue} into css::URLValue r=emilio
authorCameron McCormack <cam@mcc.id.au>
Wed, 10 Oct 2018 02:58:20 +0000
changeset 496148 f6e5bc9af12f1decb7092762aef1e9cd1a768dd6
parent 496147 48b5f15672ab54771cc7df97be6e7b3a76b201f8
child 496149 8d795e0fa2851bcb88d886ad5197aee8bffb22f6
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1495994
milestone64.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 1495994 - Part 4: Merge css::{URLValueData, ImageValue} into css::URLValue r=emilio Depends on D7595 Differential Revision: https://phabricator.services.mozilla.com/D8061
layout/style/ImageLoader.cpp
layout/style/ImageLoader.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/svg/SVGObserverUtils.cpp
servo/components/style/gecko/conversions.rs
servo/components/style/gecko/url.rs
servo/components/style/gecko_bindings/sugar/refptr.rs
servo/components/style/properties/gecko.mako.rs
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -48,17 +48,17 @@ ImageLoader::DropDocumentReference()
   // been destroyed, and it also calls ClearFrames when it is destroyed.
   ClearFrames(GetPresContext());
 
   for (auto it = mRegisteredImages.Iter(); !it.Done(); it.Next()) {
     if (imgRequestProxy* request = it.Data()) {
       request->CancelAndForgetObserver(NS_BINDING_ABORTED);
     }
 
-    // Need to check whether the entry exists, since the css::ImageValue might
+    // Need to check whether the entry exists, since the css::URLValue might
     // go away before ImageLoader::DropDocumentReference is called.
     uint64_t imageLoadID = it.Key();
     if (auto entry = sImages->Lookup(imageLoadID)) {
       entry.Data()->mImageLoaders.RemoveEntry(this);
     }
   }
 
   mRegisteredImages.Clear();
@@ -203,17 +203,17 @@ ImageLoader::AssociateRequestToFrame(img
     didAddToRequestSet = true;
   }
 
   MOZ_ASSERT(didAddToFrameSet == didAddToRequestSet,
              "We should only add to one map iff we also add to the other map.");
 }
 
 imgRequestProxy*
-ImageLoader::RegisterCSSImage(ImageLoader::Image* aImage)
+ImageLoader::RegisterCSSImage(URLValue* aImage)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aImage);
 
   if (aImage->LoadID() == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return nullptr;
   }
@@ -249,17 +249,17 @@ ImageLoader::RegisterCSSImage(ImageLoade
   MOZ_ASSERT(!mRegisteredImages.Contains(aImage->LoadID()));
 
   imgRequestProxy* requestWeak = request;
   mRegisteredImages.Put(aImage->LoadID(), request.forget());
   return requestWeak;
 }
 
 /* static */ void
-ImageLoader::DeregisterCSSImageFromAllLoaders(ImageLoader::Image* aImage)
+ImageLoader::DeregisterCSSImageFromAllLoaders(URLValue* aImage)
 {
   MOZ_ASSERT(aImage);
 
   uint64_t loadID = aImage->LoadID();
 
   if (loadID == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return;
@@ -450,31 +450,31 @@ ImageLoader::ClearFrames(nsPresContext* 
 }
 
 /* static */ void
 ImageLoader::LoadImage(nsIURI* aURI,
                        nsIPrincipal* aOriginPrincipal,
                        nsIURI* aReferrer,
                        mozilla::net::ReferrerPolicy aPolicy,
                        nsIDocument* aDocument,
-                       ImageLoader::Image* aImage,
+                       URLValue* aImage,
                        CORSMode aCorsMode)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aDocument);
   MOZ_ASSERT(aImage);
   MOZ_ASSERT(aImage->LoadID() != 0);
 
   if (aImage->LoadID() == 0) {
     MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
     return;
   }
 
   if (sImages->Contains(aImage->LoadID())) {
-    // This css::ImageValue has already been loaded.
+    // This css::URLValue has already been loaded.
     return;
   }
 
   ImageTableEntry* entry = new ImageTableEntry();
   sImages->Put(aImage->LoadID(), entry);
 
   if (!aURI) {
     return;
--- a/layout/style/ImageLoader.h
+++ b/layout/style/ImageLoader.h
@@ -26,17 +26,17 @@ class nsIFrame;
 class nsIDocument;
 class nsPresContext;
 class nsIURI;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace css {
 
-struct ImageValue;
+struct URLValue;
 
 /**
  * NOTE: All methods must be called from the main thread unless otherwise
  * specified.
  */
 class ImageLoader final : public imgINotificationObserver
 {
 public:
@@ -46,31 +46,29 @@ public:
   // We also associate flags alongside frames in the request-to-frames hashmap.
   // These are used for special handling of events for requests.
   typedef uint32_t FrameFlags;
   enum {
     REQUEST_REQUIRES_REFLOW      = 1u << 0,
     REQUEST_HAS_BLOCKED_ONLOAD   = 1u << 1,
   };
 
-  typedef mozilla::css::ImageValue Image;
-
   explicit ImageLoader(nsIDocument* aDocument)
   : mDocument(aDocument),
     mInClone(false)
   {
     MOZ_ASSERT(mDocument);
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_IMGINOTIFICATIONOBSERVER
 
   void DropDocumentReference();
 
-  imgRequestProxy* RegisterCSSImage(Image* aImage);
+  imgRequestProxy* RegisterCSSImage(URLValue* aImage);
 
   void AssociateRequestToFrame(imgIRequest* aRequest,
                                nsIFrame* aFrame,
                                FrameFlags aFlags);
 
   void DisassociateRequestFromFrame(imgIRequest* aRequest,
                                     nsIFrame* aFrame);
 
@@ -83,24 +81,24 @@ public:
   // presshell pointer on the document has been cleared.
   void ClearFrames(nsPresContext* aPresContext);
 
   static void LoadImage(nsIURI* aURI,
                         nsIPrincipal* aPrincipal,
                         nsIURI* aReferrer,
                         mozilla::net::ReferrerPolicy aPolicy,
                         nsIDocument* aDocument,
-                        Image* aCSSValue,
+                        URLValue* aImage,
                         CORSMode aCorsMode);
 
-  // Cancels the image load for the given css::ImageValue and deregisters
+  // Cancels the image load for the given css::URLValue and deregisters
   // it from any ImageLoaders it was registered with.
   //
   // May be called from any thread.
-  static void DeregisterCSSImageFromAllLoaders(Image* aImage);
+  static void DeregisterCSSImageFromAllLoaders(URLValue* aImage);
 
   void FlushUseCounters();
 
 private:
   // This callback is used to unblock document onload after a reflow
   // triggered from an image load.
   struct ImageReflowCallback final : public nsIReflowCallback
   {
@@ -182,49 +180,49 @@ private:
   RequestToFrameMap mRequestToFrameMap;
 
   // A map of nsIFrames to the imgIRequests they use.
   FrameToRequestMap mFrameToRequestMap;
 
   // A weak pointer to our document. Nulled out by DropDocumentReference.
   nsIDocument* mDocument;
 
-  // A map of css::ImageValues, keyed by their LoadID(), to the imgRequestProxy
+  // A map of css::URLValues, keyed by their LoadID(), to the imgRequestProxy
   // representing the load of the image for this ImageLoader's document.
   //
   // We use the LoadID() as the key since we can only access mRegisteredImages
-  // on the main thread, but css::ImageValues might be destroyed from other
+  // on the main thread, but css::URLValues might be destroyed from other
   // threads, and we don't want to leave dangling pointers around.
   nsRefPtrHashtable<nsUint64HashKey, imgRequestProxy> mRegisteredImages;
 
   // Are we cloning?  If so, ignore any notifications we get.
   bool mInClone;
 
-  // Data associated with every css::ImageValue object that has had a load
+  // Data associated with every css::URLValue object that has had a load
   // started.
   struct ImageTableEntry
   {
-    // Set of all ImageLoaders that have registered this css::ImageValue.
+    // Set of all ImageLoaders that have registered this css::URLValue.
     nsTHashtable<nsPtrHashKey<ImageLoader>> mImageLoaders;
 
-    // The "canonical" image request for this css::ImageValue.
+    // The "canonical" image request for this css::URLValue.
     //
-    // This request is held on to as long as the specified css::ImageValue
+    // This request is held on to as long as the specified css::URLValue
     // object is, so that any image that has already started loading (or
     // has completed loading) will stay alive even if all computed values
     // referencing the image requesst have gone away.
     RefPtr<imgRequestProxy> mCanonicalRequest;
   };
 
-  // A table of all css::ImageValues that have been loaded, keyed by their
+  // A table of all css::URLValues that have been loaded, keyed by their
   // LoadID(), mapping them to the set of ImageLoaders they have been registered
   // in, and recording their "canonical" image request.
   //
   // We use the LoadID() as the key since we can only access sImages on the
-  // main thread, but css::ImageValues might be destroyed from other threads,
+  // main thread, but css::URLValues might be destroyed from other threads,
   // and we don't want to leave dangling pointers around.
   static nsClassHashtable<nsUint64HashKey, ImageTableEntry>* sImages;
 };
 
 } // namespace css
 } // namespace mozilla
 
 #endif /* mozilla_css_ImageLoader_h___ */
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1381,31 +1381,22 @@ Gecko_CounterStyle_GetName(const Counter
 
 const AnonymousCounterStyle*
 Gecko_CounterStyle_GetAnonymous(const CounterStylePtr* aPtr)
 {
   return aPtr->AsAnonymous();
 }
 
 already_AddRefed<css::URLValue>
-ServoBundledURI::IntoCssUrl()
+ServoBundledURI::IntoCssUrl(CORSMode aCorsMode)
 {
-  MOZ_ASSERT(mExtraData->GetReferrer());
   MOZ_ASSERT(mExtraData->GetPrincipal());
 
   RefPtr<css::URLValue> urlValue =
-    new css::URLValue(mURLString, do_AddRef(mExtraData), CORSMode::CORS_NONE);
-  return urlValue.forget();
-}
-
-already_AddRefed<css::ImageValue>
-ServoBundledURI::IntoCssImage(mozilla::CORSMode aCorsMode)
-{
-  RefPtr<css::ImageValue> urlValue =
-    new css::ImageValue(mURLString, do_AddRef(mExtraData), aCorsMode);
+    new css::URLValue(mURLString, do_AddRef(mExtraData), aCorsMode);
   return urlValue.forget();
 }
 
 void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
   MOZ_ASSERT(aImage);
   aImage->SetNull();
@@ -1413,45 +1404,28 @@ Gecko_SetNullImageValue(nsStyleImage* aI
 
 void
 Gecko_SetGradientImageValue(nsStyleImage* aImage, nsStyleGradient* aGradient)
 {
   MOZ_ASSERT(aImage);
   aImage->SetGradientData(aGradient);
 }
 
-NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::ImageValue, ImageValue);
-
 static already_AddRefed<nsStyleImageRequest>
 CreateStyleImageRequest(nsStyleImageRequest::Mode aModeFlags,
-                        mozilla::css::ImageValue* aImageValue)
+                        URLValue* aImageValue)
 {
   RefPtr<nsStyleImageRequest> req =
     new nsStyleImageRequest(aModeFlags, aImageValue);
   return req.forget();
 }
 
-mozilla::css::ImageValue*
-Gecko_ImageValue_Create(ServoBundledURI aURI, mozilla::CORSMode aCORSMode)
-{
-  return aURI.IntoCssImage(aCORSMode).take();
-}
-
-MOZ_DEFINE_MALLOC_SIZE_OF(GeckoImageValueMallocSizeOf)
-
-size_t
-Gecko_ImageValue_SizeOfIncludingThis(mozilla::css::ImageValue* aImageValue)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  return aImageValue->SizeOfIncludingThis(GeckoImageValueMallocSizeOf);
-}
-
 void
 Gecko_SetLayerImageImageValue(nsStyleImage* aImage,
-                              mozilla::css::ImageValue* aImageValue)
+                              URLValue* aImageValue)
 {
   MOZ_ASSERT(aImage && aImageValue);
 
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
   aImage->SetImageRequest(req.forget());
 }
 
@@ -1481,33 +1455,33 @@ void
 Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen)
 {
   aStyleUI->mCursorImages.Clear();
   aStyleUI->mCursorImages.SetLength(aLen);
 }
 
 void
 Gecko_SetCursorImageValue(nsCursorImage* aCursor,
-                          mozilla::css::ImageValue* aImageValue)
+                          URLValue* aImageValue)
 {
   MOZ_ASSERT(aCursor && aImageValue);
 
   aCursor->mImage =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aImageValue);
 }
 
 void
 Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc)
 {
   aDest->mCursorImages = aSrc->mCursorImages;
 }
 
 void
 Gecko_SetContentDataImageValue(nsStyleContentData* aContent,
-                               mozilla::css::ImageValue* aImageValue)
+                               URLValue* aImageValue)
 {
   MOZ_ASSERT(aContent && aImageValue);
 
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
   aContent->SetImageRequest(req.forget());
 }
 
@@ -1579,17 +1553,17 @@ Gecko_GetGradientImageValue(const nsStyl
 void
 Gecko_SetListStyleImageNone(nsStyleList* aList)
 {
   aList->mListStyleImage = nullptr;
 }
 
 void
 Gecko_SetListStyleImageImageValue(nsStyleList* aList,
-                             mozilla::css::ImageValue* aImageValue)
+                                  URLValue* aImageValue)
 {
   MOZ_ASSERT(aList && aImageValue);
 
   aList->mListStyleImage =
     CreateStyleImageRequest(nsStyleImageRequest::Mode(0), aImageValue);
 }
 
 void
@@ -1647,27 +1621,27 @@ Gecko_CopyStyleGridTemplateValues(Unique
 {
   if (aOther) {
     *aGridTemplate = MakeUnique<nsStyleGridTemplate>(*aOther);
   } else {
     *aGridTemplate = nullptr;
   }
 }
 
-mozilla::css::GridTemplateAreasValue*
+GridTemplateAreasValue*
 Gecko_NewGridTemplateAreasValue(uint32_t aAreas, uint32_t aTemplates, uint32_t aColumns)
 {
-  RefPtr<mozilla::css::GridTemplateAreasValue> value = new mozilla::css::GridTemplateAreasValue;
+  RefPtr<GridTemplateAreasValue> value = new GridTemplateAreasValue;
   value->mNamedAreas.SetLength(aAreas);
   value->mTemplates.SetLength(aTemplates);
   value->mNColumns = aColumns;
   return value.forget().take();
 }
 
-NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::GridTemplateAreasValue, GridTemplateAreasValue);
+NS_IMPL_THREADSAFE_FFI_REFCOUNTING(GridTemplateAreasValue, GridTemplateAreasValue);
 
 void
 Gecko_ClearAndResizeStyleContents(nsStyleContent* aContent, uint32_t aHowMany)
 {
   aContent->AllocateContents(aHowMany);
 }
 
 void
@@ -2032,45 +2006,45 @@ void
 Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst, const nsStyleSVG* aSrc)
 {
   aDst->mContextProps = aSrc->mContextProps;
   aDst->mContextPropsBits = aSrc->mContextPropsBits;
 }
 
 
 css::URLValue*
-Gecko_NewURLValue(ServoBundledURI aURI)
+Gecko_URLValue_Create(ServoBundledURI aURI, mozilla::CORSMode aCORSMode)
 {
-  RefPtr<css::URLValue> url = aURI.IntoCssUrl();
+  RefPtr<css::URLValue> url = aURI.IntoCssUrl(aCORSMode);
   return url.forget().take();
 }
 
 MOZ_DEFINE_MALLOC_SIZE_OF(GeckoURLValueMallocSizeOf)
 
 size_t
 Gecko_URLValue_SizeOfIncludingThis(URLValue* aURL)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return aURL->SizeOfIncludingThis(GeckoURLValueMallocSizeOf);
 }
 
 void
-Gecko_GetComputedURLSpec(const URLValueData* aURL, nsCString* aOut)
+Gecko_GetComputedURLSpec(const URLValue* aURL, nsCString* aOut)
 {
   MOZ_ASSERT(aURL);
   MOZ_ASSERT(aOut);
   if (aURL->IsLocalRef()) {
     aOut->Assign(aURL->GetString());
     return;
   }
   Gecko_GetComputedImageURLSpec(aURL, aOut);
 }
 
 void
-Gecko_GetComputedImageURLSpec(const URLValueData* aURL, nsCString* aOut)
+Gecko_GetComputedImageURLSpec(const URLValue* aURL, nsCString* aOut)
 {
   // Image URIs don't serialize local refs as local.
   if (nsIURI* uri = aURL->GetURI()) {
     nsresult rv = uri->GetSpec(*aOut);
     if (NS_SUCCEEDED(rv)) {
       return;
     }
   }
@@ -2622,29 +2596,34 @@ StyleSheet*
 Gecko_LoadStyleSheet(css::Loader* aLoader,
                      StyleSheet* aParent,
                      SheetLoadData* aParentLoadData,
                      css::LoaderReusableStyleSheets* aReusableSheets,
                      ServoBundledURI aServoURL,
                      RawServoMediaListStrong aMediaList)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  RefPtr<css::URLValue> url = aServoURL.IntoCssUrl();
+
+  // 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);
   return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
                          url, aMediaList.Consume()).take();
 }
 
 void
 Gecko_LoadStyleSheetAsync(css::SheetLoadDataHolder* aParentData,
                           ServoBundledURI aServoURL,
                           RawServoMediaListStrong aMediaList,
                           RawServoImportRuleStrong aImportRule)
 {
   RefPtr<SheetLoadDataHolder> loadData = aParentData;
-  RefPtr<css::URLValue> urlVal = aServoURL.IntoCssUrl();
+  // 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<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/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -39,17 +39,16 @@ namespace mozilla {
   enum FontFamilyType : uint8_t;
   class SharedFontList;
   enum class CSSPseudoElementType : uint8_t;
   struct Keyframe;
   struct StyleTransition;
   namespace css {
     class ErrorReporter;
     struct URLValue;
-    struct ImageValue;
     class LoaderReusableStyleSheets;
   };
   namespace dom {
     enum class IterationCompositeOperation : uint8_t;
   };
   enum class UpdateAnimationsTasks : uint8_t;
   struct LangGroupFontPrefs;
   class SeenPtrs;
@@ -109,20 +108,19 @@ const bool GECKO_IS_NIGHTLY = false;
 DEFINE_ARRAY_TYPE_FOR(uintptr_t);
 #undef DEFINE_ARRAY_TYPE_FOR
 
 extern "C" {
 
 class ServoBundledURI
 {
 public:
-  // NOTE(emilio): Not calling IntoCssUrl or IntoCssImage will cause to leak the
+  // NOTE(emilio): Not calling IntoCssUrl will cause to leak the
   // string, so don't do that :)
-  already_AddRefed<mozilla::css::URLValue> IntoCssUrl();
-  already_AddRefed<mozilla::css::ImageValue> IntoCssImage(mozilla::CORSMode);
+  already_AddRefed<mozilla::css::URLValue> IntoCssUrl(mozilla::CORSMode);
   mozilla::ServoRawOffsetArc<RustString> mURLString;
   mozilla::URLExtraData* mExtraData;
 };
 
 struct FontSizePrefs
 {
   void CopyFrom(const mozilla::LangGroupFontPrefs&);
   nscoord mDefaultVariableSize;
@@ -347,22 +345,18 @@ void Gecko_CopyCounterStyle(mozilla::Cou
                             const mozilla::CounterStylePtr* src);
 nsAtom* Gecko_CounterStyle_GetName(const mozilla::CounterStylePtr* ptr);
 const mozilla::AnonymousCounterStyle*
 Gecko_CounterStyle_GetAnonymous(const mozilla::CounterStylePtr* ptr);
 
 // background-image style.
 void Gecko_SetNullImageValue(nsStyleImage* image);
 void Gecko_SetGradientImageValue(nsStyleImage* image, nsStyleGradient* gradient);
-NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::ImageValue, ImageValue);
-mozilla::css::ImageValue* Gecko_ImageValue_Create(ServoBundledURI aURI,
-                                                  mozilla::CORSMode aCORSMode);
-size_t Gecko_ImageValue_SizeOfIncludingThis(mozilla::css::ImageValue* aImageValue);
 void Gecko_SetLayerImageImageValue(nsStyleImage* image,
-                                   mozilla::css::ImageValue* aImageValue);
+                                   mozilla::css::URLValue* image_value);
 
 void Gecko_SetImageElement(nsStyleImage* image, nsAtom* atom);
 void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
 void Gecko_InitializeImageCropRect(nsStyleImage* image);
 
 nsStyleGradient* Gecko_CreateGradient(uint8_t shape,
                                       uint8_t size,
                                       bool repeating,
@@ -372,27 +366,27 @@ nsStyleGradient* Gecko_CreateGradient(ui
 
 const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* image);
 nsAtom* Gecko_GetImageElement(const nsStyleImage* image);
 const nsStyleGradient* Gecko_GetGradientImageValue(const nsStyleImage* image);
 
 // list-style-image style.
 void Gecko_SetListStyleImageNone(nsStyleList* style_struct);
 void Gecko_SetListStyleImageImageValue(nsStyleList* style_struct,
-                                  mozilla::css::ImageValue* aImageValue);
+                                  mozilla::css::URLValue* aImageValue);
 void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
 
 // cursor style.
 void Gecko_SetCursorArrayLength(nsStyleUI* ui, size_t len);
 void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
-                               mozilla::css::ImageValue* aImageValue);
+                               mozilla::css::URLValue* aImageValue);
 void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
 
 void Gecko_SetContentDataImageValue(nsStyleContentData* aList,
-                                    mozilla::css::ImageValue* aImageValue);
+                                    mozilla::css::URLValue* aImageValue);
 nsStyleContentData::CounterFunction* Gecko_SetCounterFunction(
     nsStyleContentData* content_data, mozilla::StyleContentType);
 
 // Dirtiness tracking.
 void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
 void Gecko_NoteDirtyElement(RawGeckoElementBorrowed element);
 void Gecko_NoteDirtySubtreeForInvalidation(RawGeckoElementBorrowed element);
@@ -542,20 +536,20 @@ void Gecko_nsStyleSVGPaint_CopyFrom(nsSt
 void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, mozilla::css::URLValue* uri);
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* paint);
 
 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);
+mozilla::css::URLValue* Gecko_URLValue_Create(ServoBundledURI uri, mozilla::CORSMode aCORSMode);
 size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);
-void Gecko_GetComputedURLSpec(const mozilla::css::URLValueData* url, nsCString* spec);
-void Gecko_GetComputedImageURLSpec(const mozilla::css::URLValueData* url, nsCString* spec);
+void Gecko_GetComputedURLSpec(const mozilla::css::URLValue* url, nsCString* spec);
+void Gecko_GetComputedImageURLSpec(const mozilla::css::URLValue* 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);
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -475,19 +475,17 @@ raw-lines = [
     "pub type ComputedStyleBorrowed<'a> = &'a ::properties::ComputedValues;",
     "pub type ComputedStyleBorrowedOrNull<'a> = Option<&'a ::properties::ComputedValues>;",
     "pub type ServoComputedDataBorrowed<'a> = &'a ServoComputedData;",
     "pub type RawServoAnimationValueTableBorrowed<'a> = &'a ();"
 ]
 whitelist-functions = ["Servo_.*", "Gecko_.*"]
 structs-types = [
     "mozilla::css::GridTemplateAreasValue",
-    "mozilla::css::ImageValue",
     "mozilla::css::URLValue",
-    "mozilla::css::URLValueData",
     "mozilla::dom::CallerType",
     "mozilla::dom::ShadowRoot",
     "mozilla::AnonymousCounterStyle",
     "mozilla::AtomArray",
     "mozilla::CORSMode",
     "mozilla::FontStretch",
     "mozilla::FontSlantStyle",
     "mozilla::FontWeight",
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -880,35 +880,27 @@ nsCSSValue::Array::SizeOfIncludingThis(m
 {
   size_t n = aMallocSizeOf(this);
   for (size_t i = 0; i < mCount; i++) {
     n += mArray[i].SizeOfExcludingThis(aMallocSizeOf);
   }
   return n;
 }
 
-css::URLValueData::URLValueData(ServoRawOffsetArc<RustString> aString,
-                                already_AddRefed<URLExtraData> aExtraData,
-                                CORSMode aCORSMode)
-  : mExtraData(std::move(aExtraData))
-  , mURIResolved(false)
-  , mString(aString)
-  , mCORSMode(aCORSMode)
+css::URLValue::~URLValue()
 {
-  MOZ_ASSERT(mExtraData);
-  MOZ_ASSERT(mExtraData->GetPrincipal());
-}
+  if (mLoadID != 0) {
+    ImageLoader::DeregisterCSSImageFromAllLoaders(this);
+  }
 
-css::URLValueData::~URLValueData()
-{
   Servo_ReleaseArcStringData(&mString);
 }
 
 bool
-css::URLValueData::Equals(const URLValueData& aOther) const
+css::URLValue::Equals(const URLValue& aOther) const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool eq;
   const URLExtraData* self = mExtraData;
   const URLExtraData* other = aOther.mExtraData;
   return GetString() == aOther.GetString() &&
           (GetURI() == aOther.GetURI() || // handles null == null
@@ -919,43 +911,43 @@ css::URLValueData::Equals(const URLValue
            (NS_SUCCEEDED(self->BaseURI()->Equals(other->BaseURI(), &eq)) &&
             eq)) &&
           (self->GetPrincipal() == other->GetPrincipal() ||
            self->GetPrincipal()->Equals(other->GetPrincipal())) &&
           IsLocalRef() == aOther.IsLocalRef();
 }
 
 bool
-css::URLValueData::DefinitelyEqualURIs(const URLValueData& aOther) const
+css::URLValue::DefinitelyEqualURIs(const URLValue& aOther) const
 {
   if (mExtraData->BaseURI() != aOther.mExtraData->BaseURI()) {
     return false;
   }
   return GetString() == aOther.GetString();
 }
 
 bool
-css::URLValueData::DefinitelyEqualURIsAndPrincipal(
-    const URLValueData& aOther) const
+css::URLValue::DefinitelyEqualURIsAndPrincipal(
+    const URLValue& aOther) const
 {
   return mExtraData->GetPrincipal() == aOther.mExtraData->GetPrincipal() &&
          DefinitelyEqualURIs(aOther);
 }
 
 nsDependentCSubstring
-css::URLValueData::GetString() const
+css::URLValue::GetString() const
 {
   const uint8_t* chars;
   uint32_t len;
   Servo_GetArcStringData(mString.mPtr, &chars, &len);
   return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
 }
 
 nsIURI*
-css::URLValueData::GetURI() const
+css::URLValue::GetURI() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mURIResolved) {
     MOZ_ASSERT(!mURI);
     nsCOMPtr<nsIURI> newURI;
     NS_NewURI(getter_AddRefs(newURI),
               GetString(),
@@ -963,43 +955,43 @@ css::URLValueData::GetURI() const
     mURI = newURI.forget();
     mURIResolved = true;
   }
 
   return mURI;
 }
 
 bool
-css::URLValueData::IsLocalRef() const
+css::URLValue::IsLocalRef() const
 {
   if (mIsLocalRef.isNothing()) {
     // IsLocalRefURL is O(N), use it only when IsLocalRef is called.
     mIsLocalRef.emplace(nsContentUtils::IsLocalRefURL(GetString()));
   }
   return mIsLocalRef.value();
 }
 
 bool
-css::URLValueData::HasRef() const
+css::URLValue::HasRef() const
 {
   if (IsLocalRef()) {
     return true;
   }
 
   if (nsIURI* uri = GetURI()) {
     nsAutoCString ref;
     nsresult rv = uri->GetRef(ref);
     return NS_SUCCEEDED(rv) && !ref.IsEmpty();
   }
 
   return false;
 }
 
 already_AddRefed<nsIURI>
-css::URLValueData::ResolveLocalRef(nsIURI* aURI) const
+css::URLValue::ResolveLocalRef(nsIURI* aURI) const
 {
   nsCOMPtr<nsIURI> result = GetURI();
 
   if (result && IsLocalRef()) {
     nsCString ref;
     mURI->GetRef(ref);
 
     nsresult rv = NS_MutateURI(aURI)
@@ -1011,94 +1003,81 @@ css::URLValueData::ResolveLocalRef(nsIUR
       result = aURI;
     }
   }
 
   return result.forget();
 }
 
 already_AddRefed<nsIURI>
-css::URLValueData::ResolveLocalRef(nsIContent* aContent) const
+css::URLValue::ResolveLocalRef(nsIContent* aContent) const
 {
   nsCOMPtr<nsIURI> url = aContent->GetBaseURI();
   return ResolveLocalRef(url);
 }
 
 void
-css::URLValueData::GetSourceString(nsString& aRef) const
+css::URLValue::GetSourceString(nsString& aRef) const
 {
   nsIURI* uri = GetURI();
   if (!uri) {
     aRef.Truncate();
     return;
   }
 
   nsCString cref;
   if (IsLocalRef()) {
     // XXXheycam It's possible we can just return mString in this case, since
-    // it should be the "#fragment" string the URLValueData was created with.
+    // it should be the "#fragment" string the URLValue was created with.
     uri->GetRef(cref);
     cref.Insert('#', 0);
   } else {
     // It's not entirely clear how to best handle failure here. Ensuring the
     // string is empty seems safest.
     nsresult rv = uri->GetSpec(cref);
     if (NS_FAILED(rv)) {
       cref.Truncate();
     }
   }
 
   aRef = NS_ConvertUTF8toUTF16(cref);
 }
 
 bool
-css::URLValueData::EqualsExceptRef(nsIURI* aURI) const
+css::URLValue::EqualsExceptRef(nsIURI* aURI) const
 {
   nsIURI* uri = GetURI();
   if (!uri) {
     return false;
   }
 
   bool ret = false;
   uri->EqualsExceptRef(aURI, &ret);
   return ret;
 }
 
 size_t
-css::URLValueData::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+css::URLValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // Measurement of the following members may be added later if DMD finds it
   // is worthwhile:
   // - mURI
   // - mString
   // - mExtraData
-  return 0;
-}
 
-size_t
-css::URLValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
-{
   // Only measure it if it's unshared, to avoid double-counting.
   size_t n = 0;
   if (mRefCnt <= 1) {
     n += aMallocSizeOf(this);
-    n += URLValueData::SizeOfExcludingThis(aMallocSizeOf);
   }
   return n;
 }
 
-css::ImageValue::ImageValue(ServoRawOffsetArc<RustString> aString,
-                            already_AddRefed<URLExtraData> aExtraData,
-                            CORSMode aCORSMode)
-  : URLValueData(aString, std::move(aExtraData), aCORSMode)
-{
-}
-
 imgRequestProxy*
-css::ImageValue::LoadImage(nsIDocument* aDocument)
+css::URLValue::LoadImage(nsIDocument* aDocument)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   static uint64_t sNextLoadID = 1;
 
   if (mLoadID == 0) {
     mLoadID = sNextLoadID++;
   }
@@ -1119,31 +1098,16 @@ css::ImageValue::LoadImage(nsIDocument* 
                          loadingDoc,
                          this,
                          mCORSMode);
 
   // Register the image in the document that's using it.
   return aDocument->StyleImageLoader()->RegisterCSSImage(this);
 }
 
-css::ImageValue::~ImageValue()
-{
-  if (mLoadID != 0) {
-    ImageLoader::DeregisterCSSImageFromAllLoaders(this);
-  }
-}
-
-size_t
-css::ImageValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
-{
-  size_t n = aMallocSizeOf(this);
-  n += css::URLValueData::SizeOfExcludingThis(aMallocSizeOf);
-  return n;
-}
-
 size_t
 mozilla::css::GridTemplateAreasValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // Only measure it if it's unshared, to avoid double-counting.
   size_t n = 0;
   if (mRefCnt <= 1) {
     n += aMallocSizeOf(this);
     n += mNamedAreas.ShallowSizeOfExcludingThis(aMallocSizeOf);
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -88,58 +88,61 @@ class CSSStyleSheet;
       dest->member_ = clm_clone;                                               \
       dest = clm_clone;                                                        \
     }                                                                          \
   }
 
 namespace mozilla {
 namespace css {
 
-struct URLValueData
+struct URLValue final
 {
-protected:
-  // Methods are not inline because using an nsIPrincipal means requiring
-  // caps, which leads to REQUIRES hell, since this header is included all
-  // over.
-
+public:
   // aString must not be null.
   // principal of aExtraData must not be null.
   // Construct with a base URI; this will create the actual URI lazily from
   // aString and aExtraData.
-  URLValueData(ServoRawOffsetArc<RustString> aString,
-               already_AddRefed<URLExtraData> aExtraData,
-               CORSMode aCORSMode);
+  URLValue(ServoRawOffsetArc<RustString> aString,
+           already_AddRefed<URLExtraData> aExtraData,
+           CORSMode aCORSMode)
+    : mExtraData(std::move(aExtraData))
+    , mURIResolved(false)
+    , mString(aString)
+    , mCORSMode(aCORSMode)
+  {
+    MOZ_ASSERT(mExtraData);
+    MOZ_ASSERT(mExtraData->GetPrincipal());
+  }
 
-public:
-  // Returns true iff all fields of the two URLValueData objects are equal.
+  // 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 URLValueData objects.
-  bool Equals(const URLValueData& aOther) const;
+  // nsIURI and nsIPrincipal objects stored on the URLValue objects.
+  bool Equals(const URLValue& aOther) const;
 
   // Returns true iff we know for sure, by comparing the mBaseURI pointer,
   // the specified url() value mString, and the mIsLocalRef, that these
-  // two URLValueData objects represent the same computed url() value.
+  // two URLValue objects represent the same computed url() value.
   //
   // Doesn't look at mReferrer or mOriginPrincipal.
   //
   // Safe to call from any thread.
-  bool DefinitelyEqualURIs(const URLValueData& aOther) const;
+  bool DefinitelyEqualURIs(const URLValue& aOther) const;
 
   // Smae as DefinitelyEqualURIs but additionally compares the nsIPrincipal
-  // pointers of the two URLValueData objects.
-  bool DefinitelyEqualURIsAndPrincipal(const URLValueData& aOther) const;
+  // pointers of the two URLValue objects.
+  bool DefinitelyEqualURIsAndPrincipal(const URLValue& aOther) const;
 
   nsIURI* GetURI() const;
 
   bool IsLocalRef() const;
 
   bool HasRef() const;
 
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValueData)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValue)
 
   // When matching a url with mIsLocalRef set, resolve it against aURI;
   // Otherwise, ignore aURL and return mURL directly.
   already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aURI) const;
   already_AddRefed<nsIURI> ResolveLocalRef(nsIContent* aContent) const;
 
   // Serializes mURI as a computed URI value, taking into account mIsLocalRef
   // and serializing just the fragment if true.
@@ -149,16 +152,20 @@ public:
 
   bool IsStringEmpty() const
   {
     return GetString().IsEmpty();
   }
 
   nsDependentCSubstring GetString() const;
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
+  imgRequestProxy* LoadImage(nsIDocument* aDocument);
+
   uint64_t LoadID() const { return mLoadID; }
 
 private:
   // mURI stores the lazily resolved URI.  This may be null if the URI is
   // invalid, even once resolved.
   mutable nsCOMPtr<nsIURI> mURI;
 
 public:
@@ -167,76 +174,34 @@ public:
 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;
 
-protected:
   const CORSMode mCORSMode;
 
-  // A unique, non-reused ID value for this ImageValue over the life of the
+  // 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
   // delete ImageValues OMT but cannot update the ImageLoader tables until
   // we're back on the main thread.  So to avoid dangling pointers that might
   // get re-used by the time we want to update the ImageLoader tables, we use
   // these IDs.
   uint64_t mLoadID = 0;
 
-  virtual ~URLValueData();
-
-  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+  ~URLValue();
 
 private:
-  URLValueData(const URLValueData& aOther) = delete;
-  URLValueData& operator=(const URLValueData& aOther) = delete;
-
-  friend struct ImageValue;
-};
-
-struct URLValue final : public URLValueData
-{
-  URLValue(ServoRawOffsetArc<RustString> aString,
-           already_AddRefed<URLExtraData> aExtraData,
-           CORSMode aCORSMode)
-    : URLValueData(aString, std::move(aExtraData), aCORSMode)
-  { }
-
-  URLValue(const URLValue&) = delete;
-  URLValue& operator=(const URLValue&) = delete;
-
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-};
-
-struct ImageValue final : public URLValueData
-{
-  // Not making the constructor and destructor inline because that would
-  // force us to include imgIRequest.h, which leads to REQUIRES hell, since
-  // this header is included all over.
-
-  // This constructor is safe to call from any thread, but Initialize
-  // must be called later for the object to be useful.
-  ImageValue(ServoRawOffsetArc<RustString> aURIString,
-             already_AddRefed<URLExtraData> aExtraData,
-             CORSMode aCORSMode);
-
-  ImageValue(const ImageValue&) = delete;
-  ImageValue& operator=(const ImageValue&) = delete;
-
-  imgRequestProxy* LoadImage(nsIDocument* aDocument);
-
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
-
-protected:
-  ~ImageValue();
+  URLValue(const URLValue& aOther) = delete;
+  URLValue& operator=(const URLValue& aOther) = delete;
 };
 
 struct GridNamedArea {
   nsString mName;
   uint32_t mColumnStart;
   uint32_t mColumnEnd;
   uint32_t mRowStart;
   uint32_t mRowEnd;
@@ -412,18 +377,16 @@ struct nsCSSValueSharedList;
 struct nsCSSValuePairList;
 struct nsCSSValuePairList_heap;
 
 class nsCSSValue {
 public:
   struct Array;
   friend struct Array;
 
-  friend struct mozilla::css::ImageValue;
-
   // for valueless units only (null, auto, inherit, none, all, normal)
   explicit nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null)
     : mUnit(aUnit)
   {
     MOZ_ASSERT(aUnit <= eCSSUnit_DummyInherit, "not a valueless unit");
   }
 
   nsCSSValue(int32_t aValue, nsCSSUnit aUnit);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -657,17 +657,17 @@ AddImageURL(nsIURI& aURI, nsTArray<nsStr
     return;
   }
 
   aURLs.AppendElement(NS_ConvertUTF8toUTF16(spec));
 }
 
 
 static void
-AddImageURL(const css::URLValueData& aURL, nsTArray<nsString>& aURLs)
+AddImageURL(const css::URLValue& aURL, nsTArray<nsString>& aURLs)
 {
   if (aURL.IsLocalRef()) {
     return;
   }
 
   if (nsIURI* uri = aURL.GetURI()) {
     AddImageURL(*uri, aURLs);
   }
@@ -1691,25 +1691,25 @@ nsComputedDOMStyle::SetValueToPosition(
 
   RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
   SetValueToPositionCoord(aPosition.mYPosition, valY);
   aValueList->AppendCSSValue(valY.forget());
 }
 
 
 void
-nsComputedDOMStyle::SetValueToURLValue(const css::URLValueData* aURL,
+nsComputedDOMStyle::SetValueToURLValue(const css::URLValue* aURL,
                                        nsROCSSPrimitiveValue* aValue)
 {
   if (!aURL) {
     aValue->SetIdent(eCSSKeyword_none);
     return;
   }
 
-  // If we have a usable nsIURI in the URLValueData, and the url() wasn't
+  // If we have a usable nsIURI in the URLValue, and the url() wasn't
   // a fragment-only URL, serialize the nsIURI.
   if (!aURL->IsLocalRef()) {
     if (nsIURI* uri = aURL->GetURI()) {
       aValue->SetURI(uri);
       return;
     }
   }
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -465,17 +465,17 @@ private:
                                 const mozilla::StyleComplexColor& aColor);
   void SetValueForWidgetColor(nsROCSSPrimitiveValue* aValue,
                               const mozilla::StyleComplexColor& aColor,
                               mozilla::StyleAppearance aWidgetType);
   void SetValueToPositionCoord(const mozilla::Position::Coord& aCoord,
                                nsROCSSPrimitiveValue* aValue);
   void SetValueToPosition(const mozilla::Position& aPosition,
                           nsDOMCSSValueList* aValueList);
-  void SetValueToURLValue(const mozilla::css::URLValueData* aURL,
+  void SetValueToURLValue(const mozilla::css::URLValue* aURL,
                           nsROCSSPrimitiveValue* aValue);
 
   /**
    * A method to get a percentage base for a percentage value.  Returns true
    * if a percentage base value was determined, false otherwise.
    */
   typedef bool (nsComputedDOMStyle::*PercentageBaseGetter)(nscoord&);
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -54,26 +54,26 @@ using namespace mozilla::dom;
 static constexpr size_t kStyleStructSizeLimit = 504;
 #define STYLE_STRUCT(name_) \
   static_assert(sizeof(nsStyle##name_) <= kStyleStructSizeLimit, \
                 "nsStyle" #name_ " became larger than the size limit");
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
 static bool
-DefinitelyEqualURIs(css::URLValueData* aURI1,
-                    css::URLValueData* aURI2)
+DefinitelyEqualURIs(css::URLValue* aURI1,
+                    css::URLValue* aURI2)
 {
   return aURI1 == aURI2 ||
          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIs(*aURI2));
 }
 
 static bool
-DefinitelyEqualURIsAndPrincipal(css::URLValueData* aURI1,
-                                css::URLValueData* aURI2)
+DefinitelyEqualURIsAndPrincipal(css::URLValue* aURI1,
+                                css::URLValue* aURI2)
 {
   return aURI1 == aURI2 ||
          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIsAndPrincipal(*aURI2));
 }
 
 static bool
 DefinitelyEqualImages(nsStyleImageRequest* aRequest1,
                       nsStyleImageRequest* aRequest2)
@@ -1246,17 +1246,17 @@ nsStyleSVGReset::nsStyleSVGReset(const n
 void
 nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext, const nsStyleSVGReset* aOldStyle)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mMask) {
     nsStyleImage& image = mMask.mLayers[i].mImage;
     if (image.GetType() == eStyleImageType_Image) {
-      css::URLValueData* url = image.GetURLValue();
+      css::URLValue* url = image.GetURLValue();
       // If the url is a local ref, it must be a <mask-resource>, so we don't
       // need to resolve the style image.
       if (url->IsLocalRef()) {
         continue;
       }
 #if 0
       // XXX The old style system also checks whether this is a reference to
       // the current document with reference, but it doesn't seem to be a
@@ -2078,17 +2078,17 @@ private:
   Mode mModeFlags;
   // Since we always dispatch this runnable to the main thread, these will be
   // released on the main thread when the runnable itself is released.
   RefPtr<imgRequestProxy> mRequestProxy;
   RefPtr<ImageTracker> mImageTracker;
 };
 
 nsStyleImageRequest::nsStyleImageRequest(Mode aModeFlags,
-                                         css::ImageValue* aImageValue)
+                                         css::URLValue* aImageValue)
   : mImageValue(aImageValue)
   , mModeFlags(aModeFlags)
   , mResolved(false)
 {
 }
 
 nsStyleImageRequest::~nsStyleImageRequest()
 {
@@ -2660,17 +2660,17 @@ nsStyleImage::GetImageURI() const
   if (mType != eStyleImageType_Image) {
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri = mImage->GetImageURI();
   return uri.forget();
 }
 
-css::URLValueData*
+css::URLValue*
 nsStyleImage::GetURLValue() const
 {
   if (mType == eStyleImageType_Image) {
     return mImage->GetImageValue();
   } else if (mType == eStyleImageType_URL) {
     return mURLValue;
   }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -214,25 +214,23 @@ private:
  * This can be called from any thread.  The nsStyleImageRequest is not
  * considered "resolved" at this point, and the Resolve() method must be called
  * later to initiate the image load and make calls to get() valid.
  *
  * Calls to TrackImage(), UntrackImage(), LockImage(), UnlockImage() and
  * RequestDiscard() are made to the imgRequestProxy and ImageTracker as
  * appropriate, according to the mode flags passed in to the constructor.
  *
- * The constructor receives a css::ImageValue to represent the url()
+ * The constructor receives a css::URLValue to represent the url()
  * information, which is held on to for the comparisons done in
  * DefinitelyEquals().
  */
 class nsStyleImageRequest
 {
 public:
-  typedef mozilla::css::URLValueData URLValueData;
-
   // Flags describing whether the imgRequestProxy must be tracked in the
   // ImageTracker, whether LockImage/UnlockImage calls will be made
   // when obtaining and releasing the imgRequestProxy, and whether
   // RequestDiscard will be called on release.
   enum class Mode : uint8_t {
     // The imgRequestProxy will be added to the ImageTracker when resolved
     // Without this flag, the nsStyleImageRequest itself will call LockImage/
     // UnlockImage on the imgRequestProxy, rather than leaving locking to the
@@ -246,47 +244,47 @@ public:
     // the nsStyleImageRequest is going away.
     //
     // This is currently used only for cursor images.
     Discard = 0x2,
   };
 
   // Can be called from any thread, but Resolve() must be called later
   // on the main thread before get() can be used.
-  nsStyleImageRequest(Mode aModeFlags, mozilla::css::ImageValue* aImageValue);
+  nsStyleImageRequest(Mode aModeFlags, mozilla::css::URLValue* aImageValue);
 
   bool Resolve(nsPresContext*, const nsStyleImageRequest* aOldImageRequest);
   bool IsResolved() const { return mResolved; }
 
   imgRequestProxy* get() {
     MOZ_ASSERT(IsResolved(), "Resolve() must be called first");
     MOZ_ASSERT(NS_IsMainThread());
     return mRequestProxy.get();
   }
   const imgRequestProxy* get() const {
     return const_cast<nsStyleImageRequest*>(this)->get();
   }
 
-  // Returns whether the ImageValue objects in the two nsStyleImageRequests
-  // return true from URLValueData::DefinitelyEqualURIs.
+  // Returns whether the URLValue objects in the two nsStyleImageRequests
+  // return true from URLValue::DefinitelyEqualURIs.
   bool DefinitelyEquals(const nsStyleImageRequest& aOther) const;
 
-  mozilla::css::ImageValue* GetImageValue() const { return mImageValue; }
+  mozilla::css::URLValue* GetImageValue() const { return mImageValue; }
 
   already_AddRefed<nsIURI> GetImageURI() const;
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsStyleImageRequest);
 
 private:
   ~nsStyleImageRequest();
   nsStyleImageRequest& operator=(const nsStyleImageRequest& aOther) = delete;
 
   void MaybeTrackAndLock();
 
   RefPtr<imgRequestProxy> mRequestProxy;
-  RefPtr<mozilla::css::ImageValue> mImageValue;
+  RefPtr<mozilla::css::URLValue> mImageValue;
   RefPtr<mozilla::dom::ImageTracker> mImageTracker;
 
   // Cache DocGroup for dispatching events in the destructor.
   RefPtr<mozilla::dom::DocGroup> mDocGroup;
 
   Mode mModeFlags;
   bool mResolved;
 };
@@ -330,18 +328,17 @@ private:
  * (3) An element within a document, or an <img>, <video>, or <canvas> element
  *     not in a document.
  * (*) Optionally a crop rect can be set to paint a partial (rectangular)
  * region of an image. (Currently, this feature is only supported with an
  * image of type (1)).
  */
 struct nsStyleImage
 {
-  typedef mozilla::css::URLValue     URLValue;
-  typedef mozilla::css::URLValueData URLValueData;
+  typedef mozilla::css::URLValue URLValue;
 
   nsStyleImage();
   ~nsStyleImage();
   nsStyleImage(const nsStyleImage& aOther);
   nsStyleImage& operator=(const nsStyleImage& aOther);
 
   void SetNull();
   void SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage);
@@ -385,17 +382,17 @@ struct nsStyleImage
   const mozilla::UniquePtr<nsStyleSides>& GetCropRect() const {
     NS_ASSERTION(mType == eStyleImageType_Image,
                  "Only image data can have a crop rect");
     return mCropRect;
   }
 
   already_AddRefed<nsIURI> GetImageURI() const;
 
-  URLValueData* GetURLValue() const;
+  URLValue* GetURLValue() const;
 
   /**
    * Compute the actual crop rect in pixels, using the source image bounds.
    * The computation involves converting percentage unit to pixel unit and
    * clamping each side value to fit in the source image bounds.
    * @param aActualCropRect the computed actual crop rect.
    * @param aIsEntireImage true iff |aActualCropRect| is identical to the
    * source image bounds.
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -22,17 +22,17 @@
 #include "SVGTextPathElement.h"
 #include "SVGUseElement.h"
 #include "ImageLoader.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 using namespace mozilla::dom;
 
 static already_AddRefed<URLAndReferrerInfo>
-ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
+ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValue* aURL)
 {
   MOZ_ASSERT(aFrame);
 
   if (!aURL) {
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> uri = aURL->GetURI();
@@ -795,17 +795,17 @@ private:
 NS_IMPL_ISUPPORTS(SVGMaskObserverList, nsISupports)
 
 SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame)
   : mFrame(aFrame)
 {
   const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
 
   for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
-    css::URLValueData* data = svgReset->mMask.mLayers[i].mImage.GetURLValue();
+    css::URLValue* data = svgReset->mMask.mLayers[i].mImage.GetURLValue();
     RefPtr<URLAndReferrerInfo> maskUri = ResolveURLUsingLocalRef(aFrame, data);
 
     bool hasRef = false;
     if (maskUri) {
       maskUri->GetURI()->GetHasRef(&hasRef);
     }
 
     // Accrording to maskUri, nsSVGPaintingProperty's ctor may trigger an
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -220,23 +220,23 @@ fn line_direction(horizontal: LengthOrPe
 }
 
 impl nsStyleImage {
     /// Set a given Servo `Image` value into this `nsStyleImage`.
     pub fn set(&mut self, image: Image) {
         match image {
             GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
             GenericImage::Url(ref url) => unsafe {
-                bindings::Gecko_SetLayerImageImageValue(self, url.0.image_value.get());
+                bindings::Gecko_SetLayerImageImageValue(self, (url.0).0.url_value.get());
             },
             GenericImage::Rect(ref image_rect) => {
                 unsafe {
                     bindings::Gecko_SetLayerImageImageValue(
                         self,
-                        image_rect.url.0.image_value.get(),
+                        (image_rect.url.0).0.url_value.get(),
                     );
                     bindings::Gecko_InitializeImageCropRect(self);
 
                     // Set CropRect
                     let ref mut rect = *self.mCropRect.mPtr;
                     image_rect
                         .top
                         .to_gecko_style_coord(&mut rect.data_at_mut(0));
--- a/servo/components/style/gecko/url.rs
+++ b/servo/components/style/gecko/url.rs
@@ -2,20 +2,19 @@
  * 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::mozilla::css::URLValueData;
 use gecko_bindings::structs::root::{RustString, nsStyleImageRequest};
 use gecko_bindings::structs::root::mozilla::CORSMode;
-use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue};
+use gecko_bindings::structs::root::mozilla::css::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 style_traits::{CssWriter, ParseError, ToCss};
@@ -33,34 +32,33 @@ pub struct CssUrl {
     serialization: Arc<String>,
 
     /// The URL extra data.
     #[css(skip)]
     pub extra_data: UrlExtraData,
 }
 
 impl CssUrl {
-    /// Try to parse a URL from a string value that is a valid CSS token for a
-    /// URL.
+    /// 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),
             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 URLValueData to SpecifiedUrl.
-    unsafe fn from_url_value_data(url: &URLValueData) -> Self {
+    /// 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.
@@ -112,234 +110,213 @@ impl MallocSizeOf for CssUrl {
 
         // We ignore `extra_data`, because RefPtr is tricky, and there aren't
         // many of them in practise (sharing is common).
 
         0
     }
 }
 
-/// A specified url() value for general usage.
+/// A specified non-image `url()` value.
 #[derive(Clone, Debug, SpecifiedValueInfo, ToCss)]
 pub struct SpecifiedUrl {
     /// The specified url value.
     pub url: CssUrl,
     /// Gecko's URLValue so that we can reuse it while rematching a
     /// property with this specified value.
     #[css(skip)]
     pub url_value: RefPtr<URLValue>,
 }
 
 impl SpecifiedUrl {
-    fn from_css_url(url: CssUrl) -> Self {
+    /// 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_NewURLValue(url.for_ffi());
-            // We do not expect Gecko_NewURLValue returns null.
+            let ptr = bindings::Gecko_URLValue_Create(url.for_ffi(), 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 {
+        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_NONE;
+        Self::from_css_url_with_cors(url, CORSMode_CORS_NONE)
+    }
+
+    fn from_css_url_with_cors_anonymous(url: CssUrl) -> Self {
+        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
+        Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
+    }
+}
+
+impl Parse for SpecifiedUrl {
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        CssUrl::parse(context, input).map(Self::from_css_url)
+    }
 }
 
 impl PartialEq for SpecifiedUrl {
     fn eq(&self, other: &Self) -> bool {
         self.url.eq(&other.url)
     }
 }
 
 impl Eq for SpecifiedUrl {}
 
-impl Parse for SpecifiedUrl {
-    fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        CssUrl::parse(context, input).map(Self::from_css_url)
-    }
-}
-
 impl MallocSizeOf for SpecifiedUrl {
     fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
         let mut n = self.url.size_of(ops);
         // Although this is a RefPtr, this is the primary reference because
         // SpecifiedUrl is responsible for creating the url_value. So we
         // measure unconditionally here.
         n += unsafe { bindings::Gecko_URLValue_SizeOfIncludingThis(self.url_value.get()) };
         n
     }
 }
 
-/// A specified url() value for image.
-///
-/// This exists so that we can construct `ImageValue` and reuse it.
-#[derive(Clone, Debug, SpecifiedValueInfo, ToCss)]
-pub struct SpecifiedImageUrl {
-    /// The specified url value.
-    pub url: CssUrl,
-    /// Gecko's ImageValue so that we can reuse it while rematching a
-    /// property with this specified value.
-    #[css(skip)]
-    pub image_value: RefPtr<ImageValue>,
-}
-
-impl SpecifiedImageUrl {
-    /// Parse a URL from a string value. See SpecifiedUrl::parse_from_string.
-    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 image_value = unsafe {
-            let ptr = bindings::Gecko_ImageValue_Create(url.for_ffi(), cors);
-            // We do not expect Gecko_ImageValue_Create returns null.
-            debug_assert!(!ptr.is_null());
-            RefPtr::from_addrefed(ptr)
-        };
-        Self { url, image_value }
-    }
-
-    fn from_css_url(url: CssUrl) -> Self {
-        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_NONE;
-        Self::from_css_url_with_cors(url, CORSMode_CORS_NONE)
-    }
-
-    fn from_css_url_with_cors_anonymous(url: CssUrl) -> Self {
-        use gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
-        Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
-    }
-
-    /// Provides an alternate method for parsing that associates the URL
-    /// with anonymous CORS headers.
-    pub fn parse_with_cors_anonymous<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        CssUrl::parse(context, input).map(Self::from_css_url_with_cors_anonymous)
-    }
-}
-
-impl Parse for SpecifiedImageUrl {
-    fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        CssUrl::parse(context, input).map(Self::from_css_url)
-    }
-}
-
-impl PartialEq for SpecifiedImageUrl {
-    fn eq(&self, other: &Self) -> bool {
-        self.url.eq(&other.url)
-    }
-}
-
-impl Eq for SpecifiedImageUrl {}
-
-impl MallocSizeOf for SpecifiedImageUrl {
-    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
-        let mut n = self.url.size_of(ops);
-        // 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 { bindings::Gecko_ImageValue_SizeOfIncludingThis(self.image_value.get()) };
-        n
-    }
-}
-
 impl ToComputedValue for SpecifiedUrl {
     type ComputedValue = ComputedUrl;
 
     #[inline]
     fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
         ComputedUrl(self.clone())
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         computed.0.clone()
     }
 }
 
+/// A specified image `url()` value.
+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
+pub struct SpecifiedImageUrl(pub SpecifiedUrl);
+
+impl SpecifiedImageUrl {
+    /// 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 {
+        SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context))
+    }
+
+    /// Provides an alternate method for parsing that associates the URL
+    /// with anonymous CORS headers.
+    pub fn parse_with_cors_anonymous<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        CssUrl::parse(context, input)
+            .map(SpecifiedUrl::from_css_url_with_cors_anonymous)
+            .map(SpecifiedImageUrl)
+    }
+}
+
+impl Parse for SpecifiedImageUrl {
+    fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        SpecifiedUrl::parse(context, input).map(SpecifiedImageUrl)
+    }
+}
+
 impl ToComputedValue for SpecifiedImageUrl {
     type ComputedValue = ComputedImageUrl;
 
     #[inline]
     fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
         ComputedImageUrl(self.clone())
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         computed.0.clone()
     }
 }
 
 fn serialize_computed_url<W>(
-    url_value_data: &URLValueData,
+    url_value: &URLValue,
     dest: &mut CssWriter<W>,
-    get_url: unsafe extern "C" fn(*const URLValueData, *mut nsCString),
+    get_url: unsafe extern "C" fn(*const URLValue, *mut nsCString) -> (),
 ) -> fmt::Result
 where
     W: Write,
 {
     dest.write_str("url(")?;
     unsafe {
         let mut string = nsCString::new();
-        get_url(url_value_data, &mut string);
+        get_url(url_value, &mut string);
         string.as_str_unchecked().to_css(dest)?;
     }
     dest.write_char(')')
 }
 
-/// The computed value of a CSS `url()`.
+/// The computed value of a CSS non-image `url()`.
 ///
 /// The only difference between specified and computed URLs is the
 /// serialization.
 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
 pub struct ComputedUrl(pub SpecifiedUrl);
 
 impl ToCss for ComputedUrl {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
         serialize_computed_url(
-            &self.0.url_value._base,
+            &self.0.url_value,
             dest,
             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_data(&url_value._base);
+        let url = CssUrl::from_url_value(&*url_value);
         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()
+    }
 }
 
-/// The computed value of a CSS `url()` for image.
+/// The computed value of a CSS image `url()`.
 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
 pub struct ComputedImageUrl(pub SpecifiedImageUrl);
 
 impl ToCss for ComputedImageUrl {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: Write,
     {
         serialize_computed_url(
-            &self.0.image_value._base,
+            &(self.0).0.url_value,
             dest,
             bindings::Gecko_GetComputedImageURLSpec,
         )
     }
 }
 
 impl ComputedImageUrl {
     /// Convert from nsStyleImageReques to ComputedImageUrl.
     pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
-        let image_value = image_request.mImageValue.to_safe();
-        let url = CssUrl::from_url_value_data(&image_value._base);
-        ComputedImageUrl(SpecifiedImageUrl { url, image_value })
+        let url_value = image_request.mImageValue.to_safe();
+        let url = CssUrl::from_url_value(&*url_value);
+        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/components/style/gecko_bindings/sugar/refptr.rs
+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs
@@ -293,21 +293,16 @@ impl_threadsafe_refcount!(
     bindings::Gecko_ReleaseCSSURLValueArbitraryThread
 );
 impl_threadsafe_refcount!(
     structs::mozilla::css::GridTemplateAreasValue,
     bindings::Gecko_AddRefGridTemplateAreasValueArbitraryThread,
     bindings::Gecko_ReleaseGridTemplateAreasValueArbitraryThread
 );
 impl_threadsafe_refcount!(
-    structs::ImageValue,
-    bindings::Gecko_AddRefImageValueArbitraryThread,
-    bindings::Gecko_ReleaseImageValueArbitraryThread
-);
-impl_threadsafe_refcount!(
     structs::SharedFontList,
     bindings::Gecko_AddRefSharedFontListArbitraryThread,
     bindings::Gecko_ReleaseSharedFontListArbitraryThread
 );
 impl_threadsafe_refcount!(
     structs::SheetLoadDataHolder,
     bindings::Gecko_AddRefSheetLoadDataHolderArbitraryThread,
     bindings::Gecko_ReleaseSheetLoadDataHolderArbitraryThread
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -684,17 +684,20 @@ def set_gecko_property(ffi_name, expr):
             SVGPaintKind::ContextFill => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill;
             }
             SVGPaintKind::ContextStroke => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke;
             }
             SVGPaintKind::PaintServer(url) => {
                 unsafe {
-                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.0.url_value.get());
+                    bindings::Gecko_nsStyleSVGPaint_SetURLValue(
+                        paint,
+                        url.url_value_ptr(),
+                    )
                 }
             }
             SVGPaintKind::Color(color) => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
                 unsafe {
                     *paint.mPaint.mColor.as_mut() = color.into();
                 }
             }
@@ -4148,17 +4151,20 @@ fn static_assert() {
         match image {
             UrlOrNone::None => {
                 unsafe {
                     Gecko_SetListStyleImageNone(&mut self.gecko);
                 }
             }
             UrlOrNone::Url(ref url) => {
                 unsafe {
-                    Gecko_SetListStyleImageImageValue(&mut self.gecko, url.0.image_value.get());
+                    Gecko_SetListStyleImageImageValue(
+                        &mut self.gecko,
+                        url.url_value_ptr(),
+                    );
                 }
             }
         }
     }
 
     pub fn copy_list_style_image_from(&mut self, other: &Self) {
         unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); }
     }
@@ -5353,17 +5359,17 @@ clip-path
 
         unsafe {
             Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
         }
         for i in 0..v.images.len() {
             unsafe {
                 Gecko_SetCursorImageValue(
                     &mut self.gecko.mCursorImages[i],
-                    v.images[i].url.0.image_value.get(),
+                    v.images[i].url.url_value_ptr(),
                 );
             }
 
             match v.images[i].hotspot {
                 Some((x, y)) => {
                     self.gecko.mCursorImages[i].mHaveHotspot = true;
                     self.gecko.mCursorImages[i].mHotspotX = x;
                     self.gecko.mCursorImages[i].mHotspotY = y;
@@ -5654,17 +5660,17 @@ clip-path
                                 style.clone(),
                                 device,
                             );
                         }
                         ContentItem::Url(ref url) => {
                             unsafe {
                                 bindings::Gecko_SetContentDataImageValue(
                                     &mut self.gecko.mContents[i],
-                                    url.0.image_value.get(),
+                                    url.url_value_ptr(),
                                 )
                             }
                         }
                     }
                 }
             }
         }
     }