Bug 1351957 - Create URLExtraData for holding base uri, referrer, and principal. r=heycam
authorXidorn Quan <me@upsuper.org>
Thu, 30 Mar 2017 18:54:48 +1100
changeset 350890 21926c2cc38dd23afc0d6f02e7313af4170fb77b
parent 350889 a8e661d8591cdfa2afa3b5753c18ab2317a8f9fa
child 350891 b2d106b73e6a4a1a8557981e597fea358b09d650
push id31593
push usercbook@mozilla.com
push dateMon, 03 Apr 2017 10:11:46 +0000
treeherdermozilla-central@b2d106b73e6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1351957
milestone55.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 1351957 - Create URLExtraData for holding base uri, referrer, and principal. r=heycam MozReview-Commit-ID: 1wqTb3kvvWh
dom/animation/KeyframeUtils.cpp
dom/animation/TimingParams.cpp
dom/base/Element.cpp
dom/base/nsAttrValue.cpp
dom/svg/nsSVGElement.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/style/FontFaceSet.cpp
layout/style/ServoBindingList.h
layout/style/ServoBindingTypes.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoDeclarationBlock.cpp
layout/style/ServoDeclarationBlock.h
layout/style/ServoStyleSheet.cpp
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -1017,23 +1017,24 @@ MakePropertyValuePair(nsCSSPropertyID aP
 
   if (aDocument->GetStyleBackendType() == StyleBackendType::Servo) {
     nsCString name = nsCSSProps::GetStringValue(aProperty);
 
     NS_ConvertUTF16toUTF8 value(aStringValue);
 
     nsCString baseString;
     // FIXME this is using the wrong base uri (bug 1343919)
-    GeckoParserExtraData data(aDocument->GetDocumentURI(),
-                              aDocument->GetDocumentURI(),
-                              aDocument->NodePrincipal());
+    RefPtr<css::URLExtraData> data =
+      new css::URLExtraData(aDocument->GetDocumentURI(),
+                            aDocument->GetDocumentURI(),
+                            aDocument->NodePrincipal());
     aDocument->GetDocumentURI()->GetSpec(baseString);
 
     RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
-      Servo_ParseProperty(&name, &value, &baseString, &data).Consume();
+      Servo_ParseProperty(&name, &value, &baseString, data).Consume();
 
     if (servoDeclarationBlock) {
       result.mServoDeclarationBlock = servoDeclarationBlock.forget();
     }
     return result;
   }
 
   nsCSSValue value;
--- a/dom/animation/TimingParams.cpp
+++ b/dom/animation/TimingParams.cpp
@@ -113,21 +113,22 @@ TimingParams::ParseEasing(const nsAStrin
                           ErrorResult& aRv)
 {
   MOZ_ASSERT(aDocument);
 
   if (aDocument->IsStyledByServo()) {
     nsTimingFunction timingFunction;
     nsCString baseString;
     // FIXME this is using the wrong base uri (bug 1343919)
-    GeckoParserExtraData data(aDocument->GetDocumentURI(),
-                              aDocument->GetDocumentURI(),
-                              aDocument->NodePrincipal());
+    RefPtr<css::URLExtraData> data =
+      new css::URLExtraData(aDocument->GetDocumentURI(),
+                            aDocument->GetDocumentURI(),
+                            aDocument->NodePrincipal());
     aDocument->GetDocumentURI()->GetSpec(baseString);
-    if (!Servo_ParseEasing(&aEasing, &baseString, &data, &timingFunction)) {
+    if (!Servo_ParseEasing(&aEasing, &baseString, data, &timingFunction)) {
       aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
       return Nothing();
     }
 
     if (timingFunction.mType == nsTimingFunction::Type::Linear) {
       return Nothing();
     }
 
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -545,17 +545,17 @@ Element::WrapObject(JSContext *aCx, JS::
     bool ok = GetBindingURL(doc, getter_AddRefs(bindingURL));
     if (!ok) {
       dom::Throw(aCx, NS_ERROR_FAILURE);
       return nullptr;
     }
 
     if (bindingURL) {
       nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
-      nsCOMPtr<nsIPrincipal> principal = bindingURL->mOriginPrincipal.get();
+      nsCOMPtr<nsIPrincipal> principal = bindingURL->mExtraData->GetPrincipal();
 
       // We have a binding that must be installed.
       bool dummy;
 
       nsXBLService* xblService = nsXBLService::GetInstance();
       if (!xblService) {
         dom::Throw(aCx, NS_ERROR_NOT_AVAILABLE);
         return nullptr;
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -1682,18 +1682,18 @@ nsAttrValue::LoadImage(nsIDocument* aDoc
     NS_ASSERTION(!val.IsEmpty(),
                  "How did we end up with an empty string for eURL");
   }
 #endif
 
   MiscContainer* cont = GetMiscContainer();
   mozilla::css::URLValue* url = cont->mValue.mURL;
   mozilla::css::ImageValue* image =
-    new css::ImageValue(url->GetURI(), url->mString, url->mBaseURI,
-                        url->mReferrer, url->mOriginPrincipal, aDocument);
+    new css::ImageValue(url->GetURI(), url->mString,
+                        do_AddRef(url->mExtraData), aDocument);
 
   NS_ADDREF(image);
   cont->mValue.mImage = image;
   NS_RELEASE(url);
   cont->mType = eImage;
 }
 
 bool
@@ -1720,17 +1720,18 @@ nsAttrValue::ParseStyleAttribute(const n
       NS_ADDREF(cont);
       SetPtrValueAndType(cont, eOtherBase);
       return true;
     }
   }
 
   RefPtr<DeclarationBlock> decl;
   if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) {
-    GeckoParserExtraData data(baseURI, docURI, aElement->NodePrincipal());
+    RefPtr<css::URLExtraData> data =
+      new css::URLExtraData(baseURI, docURI, aElement->NodePrincipal());
     decl = ServoDeclarationBlock::FromCssText(aString, data);
   } else {
     css::Loader* cssLoader = ownerDoc->CSSLoader();
     nsCSSParser cssParser(cssLoader);
     decl = cssParser.ParseStyleAttribute(aString, docURI, baseURI,
                                          aElement->NodePrincipal());
   }
   if (!decl) {
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -1230,21 +1230,22 @@ MappedAttrParser::ParseMappedAttrValue(n
     bool changed = false; // outparam for ParseProperty.
     if (mBackend == StyleBackendType::Gecko) {
       mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
                             mElement->NodePrincipal(), mDecl->AsGecko(), &changed, false, true);
     } else {
       NS_ConvertUTF16toUTF8 value(aMappedAttrValue);
       // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
       nsCString baseString;
-      GeckoParserExtraData data(mBaseURI, mDocURI, mElement->NodePrincipal());
+      RefPtr<css::URLExtraData> data =
+        new css::URLExtraData(mBaseURI, mDocURI, mElement->NodePrincipal());
       mBaseURI->GetSpec(baseString);
       // FIXME (bug 1342559): Set SVG parsing mode for lengths
       changed = Servo_DeclarationBlock_SetPropertyById(mDecl->AsServo()->Raw(), propertyID,
-                                                       &value, false, &baseString, &data);
+                                                       &value, false, &baseString, data);
     }
 
     if (changed) {
       // The normal reporting of use counters by the nsCSSParser won't happen
       // since it doesn't have a sheet.
       if (nsCSSProps::IsShorthand(propertyID)) {
         CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, propertyID,
                                              CSSEnabledState::eForAllContent) {
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2470,17 +2470,17 @@ nsCSSFrameConstructor::ConstructDocEleme
 
     nsXBLService* xblService = nsXBLService::GetInstance();
     if (!xblService) {
       return nullptr;
     }
 
     RefPtr<nsXBLBinding> binding;
     rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
-                                  display->mBinding->mOriginPrincipal,
+                                  display->mBinding->mExtraData->GetPrincipal(),
                                   getter_AddRefs(binding), &resolveStyle);
     if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
       return nullptr; // Binding will load asynchronously.
 
     if (binding) {
       // For backwards compat, keep firing the root's constructor
       // after all of its kids' constructors.  So tell the binding
       // manager about it right now.
@@ -5774,20 +5774,20 @@ nsCSSFrameConstructor::AddFrameConstruct
       nsXBLService* xblService = nsXBLService::GetInstance();
       if (!xblService)
         return;
 
       bool resolveStyle;
 
       nsAutoPtr<PendingBinding> newPendingBinding(new PendingBinding());
 
-      nsresult rv = xblService->LoadBindings(aContent, display->mBinding->GetURI(),
-                                             display->mBinding->mOriginPrincipal,
-                                             getter_AddRefs(newPendingBinding->mBinding),
-                                             &resolveStyle);
+      nsresult rv = xblService->LoadBindings(
+        aContent, display->mBinding->GetURI(),
+        display->mBinding->mExtraData->GetPrincipal(),
+        getter_AddRefs(newPendingBinding->mBinding), &resolveStyle);
       if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED)
         return;
 
       if (newPendingBinding->mBinding) {
         pendingBinding = newPendingBinding;
         // aState takes over owning newPendingBinding
         aState.AddPendingBinding(newPendingBinding.forget());
       }
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -1093,22 +1093,23 @@ FontFaceSet::FindOrCreateUserFontEntryFr
         switch (unit) {
 
         case eCSSUnit_Local_Font:
           val.GetStringValue(face->mLocalName);
           face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
           face->mURI = nullptr;
           face->mFormatFlags = 0;
           break;
-        case eCSSUnit_URL:
+        case eCSSUnit_URL: {
           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
           face->mURI = val.GetURLValue();
-          face->mReferrer = val.GetURLStructValue()->mReferrer;
+          URLValue* url = val.GetURLStructValue();
+          face->mReferrer = url->mExtraData->GetReferrer();
           face->mReferrerPolicy = mDocument->GetReferrerPolicy();
-          face->mOriginPrincipal = val.GetURLStructValue()->mOriginPrincipal;
+          face->mOriginPrincipal = url->mExtraData->GetPrincipal();
           NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
 
           // agent and user stylesheets are treated slightly differently,
           // the same-site origin check and access control headers are
           // enforced against the sheet principal rather than the document
           // principal to allow user stylesheets to include @font-face rules
           face->mUseOriginPrincipal = (aSheetType == SheetType::User ||
                                        aSheetType == SheetType::Agent);
@@ -1142,16 +1143,17 @@ FontFaceSet::FindOrCreateUserFontEntryFr
           }
           if (!face->mURI) {
             // if URI not valid, omit from src array
             srcArray.RemoveElementAt(srcArray.Length() - 1);
             NS_WARNING("null url in @font-face rule");
             continue;
           }
           break;
+        }
         default:
           NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
                        "strange unit type in font-face src array");
           break;
         }
        }
     } else {
       NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -25,31 +25,27 @@ SERVO_BINDING_FUNC(Servo_Element_ClearDa
 SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetStrong,
                    mozilla::css::SheetParsingMode parsing_mode)
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
                    mozilla::css::Loader* loader,
                    mozilla::ServoStyleSheet* gecko_stylesheet,
                    const nsACString* data,
                    mozilla::css::SheetParsingMode parsing_mode,
                    const nsACString* base_url,
-                   ThreadSafeURIHolder* base,
-                   ThreadSafeURIHolder* referrer,
-                   ThreadSafePrincipalHolder* principal)
+                   RawGeckoURLExtraData* extra_data)
 SERVO_BINDING_FUNC(Servo_ImportRule_GetSheet,
                    RawServoStyleSheetStrong,
                    const RawServoImportRuleBorrowed import_rule)
 SERVO_BINDING_FUNC(Servo_StyleSheet_ClearAndUpdate,
                    void,
                    RawServoStyleSheetBorrowed stylesheet,
                    mozilla::css::Loader* loader,
                    mozilla::ServoStyleSheet* gecko_stylesheet,
                    const nsACString* data,
-                   ThreadSafeURIHolder* base,
-                   ThreadSafeURIHolder* referrer,
-                   ThreadSafePrincipalHolder* principal)
+                   RawGeckoURLExtraData* extra_data)
 SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned, RawGeckoPresContextOwned pres_context)
 SERVO_BINDING_FUNC(Servo_StyleSet_RebuildData, void,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
@@ -117,21 +113,21 @@ SERVO_BINDING_FUNC(Servo_NamespaceRule_G
 SERVO_BINDING_FUNC(Servo_NamespaceRule_GetURI, nsIAtom*,
                    RawServoNamespaceRuleBorrowed rule)
 
 // Animations API
 SERVO_BINDING_FUNC(Servo_ParseProperty,
                    RawServoDeclarationBlockStrong,
                    const nsACString* property, const nsACString* value,
                    const nsACString* base,
-                   const GeckoParserExtraData* data)
+                   RawGeckoURLExtraData* data)
 SERVO_BINDING_FUNC(Servo_ParseEasing, bool,
                    const nsAString* easing,
                    const nsACString* base,
-                   const GeckoParserExtraData* data,
+                   RawGeckoURLExtraData* data,
                    nsTimingFunctionBorrowedMut output)
 SERVO_BINDING_FUNC(Servo_GetComputedKeyframeValues, void,
                    RawGeckoKeyframeListBorrowed keyframes,
                    ServoComputedValuesBorrowed style,
                    ServoComputedValuesBorrowedOrNull parent_style,
                    RawServoStyleSetBorrowed set,
                    RawGeckoComputedKeyframeValuesListBorrowedMut result)
 SERVO_BINDING_FUNC(Servo_AnimationValueMap_Push, void,
@@ -157,17 +153,17 @@ SERVO_BINDING_FUNC(Servo_AnimationValue_
 SERVO_BINDING_FUNC(Servo_AnimationValue_DeepEqual, bool,
                    RawServoAnimationValueBorrowed,
                    RawServoAnimationValueBorrowed)
 
 // Style attribute
 SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
                    const nsACString* data,
                    const nsACString* base,
-                   const GeckoParserExtraData* extraData)
+                   RawGeckoURLExtraData* extra_data)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_CreateEmpty,
                    RawServoDeclarationBlockStrong)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Clone, RawServoDeclarationBlockStrong,
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Equals, bool,
                    RawServoDeclarationBlockBorrowed a,
                    RawServoDeclarationBlockBorrowed b)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetCssText, void,
@@ -190,23 +186,23 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyIsImportant, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetProperty, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property,
                    const nsACString* value, bool is_important,
                    const nsACString* base,
-                   const GeckoParserExtraData* data)
+                   RawGeckoURLExtraData* data)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetPropertyById, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property,
                    const nsACString* value, bool is_important,
                    const nsACString* base,
-                   const GeckoParserExtraData* data)
+                   RawGeckoURLExtraData* data)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemovePropertyById, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property)
 
 // presentation attributes
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -17,16 +17,19 @@ struct RawServoStyleSet;
 
 #define SERVO_ARC_TYPE(name_, type_) struct type_;
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
 
 namespace mozilla {
   class ServoElementSnapshot;
   struct StyleAnimation;
+namespace css {
+struct URLExtraData;
+} // namespace css
 namespace dom {
 class Element;
 class StyleChildrenIterator;
 } // namespace dom
 struct Keyframe;
 struct PropertyStyleAnimationValuePair;
 using ComputedKeyframeValues = nsTArray<PropertyStyleAnimationValuePair>;
 } // namespace mozilla
@@ -40,16 +43,17 @@ struct nsTimingFunction;
 
 using mozilla::dom::StyleChildrenIterator;
 using mozilla::ServoElementSnapshot;
 
 typedef nsINode RawGeckoNode;
 typedef mozilla::dom::Element RawGeckoElement;
 typedef nsIDocument RawGeckoDocument;
 typedef nsPresContext RawGeckoPresContext;
+typedef mozilla::css::URLExtraData RawGeckoURLExtraData;
 typedef nsTArray<mozilla::Keyframe> RawGeckoKeyframeList;
 typedef nsTArray<mozilla::ComputedKeyframeValues> RawGeckoComputedKeyframeValuesList;
 typedef nsTArray<mozilla::PropertyStyleAnimationValuePair> RawGeckoAnimationValueList;
 typedef nsStyleAutoArray<mozilla::StyleAnimation> RawGeckoStyleAnimationList;
 typedef nsTArray<nsFontFaceRuleContainer> RawGeckoFontFaceRuleList;
 
 // We have these helper types so that we can directly generate
 // things like &T or Borrowed<T> on the Rust side in the function, providing
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -867,52 +867,37 @@ Gecko_SetListStyleType(nsStyleList* styl
 }
 
 void
 Gecko_CopyListStyleTypeFrom(nsStyleList* dst, const nsStyleList* src)
 {
   dst->SetCounterStyle(src->GetCounterStyle());
 }
 
-NS_IMPL_HOLDER_FFI_REFCOUNTING(nsIPrincipal, Principal)
-NS_IMPL_HOLDER_FFI_REFCOUNTING(nsIURI, URI)
-
 already_AddRefed<css::URLValue>
 ServoBundledURI::IntoCssUrl()
 {
   if (!mURLString) {
     return nullptr;
   }
 
-  MOZ_ASSERT(mBaseURI);
-  MOZ_ASSERT(mReferrer);
-  MOZ_ASSERT(mPrincipal);
+  MOZ_ASSERT(mExtraData->GetReferrer());
+  MOZ_ASSERT(mExtraData->GetPrincipal());
 
   nsString url;
   nsDependentCSubstring urlString(reinterpret_cast<const char*>(mURLString),
                                   mURLStringLength);
   AppendUTF8toUTF16(urlString, url);
   RefPtr<nsStringBuffer> urlBuffer = nsCSSValue::BufferFromString(url);
 
-  RefPtr<css::URLValue> urlValue = new css::URLValue(urlBuffer,
-                                                     do_AddRef(mBaseURI),
-                                                     do_AddRef(mReferrer),
-                                                     do_AddRef(mPrincipal));
+  RefPtr<css::URLValue> urlValue =
+    new css::URLValue(urlBuffer, do_AddRef(mExtraData));
   return urlValue.forget();
 }
 
-GeckoParserExtraData::GeckoParserExtraData(nsIURI* aBaseURI,
-                                           nsIURI* aReferrer,
-                                           nsIPrincipal* aPrincipal)
-    : mBaseURI(new ThreadSafeURIHolder(aBaseURI)),
-      mReferrer(new ThreadSafeURIHolder(aReferrer)),
-      mPrincipal(new ThreadSafePrincipalHolder(aPrincipal))
-{
-}
-
 void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
   MOZ_ASSERT(aImage);
   aImage->SetNull();
 }
 
 void
@@ -922,29 +907,27 @@ Gecko_SetGradientImageValue(nsStyleImage
   aImage->SetGradientData(aGradient);
 }
 
 static already_AddRefed<nsStyleImageRequest>
 CreateStyleImageRequest(nsStyleImageRequest::Mode aModeFlags,
                         ServoBundledURI aURI)
 {
   MOZ_ASSERT(aURI.mURLString);
-  MOZ_ASSERT(aURI.mBaseURI);
-  MOZ_ASSERT(aURI.mReferrer);
-  MOZ_ASSERT(aURI.mPrincipal);
+  MOZ_ASSERT(aURI.mExtraData->GetReferrer());
+  MOZ_ASSERT(aURI.mExtraData->GetPrincipal());
 
   nsString url;
   nsDependentCSubstring urlString(reinterpret_cast<const char*>(aURI.mURLString),
                                   aURI.mURLStringLength);
   AppendUTF8toUTF16(urlString, url);
   RefPtr<nsStringBuffer> urlBuffer = nsCSSValue::BufferFromString(url);
 
   RefPtr<nsStyleImageRequest> req =
-    new nsStyleImageRequest(aModeFlags, urlBuffer, do_AddRef(aURI.mBaseURI),
-                            do_AddRef(aURI.mReferrer), do_AddRef(aURI.mPrincipal));
+    new nsStyleImageRequest(aModeFlags, urlBuffer, do_AddRef(aURI.mExtraData));
   return req.forget();
 }
 
 void
 Gecko_SetUrlImageValue(nsStyleImage* aImage, ServoBundledURI aURI)
 {
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aURI);
@@ -1315,16 +1298,18 @@ css::URLValue*
 Gecko_NewURLValue(ServoBundledURI aURI)
 {
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   return url.forget().take();
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLValue, CSSURLValue);
 
+NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLExtraData, URLExtraData);
+
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray*
 Gecko_NewCSSShadowArray(uint32_t aLen)
 {
   RefPtr<nsCSSShadowArray> arr = new(aLen) nsCSSShadowArray(aLen);
   return arr.forget().take();
 }
@@ -1547,43 +1532,44 @@ Gecko_nsStyleFont_GetBaseSize(const nsSt
 {
   return aPresContext->GetDefaultFont(aFont->mGenericID, aFont->mLanguage)->size;
 }
 
 void
 Gecko_LoadStyleSheet(css::Loader* aLoader,
                      ServoStyleSheet* aParent,
                      RawServoImportRuleBorrowed aImportRule,
-                     nsIURI* aBaseURI,
+                     RawGeckoURLExtraData* aBaseURLData,
                      const uint8_t* aURLString,
                      uint32_t aURLStringLength,
                      const uint8_t* aMediaString,
                      uint32_t aMediaStringLength)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aLoader, "Should've catched this before");
   MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
   MOZ_ASSERT(aURLString, "Invalid URLs shouldn't be loaded!");
-  MOZ_ASSERT(aBaseURI, "Need a base URI");
+  MOZ_ASSERT(aBaseURLData, "Need base URL data");
   RefPtr<nsMediaList> media = new nsMediaList();
   if (aMediaStringLength) {
     MOZ_ASSERT(aMediaString);
     // TODO(emilio, bug 1325878): This is not great, though this is going away
     // soon anyway, when we can have a Servo-backed nsMediaList.
     nsDependentCSubstring medium(reinterpret_cast<const char*>(aMediaString),
                                  aMediaStringLength);
     nsCSSParser mediumParser(aLoader);
     mediumParser.ParseMediaList(
         NS_ConvertUTF8toUTF16(medium), nullptr, 0, media);
   }
 
   nsDependentCSubstring urlSpec(reinterpret_cast<const char*>(aURLString),
                                 aURLStringLength);
   nsCOMPtr<nsIURI> uri;
-  nsresult rv = NS_NewURI(getter_AddRefs(uri), urlSpec, nullptr, aBaseURI);
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), urlSpec, nullptr,
+                          aBaseURLData->BaseURI());
 
   if (NS_FAILED(rv)) {
     // Servo and Gecko have different ideas of what a valid URL is, so we might
     // get in here with a URL string that NS_NewURI can't handle.  If so,
     // silently do nothing.  Eventually we should be able to assert that the
     // NS_NewURI succeeds, here.
     return;
   }
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -59,69 +59,41 @@ struct nsStyleDisplay;
   static_assert(class_::HasThreadSafeRefCnt::value,                           \
                 "NS_DECL_THREADSAFE_FFI_REFCOUNTING can only be used with "   \
                 "classes that have thread-safe refcounting");                 \
   void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr)                     \
   { NS_ADDREF(aPtr); }                                                        \
   void Gecko_Release##name_##ArbitraryThread(class_* aPtr)                    \
   { NS_RELEASE(aPtr); }
 
-#define NS_DECL_HOLDER_FFI_REFCOUNTING(class_, name_)                         \
-  typedef nsMainThreadPtrHolder<class_> ThreadSafe##name_##Holder;            \
-  void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr); \
-  void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr);
-#define NS_IMPL_HOLDER_FFI_REFCOUNTING(class_, name_)                         \
-  void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr)  \
-  { NS_ADDREF(aPtr); }                                                        \
-  void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr) \
-  { NS_RELEASE(aPtr); }                                                       \
-
 #define NS_DECL_FFI_REFCOUNTING(class_, name_)  \
   void Gecko_##name_##_AddRef(class_* aPtr);    \
   void Gecko_##name_##_Release(class_* aPtr);
 #define NS_IMPL_FFI_REFCOUNTING(class_, name_)                    \
   void Gecko_##name_##_AddRef(class_* aPtr) { NS_ADDREF(aPtr); }  \
   void Gecko_##name_##_Release(class_* aPtr) { NS_RELEASE(aPtr); }
 
-
 #define DEFINE_ARRAY_TYPE_FOR(type_)                                \
   struct nsTArrayBorrowed_##type_ {                                 \
     nsTArray<type_>* mArray;                                        \
     MOZ_IMPLICIT nsTArrayBorrowed_##type_(nsTArray<type_>* aArray)  \
       : mArray(aArray) {}                                           \
   }
 DEFINE_ARRAY_TYPE_FOR(uintptr_t);
 #undef DEFINE_ARRAY_TYPE_FOR
 
 extern "C" {
 
-// Object refcounting.
-NS_DECL_HOLDER_FFI_REFCOUNTING(nsIPrincipal, Principal)
-NS_DECL_HOLDER_FFI_REFCOUNTING(nsIURI, URI)
-
 class ServoBundledURI
 {
 public:
   already_AddRefed<mozilla::css::URLValue> IntoCssUrl();
   const uint8_t* mURLString;
   uint32_t mURLStringLength;
-  ThreadSafeURIHolder* mBaseURI;
-  ThreadSafeURIHolder* mReferrer;
-  ThreadSafePrincipalHolder* mPrincipal;
-};
-
-class GeckoParserExtraData
-{
-public:
-  GeckoParserExtraData(nsIURI* aBaseURI,
-                       nsIURI* aReferrer,
-                       nsIPrincipal* aPrincipal);
-  RefPtr<ThreadSafeURIHolder> mBaseURI;
-  RefPtr<ThreadSafeURIHolder> mReferrer;
-  RefPtr<ThreadSafePrincipalHolder> mPrincipal;
+  mozilla::css::URLExtraData* mExtraData;
 };
 
 // DOM Traversal.
 uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
 bool Gecko_NodeIsElement(RawGeckoNodeBorrowed node);
 bool Gecko_IsInDocument(RawGeckoNodeBorrowed node);
 bool Gecko_FlattenedTreeParentIsParent(RawGeckoNodeBorrowed node);
 bool Gecko_IsSignificantChild(RawGeckoNodeBorrowed node,
@@ -135,17 +107,17 @@ RawGeckoNodeBorrowedOrNull Gecko_GetNext
 RawGeckoElementBorrowedOrNull Gecko_GetFirstChildElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetPrevSiblingElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetNextSiblingElement(RawGeckoElementBorrowed element);
 RawGeckoElementBorrowedOrNull Gecko_GetDocumentElement(RawGeckoDocumentBorrowed document);
 void Gecko_LoadStyleSheet(mozilla::css::Loader* loader,
                           mozilla::ServoStyleSheet* parent,
                           RawServoImportRuleBorrowed import_rule,
-                          nsIURI* base_uri,
+                          RawGeckoURLExtraData* base_url_data,
                           const uint8_t* url_bytes,
                           uint32_t url_length,
                           const uint8_t* media_bytes,
                           uint32_t media_length);
 
 // By default, Servo walks the DOM by traversing the siblings of the DOM-view
 // first child. This generally works, but misses anonymous children, which we
 // want to traverse during styling. To support these cases, we create an
@@ -341,16 +313,17 @@ void Gecko_nsStyleSVGPaint_CopyFrom(nsSt
 void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, ServoBundledURI 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);
 
 mozilla::css::URLValue* Gecko_NewURLValue(ServoBundledURI uri);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue);
+NS_DECL_THREADSAFE_FFI_REFCOUNTING(RawGeckoURLExtraData, URLExtraData);
 
 void Gecko_FillAllBackgroundLists(nsStyleImageLayers* layers, uint32_t max_len);
 void Gecko_FillAllMaskLists(nsStyleImageLayers* layers, uint32_t max_len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
 
--- a/layout/style/ServoDeclarationBlock.cpp
+++ b/layout/style/ServoDeclarationBlock.cpp
@@ -8,24 +8,24 @@
 #include "mozilla/ServoBindings.h"
 
 #include "nsCSSProps.h"
 
 namespace mozilla {
 
 /* static */ already_AddRefed<ServoDeclarationBlock>
 ServoDeclarationBlock::FromCssText(const nsAString& aCssText,
-                                   const GeckoParserExtraData& aExtraData)
+                                   css::URLExtraData* aExtraData)
 {
   NS_ConvertUTF16toUTF8 value(aCssText);
   nsCString baseString;
   // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
-  aExtraData.mBaseURI->get()->GetSpec(baseString);
+  aExtraData->BaseURI()->GetSpec(baseString);
   RefPtr<RawServoDeclarationBlock>
-    raw = Servo_ParseStyleAttribute(&value, &baseString, &aExtraData).Consume();
+    raw = Servo_ParseStyleAttribute(&value, &baseString, aExtraData).Consume();
   RefPtr<ServoDeclarationBlock> decl = new ServoDeclarationBlock(raw.forget());
   return decl.forget();
 }
 
 void
 ServoDeclarationBlock::GetPropertyValue(const nsAString& aProperty,
                                         nsAString& aValue) const
 {
--- a/layout/style/ServoDeclarationBlock.h
+++ b/layout/style/ServoDeclarationBlock.h
@@ -23,18 +23,17 @@ public:
 
   ServoDeclarationBlock(const ServoDeclarationBlock& aCopy)
     : DeclarationBlock(aCopy)
     , mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume()) {}
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ServoDeclarationBlock)
 
   static already_AddRefed<ServoDeclarationBlock>
-  FromCssText(const nsAString& aCssText,
-              const GeckoParserExtraData& aExtraData);
+  FromCssText(const nsAString& aCssText, css::URLExtraData* aExtraData);
 
   RawServoDeclarationBlock* Raw() const { return mRaw; }
   RawServoDeclarationBlock* const* RefRaw() const {
     static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
                   sizeof(RawServoDeclarationBlock*),
                   "RefPtr should just be a pointer");
     return reinterpret_cast<RawServoDeclarationBlock* const*>(&mRaw);
   }
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -82,34 +82,31 @@ ServoStyleSheet::HasRules() const
 nsresult
 ServoStyleSheet::ParseSheet(css::Loader* aLoader,
                             const nsAString& aInput,
                             nsIURI* aSheetURI,
                             nsIURI* aBaseURI,
                             nsIPrincipal* aSheetPrincipal,
                             uint32_t aLineNumber)
 {
-  RefPtr<ThreadSafeURIHolder> base = new ThreadSafeURIHolder(aBaseURI);
-  RefPtr<ThreadSafeURIHolder> referrer = new ThreadSafeURIHolder(aSheetURI);
-  RefPtr<ThreadSafePrincipalHolder> principal =
-    new ThreadSafePrincipalHolder(aSheetPrincipal);
+  RefPtr<css::URLExtraData> extraData =
+    new css::URLExtraData(aBaseURI, aSheetURI, aSheetPrincipal);
 
   nsCString baseString;
   nsresult rv = aBaseURI->GetSpec(baseString);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF16toUTF8 input(aInput);
   if (!Inner()->mSheet) {
     Inner()->mSheet =
       Servo_StyleSheet_FromUTF8Bytes(aLoader, this, &input, mParsingMode,
-                                     &baseString, base, referrer,
-                                     principal).Consume();
+                                     &baseString, extraData).Consume();
   } else {
-    Servo_StyleSheet_ClearAndUpdate(Inner()->mSheet, aLoader, this, &input, base,
-                                    referrer, principal);
+    Servo_StyleSheet_ClearAndUpdate(Inner()->mSheet, aLoader,
+                                    this, &input, extraData);
   }
 
   return NS_OK;
 }
 
 void
 ServoStyleSheet::LoadFailed()
 {
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -896,19 +896,17 @@ nsCSSValue::GetCalcValue() const
 }
 
 void nsCSSValue::StartImageLoad(nsIDocument* aDocument) const
 {
   MOZ_ASSERT(eCSSUnit_URL == mUnit, "Not a URL value!");
   mozilla::css::ImageValue* image =
     new mozilla::css::ImageValue(mValue.mURL->GetURI(),
                                  mValue.mURL->mString,
-                                 mValue.mURL->mBaseURI,
-                                 mValue.mURL->mReferrer,
-                                 mValue.mURL->mOriginPrincipal,
+                                 do_AddRef(mValue.mURL->mExtraData),
                                  aDocument);
 
   nsCSSValue* writable = const_cast<nsCSSValue*>(this);
   writable->SetImageValue(image);
 }
 
 nscolor nsCSSValue::GetColorValue() const
 {
@@ -2780,103 +2778,102 @@ 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::URLExtraData::~URLExtraData()
+{
+  if (!NS_IsMainThread()) {
+    NS_ReleaseOnMainThread(mBaseURI.forget());
+    NS_ReleaseOnMainThread(mReferrer.forget());
+    NS_ReleaseOnMainThread(mPrincipal.forget());
+  }
+}
+
 css::URLValueData::URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI,
                                 nsStringBuffer* aString,
-                                already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-                                already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-                                already_AddRefed<PtrHolder<nsIPrincipal>>
-                                  aOriginPrincipal)
+                                already_AddRefed<URLExtraData> aExtraData)
   : mURI(Move(aURI))
-  , mBaseURI(Move(aBaseURI))
   , mString(aString)
-  , mReferrer(Move(aReferrer))
-  , mOriginPrincipal(Move(aOriginPrincipal))
+  , mExtraData(Move(aExtraData))
   , mURIResolved(true)
   , mIsLocalRef(IsLocalRefURL(aString))
 {
   MOZ_ASSERT(mString);
-  MOZ_ASSERT(mBaseURI);
-  MOZ_ASSERT(mOriginPrincipal);
+  MOZ_ASSERT(mExtraData);
+  MOZ_ASSERT(mExtraData->GetPrincipal());
 }
 
 css::URLValueData::URLValueData(nsStringBuffer* aString,
-                                already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-                                already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-                                already_AddRefed<PtrHolder<nsIPrincipal>>
-                                  aOriginPrincipal)
-  : mBaseURI(Move(aBaseURI))
-  , mString(aString)
-  , mReferrer(Move(aReferrer))
-  , mOriginPrincipal(Move(aOriginPrincipal))
+                                already_AddRefed<URLExtraData> aExtraData)
+  : mString(aString)
+  , mExtraData(Move(aExtraData))
   , mURIResolved(false)
   , mIsLocalRef(IsLocalRefURL(aString))
 {
   MOZ_ASSERT(aString);
-  MOZ_ASSERT(mBaseURI);
-  MOZ_ASSERT(mOriginPrincipal);
+  MOZ_ASSERT(mExtraData);
+  MOZ_ASSERT(mExtraData->GetPrincipal());
 }
 
 bool
 css::URLValueData::Equals(const URLValueData& aOther) const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool eq;
   // Cast away const so we can call nsIPrincipal::Equals.
-  auto& self = *const_cast<URLValueData*>(this);
-  auto& other = const_cast<URLValueData&>(aOther);
+  const URLExtraData* self = mExtraData;
+  const URLExtraData* other = aOther.mExtraData;
   return NS_strcmp(nsCSSValue::GetBufferValue(mString),
                    nsCSSValue::GetBufferValue(aOther.mString)) == 0 &&
           (GetURI() == aOther.GetURI() || // handles null == null
            (mURI && aOther.mURI &&
             NS_SUCCEEDED(mURI->Equals(aOther.mURI, &eq)) &&
             eq)) &&
-          (mBaseURI == aOther.mBaseURI ||
-           (NS_SUCCEEDED(self.mBaseURI.get()->Equals(other.mBaseURI.get(), &eq)) &&
+          (self->BaseURI() == other->BaseURI() ||
+           (NS_SUCCEEDED(self->BaseURI()->Equals(other->BaseURI(), &eq)) &&
             eq)) &&
-          (mOriginPrincipal == aOther.mOriginPrincipal ||
-           self.mOriginPrincipal.get()->Equals(other.mOriginPrincipal.get())) &&
+          (self->GetPrincipal() == other->GetPrincipal() ||
+           self->GetPrincipal()->Equals(other->GetPrincipal())) &&
           mIsLocalRef == aOther.mIsLocalRef;
 }
 
 bool
 css::URLValueData::DefinitelyEqualURIs(const URLValueData& aOther) const
 {
-  return mBaseURI == aOther.mBaseURI &&
+  return mExtraData->BaseURI() == aOther.mExtraData->BaseURI() &&
          (mString == aOther.mString ||
           NS_strcmp(nsCSSValue::GetBufferValue(mString),
                     nsCSSValue::GetBufferValue(aOther.mString)) == 0);
 }
 
 bool
 css::URLValueData::DefinitelyEqualURIsAndPrincipal(
     const URLValueData& aOther) const
 {
-  return mOriginPrincipal == aOther.mOriginPrincipal &&
+  return mExtraData->GetPrincipal() == aOther.mExtraData->GetPrincipal() &&
          DefinitelyEqualURIs(aOther);
 }
 
 nsIURI*
 css::URLValueData::GetURI() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mURIResolved) {
     MOZ_ASSERT(!mURI);
     nsCOMPtr<nsIURI> newURI;
     NS_NewURI(getter_AddRefs(newURI),
               NS_ConvertUTF16toUTF8(nsCSSValue::GetBufferValue(mString)),
-              nullptr, const_cast<nsIURI*>(mBaseURI.get()));
+              nullptr, mExtraData->BaseURI());
     mURI = new PtrHolder<nsIURI>(newURI.forget());
     mURIResolved = true;
   }
 
   return mURI;
 }
 
 bool
@@ -2967,38 +2964,34 @@ size_t
 css::URLValueData::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = 0;
   n += mString->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
 
   // Measurement of the following members may be added later if DMD finds it
   // is worthwhile:
   // - mURI
-  // - mReferrer
-  // - mOriginPrincipal
+  // - mExtraData
   return n;
 }
 
 URLValue::URLValue(nsStringBuffer* aString, nsIURI* aBaseURI, nsIURI* aReferrer,
                    nsIPrincipal* aOriginPrincipal)
-  : URLValueData(aString,
-                 do_AddRef(new PtrHolder<nsIURI>(aBaseURI)),
-                 do_AddRef(new PtrHolder<nsIURI>(aReferrer)),
-                 do_AddRef(new PtrHolder<nsIPrincipal>(aOriginPrincipal)))
+  : URLValueData(aString, do_AddRef(new URLExtraData(aBaseURI, aReferrer,
+                                                     aOriginPrincipal)))
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 URLValue::URLValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aBaseURI,
                    nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal)
   : URLValueData(do_AddRef(new PtrHolder<nsIURI>(aURI)),
                  aString,
-                 do_AddRef(new PtrHolder<nsIURI>(aBaseURI)),
-                 do_AddRef(new PtrHolder<nsIURI>(aReferrer)),
-                 do_AddRef(new PtrHolder<nsIPrincipal>(aOriginPrincipal)))
+                 do_AddRef(new URLExtraData(aBaseURI, aReferrer,
+                                            aOriginPrincipal)))
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 size_t
 css::URLValue::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   // Only measure it if it's unshared, to avoid double-counting.
@@ -3006,35 +2999,27 @@ css::URLValue::SizeOfIncludingThis(mozil
   if (mRefCnt <= 1) {
     n += aMallocSizeOf(this);
     n += URLValueData::SizeOfExcludingThis(aMallocSizeOf);
   }
   return n;
 }
 
 css::ImageValue::ImageValue(nsIURI* aURI, nsStringBuffer* aString,
-                            nsIURI* aBaseURI, nsIURI* aReferrer,
-                            nsIPrincipal* aOriginPrincipal,
+                            already_AddRefed<URLExtraData> aExtraData,
                             nsIDocument* aDocument)
   : URLValueData(do_AddRef(new PtrHolder<nsIURI>(aURI)),
-                 aString,
-                 do_AddRef(new PtrHolder<nsIURI>(aBaseURI, false)),
-                 do_AddRef(new PtrHolder<nsIURI>(aReferrer)),
-                 do_AddRef(new PtrHolder<nsIPrincipal>(aOriginPrincipal)))
+                 aString, Move(aExtraData))
 {
   Initialize(aDocument);
 }
 
-css::ImageValue::ImageValue(
-    nsStringBuffer* aString,
-    already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-    already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-    already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal)
-  : URLValueData(aString, Move(aBaseURI), Move(aReferrer),
-                 Move(aOriginPrincipal))
+css::ImageValue::ImageValue(nsStringBuffer* aString,
+                            already_AddRefed<URLExtraData> aExtraData)
+  : URLValueData(aString, Move(aExtraData))
 {
 }
 
 void
 css::ImageValue::Initialize(nsIDocument* aDocument)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mInitialized);
@@ -3042,18 +3027,19 @@ css::ImageValue::Initialize(nsIDocument*
   // NB: If aDocument is not the original document, we may not be able to load
   // images from aDocument.  Instead we do the image load from the original doc
   // and clone it to aDocument.
   nsIDocument* loadingDoc = aDocument->GetOriginalDocument();
   if (!loadingDoc) {
     loadingDoc = aDocument;
   }
 
-  loadingDoc->StyleImageLoader()->LoadImage(GetURI(), mOriginPrincipal,
-                                            mReferrer, this);
+  loadingDoc->StyleImageLoader()->LoadImage(GetURI(),
+                                            mExtraData->GetPrincipal(),
+                                            mExtraData->GetReferrer(), this);
 
   if (loadingDoc != aDocument) {
     aDocument->StyleImageLoader()->MaybeRegisterCSSImage(this);
   }
 
 #ifdef DEBUG
   mInitialized = true;
 #endif
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -88,37 +88,64 @@ class CSSStyleSheet;
       dest->member_ = clm_clone;                                               \
       dest = clm_clone;                                                        \
     }                                                                          \
   }
 
 namespace mozilla {
 namespace css {
 
+struct URLExtraData
+{
+  URLExtraData(already_AddRefed<nsIURI> aBaseURI,
+               already_AddRefed<nsIURI> aReferrer,
+               already_AddRefed<nsIPrincipal> aPrincipal)
+    : mBaseURI(Move(aBaseURI))
+    , mReferrer(Move(aReferrer))
+    , mPrincipal(Move(aPrincipal))
+  {
+    MOZ_ASSERT(mBaseURI);
+  }
+
+  URLExtraData(nsIURI* aBaseURI, nsIURI* aReferrer, nsIPrincipal* aPrincipal)
+    : URLExtraData(do_AddRef(aBaseURI),
+                   do_AddRef(aReferrer),
+                   do_AddRef(aPrincipal)) {}
+
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLExtraData)
+
+  nsIURI* BaseURI() const { return mBaseURI; }
+  nsIURI* GetReferrer() const { return mReferrer; }
+  nsIPrincipal* GetPrincipal() const { return mPrincipal; }
+
+private:
+  ~URLExtraData();
+
+  RefPtr<nsIURI> mBaseURI;
+  RefPtr<nsIURI> mReferrer;
+  RefPtr<nsIPrincipal> mPrincipal;
+};
+
 struct URLValueData
 {
 protected:
   // Methods are not inline because using an nsIPrincipal means requiring
   // caps, which leads to REQUIRES hell, since this header is included all
   // over.
 
   // For both constructors aString must not be null.
-  // For both constructors aOriginPrincipal must not be null.
+  // For both constructors principal of aExtraData must not be null.
   // Construct with a base URI; this will create the actual URI lazily from
-  // aString and aBaseURI.
+  // aString and aExtraData.
   URLValueData(nsStringBuffer* aString,
-               already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-               already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-               already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPricinpal);
+               already_AddRefed<URLExtraData> aExtraData);
   // Construct with the actual URI.
   URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI,
                nsStringBuffer* aString,
-               already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-               already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-               already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal);
+               already_AddRefed<URLExtraData> aExtraData);
 
 public:
   // Returns true iff all fields of the two URLValueData 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;
 
@@ -154,20 +181,18 @@ public:
 
   bool EqualsExceptRef(nsIURI* aURI) const;
 
 private:
   // mURI stores the lazily resolved URI.  This may be null if the URI is
   // invalid, even once resolved.
   mutable PtrHandle<nsIURI> mURI;
 public:
-  PtrHandle<nsIURI> mBaseURI;
   RefPtr<nsStringBuffer> mString;
-  PtrHandle<nsIURI> mReferrer;
-  PtrHandle<nsIPrincipal> mOriginPrincipal;
+  RefPtr<URLExtraData> mExtraData;
 private:
   mutable bool mURIResolved;
   // mIsLocalRef is set when url starts with a U+0023 number sign(#) character.
   bool mIsLocalRef;
 
 protected:
   virtual ~URLValueData() = default;
 
@@ -183,46 +208,41 @@ struct URLValue final : public URLValueD
   // These two constructors are safe to call only on the main thread.
   URLValue(nsStringBuffer* aString, nsIURI* aBaseURI, nsIURI* aReferrer,
            nsIPrincipal* aOriginPrincipal);
   URLValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aBaseURI,
            nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal);
 
   // This constructor is safe to call from any thread.
   URLValue(nsStringBuffer* aString,
-           already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-           already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-           already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal)
-    : URLValueData(aString, Move(aBaseURI), Move(aReferrer),
-                   Move(aOriginPrincipal)) {}
+           already_AddRefed<URLExtraData> aExtraData)
+    : URLValueData(aString, Move(aExtraData)) {}
 
   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.
   // aString must not be null.
   //
   // This constructor is only safe to call from the main thread.
-  ImageValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aBaseURI,
-             nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal,
+  ImageValue(nsIURI* aURI, nsStringBuffer* aString,
+             already_AddRefed<URLExtraData> aExtraData,
              nsIDocument* aDocument);
 
   // This constructor is safe to call from any thread, but Initialize
   // must be called later for the object to be useful.
   ImageValue(nsStringBuffer* aString,
-             already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-             already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-             already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal);
+             already_AddRefed<URLExtraData> aExtraData);
 
   ImageValue(const ImageValue&) = delete;
   ImageValue& operator=(const ImageValue&) = delete;
 
   void Initialize(nsIDocument* aDocument);
 
   // XXXheycam We should have our own SizeOfIncludingThis method.
 
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -126,17 +126,18 @@ nsDOMCSSDeclaration::SetCssText(const ns
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
 
   RefPtr<DeclarationBlock> newdecl;
   if (olddecl->IsServo()) {
-    GeckoParserExtraData data(env.mBaseURI, env.mSheetURI, env.mPrincipal);
+    RefPtr<css::URLExtraData> data =
+      new css::URLExtraData(env.mBaseURI, env.mSheetURI, env.mPrincipal);
     newdecl = ServoDeclarationBlock::FromCssText(aCssText, data);
   } else {
     RefPtr<css::Declaration> decl(new css::Declaration());
     decl->InitializeEmpty();
     nsCSSParser cssParser(env.mCSSLoader);
     bool changed;
     nsresult result = cssParser.ParseDeclarations(aCssText, env.mSheetURI,
                                                   env.mBaseURI, env.mPrincipal,
@@ -302,22 +303,23 @@ nsDOMCSSDeclaration::ParsePropertyValue(
   bool changed;
   if (decl->IsGecko()) {
     nsCSSParser cssParser(env.mCSSLoader);
     cssParser.ParseProperty(aPropID, aPropValue,
                             env.mSheetURI, env.mBaseURI, env.mPrincipal,
                             decl->AsGecko(), &changed, aIsImportant);
   } else {
     NS_ConvertUTF16toUTF8 value(aPropValue);
-    GeckoParserExtraData data(env.mBaseURI, env.mSheetURI, env.mPrincipal);
+    RefPtr<css::URLExtraData> data =
+      new css::URLExtraData(env.mBaseURI, env.mSheetURI, env.mPrincipal);
     nsCString baseString;
     // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
     env.mBaseURI->GetSpec(baseString);
     changed = Servo_DeclarationBlock_SetPropertyById(
-      decl->AsServo()->Raw(), aPropID, &value, aIsImportant, &baseString, &data);
+      decl->AsServo()->Raw(), aPropID, &value, aIsImportant, &baseString, data);
   }
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }
@@ -353,21 +355,22 @@ nsDOMCSSDeclaration::ParseCustomProperty
     nsCSSParser cssParser(env.mCSSLoader);
     auto propName = Substring(aPropertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
     cssParser.ParseVariable(propName, aPropValue, env.mSheetURI,
                             env.mBaseURI, env.mPrincipal, decl->AsGecko(),
                             &changed, aIsImportant);
   } else {
     NS_ConvertUTF16toUTF8 property(aPropertyName);
     NS_ConvertUTF16toUTF8 value(aPropValue);
-    GeckoParserExtraData data(env.mBaseURI, env.mSheetURI, env.mPrincipal);
+    RefPtr<css::URLExtraData> data =
+      new css::URLExtraData(env.mBaseURI, env.mSheetURI, env.mPrincipal);
     nsCString baseString;
     env.mBaseURI->GetSpec(baseString);
     changed = Servo_DeclarationBlock_SetProperty(
-      decl->AsServo()->Raw(), &property, &value, aIsImportant, &baseString, &data);
+      decl->AsServo()->Raw(), &property, &value, aIsImportant, &baseString, data);
   }
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1994,24 +1994,21 @@ nsStyleImageRequest::nsStyleImageRequest
   if (mRequestProxy) {
     MaybeTrackAndLock();
   }
 }
 
 nsStyleImageRequest::nsStyleImageRequest(
     Mode aModeFlags,
     nsStringBuffer* aURLBuffer,
-    already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
-    already_AddRefed<PtrHolder<nsIURI>> aReferrer,
-    already_AddRefed<PtrHolder<nsIPrincipal>> aPrincipal)
-  : mModeFlags(aModeFlags)
+    already_AddRefed<css::URLExtraData> aExtraData)
+  : mImageValue(new css::ImageValue(aURLBuffer, Move(aExtraData)))
+  , mModeFlags(aModeFlags)
   , mResolved(false)
 {
-  mImageValue = new css::ImageValue(aURLBuffer, Move(aBaseURI),
-                                    Move(aReferrer), Move(aPrincipal));
 }
 
 nsStyleImageRequest::~nsStyleImageRequest()
 {
   // We may or may not be being destroyed on the main thread.  To clean
   // up, we must untrack and unlock the image (depending on mModeFlags),
   // and release mRequestProxy and mImageValue, all on the main thread.
   {
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -334,19 +334,17 @@ public:
                       mozilla::css::ImageValue* aImageValue,
                       mozilla::dom::ImageTracker* aImageTracker);
 
   // Can be called from any thread, but Resolve() must be called later
   // on the main thread before get() can be used.
   nsStyleImageRequest(
       Mode aModeFlags,
       nsStringBuffer* aURLBuffer,
-      already_AddRefed<mozilla::PtrHolder<nsIURI>> aBaseURI,
-      already_AddRefed<mozilla::PtrHolder<nsIURI>> aReferrer,
-      already_AddRefed<mozilla::PtrHolder<nsIPrincipal>> aPrincipal);
+      already_AddRefed<mozilla::css::URLExtraData> aExtraData);
 
   bool Resolve(nsPresContext* aPresContext);
   bool IsResolved() const { return mResolved; }
 
   imgRequestProxy* get() {
     MOZ_ASSERT(IsResolved(), "Resolve() must be called first");
     MOZ_ASSERT(NS_IsMainThread());
     return mRequestProxy.get();