Bug 1552708 - Use cbindgen for URIs. r=heycam

This doesn't clean up as much as a whole, but it's a step in the right
direction. In particular, it allows us to start using simple bindings for:

 * Filters
 * Shapes and images, almost. Need to:
   * Get rid of the complex -moz- gradient parsing (let
     layout.css.simple-moz-gradient.enabled get to release).
 * Counters, almost. Need to:
   * Share the Attr representation with Gecko, by not using Option<>.
     * Just another variant should be enough (ContentItem::{Attr,Prefixedattr},
       maybe).

Which in turn allows us to remove a whole lot of bindings in followups to this.

The setup changes a bit. This also removes the double pointer I complained about
while reviewing the shared UA sheet patches. The old setup is:

```
SpecifiedUrl
 * CssUrl
   * Arc<CssUrlData>
     * String
     * UrlExtraData
 * UrlValueSource
   * Arc<CssUrlData>
   * load id
   * resolved uri
   * CORS mode.
   * ...
```

The new one removes the double reference to the url data via URLValue, and looks
like:

```
SpecifiedUrl
 * CssUrl
   * Arc<CssUrlData>
     * String
     * UrlExtraData
     * CorsMode
     * LoadData
       * load id
       * resolved URI
```

The LoadData is the only mutable bit that C++ can change, and is not used from
Rust. Ideally, in the future, we could just use rust-url to resolve the URL
after parsing or something, and make it all immutable. Maybe.

I've verified that this approach still works with the UA sheet patches (via the
LoadDataSource::Lazy).

The reordering of mWillChange is to avoid nsStyleDisplay from going over the
size limit. We want to split it up anyway in bug 1552587, but mBinding gains a
tag member, which means that we were having a bit of extra padding.

One thing I want to explore is to see if we can abuse rustc's non-zero
optimizations to predict the layout from C++, but that's something to explore at
some other point in time and with a lot of care and help from Michael (who sits
next to me and works on rustc ;)).

Differential Revision: https://phabricator.services.mozilla.com/D31742
This commit is contained in:
Emilio Cobos Álvarez 2019-05-27 11:45:12 +00:00
parent 3be073fe95
commit a384dedd93
35 changed files with 799 additions and 859 deletions

View File

@ -545,19 +545,19 @@ static bool MayNeedToLoadXBLBinding(const Document& aDocument,
return aElement.IsAnyOfHTMLElements(nsGkAtoms::object, nsGkAtoms::embed);
}
bool Element::GetBindingURL(Document* aDocument, css::URLValue** aResult) {
StyleUrlOrNone Element::GetBindingURL(Document* aDocument) {
if (!MayNeedToLoadXBLBinding(*aDocument, *this)) {
*aResult = nullptr;
return true;
return StyleUrlOrNone::None();
}
// Get the computed -moz-binding directly from the ComputedStyle
RefPtr<ComputedStyle> sc =
RefPtr<ComputedStyle> style =
nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr);
NS_ENSURE_TRUE(sc, false);
if (!style) {
return StyleUrlOrNone::None();
}
NS_IF_ADDREF(*aResult = sc->StyleDisplay()->mBinding);
return true;
return style->StyleDisplay()->mBinding;
}
JSObject* Element::WrapObject(JSContext* aCx,
@ -597,17 +597,11 @@ JSObject* Element::WrapObject(JSContext* aCx,
// since that can destroy the relevant presshell.
{
// Make a scope so that ~nsRefPtr can GC before returning obj.
RefPtr<css::URLValue> bindingURL;
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->ExtraData()->Principal();
StyleUrlOrNone result = GetBindingURL(doc);
if (result.IsUrl()) {
auto& url = result.AsUrl();
nsCOMPtr<nsIURI> uri = url.GetURI();
nsCOMPtr<nsIPrincipal> principal = url.ExtraData().Principal();
// We have a binding that must be installed.
nsXBLService* xblService = nsXBLService::GetInstance();

View File

@ -460,7 +460,7 @@ class Element : public FragmentOrElement {
}
}
bool GetBindingURL(Document* aDocument, css::URLValue** aResult);
mozilla::StyleUrlOrNone GetBindingURL(Document* aDocument);
Directionality GetComputedDirectionality() const;

View File

@ -2246,7 +2246,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
// Ensure that our XBL bindings are installed.
//
// FIXME(emilio): Can we remove support for bindings on the root?
if (display->mBinding) {
if (display->mBinding.IsUrl()) {
// Get the XBL loader.
nsresult rv;
@ -2255,9 +2255,11 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
return nullptr;
}
const auto& url = display->mBinding.AsUrl();
RefPtr<nsXBLBinding> binding;
rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
display->mBinding->ExtraData()->Principal(),
rv = xblService->LoadBindings(aDocElement, url.GetURI(),
url.ExtraData().Principal(),
getter_AddRefs(binding));
if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
// Binding will load asynchronously.
@ -5316,8 +5318,9 @@ nsCSSFrameConstructor::LoadXBLBindingIfNeeded(nsIContent& aContent,
if (!(aFlags & ITEM_ALLOW_XBL_BASE)) {
return XBLBindingLoadInfo(nullptr);
}
css::URLValue* binding = aStyle.StyleDisplay()->mBinding;
if (!binding) {
const auto& binding = aStyle.StyleDisplay()->mBinding;
if (binding.IsNone()) {
return XBLBindingLoadInfo(nullptr);
}
@ -5327,11 +5330,10 @@ nsCSSFrameConstructor::LoadXBLBindingIfNeeded(nsIContent& aContent,
}
auto newPendingBinding = MakeUnique<PendingBinding>();
nsresult rv =
xblService->LoadBindings(aContent.AsElement(), binding->GetURI(),
binding->ExtraData()->Principal(),
getter_AddRefs(newPendingBinding->mBinding));
const auto& url = binding.AsUrl();
nsresult rv = xblService->LoadBindings(
aContent.AsElement(), url.GetURI(), url.ExtraData().Principal(),
getter_AddRefs(newPendingBinding->mBinding));
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_XBL_BLOCKED) {
return XBLBindingLoadInfo(nullptr);

View File

@ -1081,14 +1081,14 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(
}
case StyleFontFaceSourceListComponent::Tag::Url: {
face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
const URLValue* url = component.AsUrl();
const StyleCssUrl* url = component.AsUrl();
nsIURI* uri = url->GetURI();
face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
URLExtraData* extraData = url->ExtraData();
face->mReferrer = extraData->GetReferrer();
face->mReferrerPolicy = extraData->GetReferrerPolicy();
const URLExtraData& extraData = url->ExtraData();
face->mReferrer = extraData.GetReferrer();
face->mReferrerPolicy = extraData.GetReferrerPolicy();
face->mOriginPrincipal =
new gfxFontSrcPrincipal(extraData->Principal());
new gfxFontSrcPrincipal(extraData.Principal());
// agent and user stylesheets are treated slightly differently,
// the same-site origin check and access control headers are

View File

@ -45,7 +45,7 @@
#include "nsTransitionManager.h"
#include "nsWindowSizes.h"
#include "mozilla/CORSMode.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
@ -1141,18 +1141,17 @@ void Gecko_SetGradientImageValue(nsStyleImage* aImage,
}
static already_AddRefed<nsStyleImageRequest> CreateStyleImageRequest(
nsStyleImageRequest::Mode aModeFlags, URLValue* aImageValue) {
RefPtr<nsStyleImageRequest> req =
new nsStyleImageRequest(aModeFlags, aImageValue);
nsStyleImageRequest::Mode aModeFlags, const StyleComputedImageUrl* aUrl) {
RefPtr<nsStyleImageRequest> req = new nsStyleImageRequest(aModeFlags, *aUrl);
return req.forget();
}
void Gecko_SetLayerImageImageValue(nsStyleImage* aImage,
URLValue* aImageValue) {
MOZ_ASSERT(aImage && aImageValue);
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aImage && aUrl);
RefPtr<nsStyleImageRequest> req =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aUrl);
aImage->SetImageRequest(req.forget());
}
@ -1179,11 +1178,12 @@ void Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen) {
aStyleUI->mCursorImages.SetLength(aLen);
}
void Gecko_SetCursorImageValue(nsCursorImage* aCursor, URLValue* aImageValue) {
MOZ_ASSERT(aCursor && aImageValue);
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aCursor && aUrl);
aCursor->mImage =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aImageValue);
CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aUrl);
}
void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) {
@ -1191,11 +1191,11 @@ void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) {
}
void Gecko_SetContentDataImageValue(nsStyleContentData* aContent,
URLValue* aImageValue) {
MOZ_ASSERT(aContent && aImageValue);
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aContent && aUrl);
RefPtr<nsStyleImageRequest> req =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aUrl);
aContent->SetImageRequest(req.forget());
}
@ -1255,11 +1255,11 @@ void Gecko_SetListStyleImageNone(nsStyleList* aList) {
}
void Gecko_SetListStyleImageImageValue(nsStyleList* aList,
URLValue* aImageValue) {
MOZ_ASSERT(aList && aImageValue);
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aList && aUrl);
aList->mListStyleImage =
CreateStyleImageRequest(nsStyleImageRequest::Mode(0), aImageValue);
CreateStyleImageRequest(nsStyleImageRequest::Mode(0), aUrl);
}
void Gecko_CopyListStyleImageFrom(nsStyleList* aList,
@ -1560,8 +1560,9 @@ void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest) {
aDest->mFilters = aSrc->mFilters;
}
void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* aEffects, URLValue* aURL) {
aEffects->SetURL(aURL);
void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* aEffects,
const StyleComputedUrl* aURL) {
aEffects->SetURL(*aURL);
}
void Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* aDest,
@ -1570,8 +1571,8 @@ void Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* aDest,
}
void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* aPaint,
URLValue* aURL) {
aPaint->SetPaintServer(aURL);
const StyleComputedUrl* aURL) {
aPaint->SetPaintServer(*aURL);
}
void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* aPaint) { aPaint->SetNone(); }
@ -1585,30 +1586,18 @@ void Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* aDst, const nsStyleSVG* aSrc) {
aDst->mStrokeDasharray = aSrc->mStrokeDasharray;
}
URLValue* Gecko_URLValue_Create(StyleStrong<RawServoCssUrlData> aCssUrl,
CORSMode aCORSMode) {
RefPtr<URLValue> url = new URLValue(aCssUrl.Consume(), 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 URLValue* aURL, nsCString* aOut) {
void Gecko_GetComputedURLSpec(const StyleComputedUrl* aURL, nsCString* aOut) {
MOZ_ASSERT(aURL);
MOZ_ASSERT(aOut);
if (aURL->IsLocalRef()) {
aOut->Assign(aURL->GetString());
aOut->Assign(aURL->SpecifiedSerialization());
return;
}
Gecko_GetComputedImageURLSpec(aURL, aOut);
}
void Gecko_GetComputedImageURLSpec(const URLValue* aURL, nsCString* aOut) {
void Gecko_GetComputedImageURLSpec(const StyleComputedUrl* aURL,
nsCString* aOut) {
// Image URIs don't serialize local refs as local.
if (nsIURI* uri = aURL->GetURI()) {
nsresult rv = uri->GetSpec(*aOut);
@ -1627,6 +1616,11 @@ void Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut) {
}
}
// XXX Implemented by hand because even though it's thread-safe, only the
// subclasses have the HasThreadSafeRefCnt bits.
void Gecko_AddRefnsIURIArbitraryThread(nsIURI* aPtr) { NS_ADDREF(aPtr); }
void Gecko_ReleasensIURIArbitraryThread(nsIURI* aPtr) { NS_RELEASE(aPtr); }
template <typename ElementLike>
void DebugListAttributes(const ElementLike& aElement, nsCString& aOut) {
const uint32_t kMaxAttributeLength = 40;
@ -1665,8 +1659,6 @@ void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot,
DebugListAttributes(*aSnapshot, *aOut);
}
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLValue, CSSURLValue);
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
@ -1841,15 +1833,14 @@ void Gecko_StyleSheet_FinishAsyncParse(
static already_AddRefed<StyleSheet> LoadImportSheet(
Loader* aLoader, StyleSheet* aParent, SheetLoadData* aParentLoadData,
LoaderReusableStyleSheets* aReusableSheets, URLValue* aURL,
LoaderReusableStyleSheets* aReusableSheets, const StyleCssUrl& aURL,
already_AddRefed<RawServoMediaList> aMediaList) {
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(aURL, "Invalid URLs shouldn't be loaded!");
RefPtr<MediaList> media = new MediaList(std::move(aMediaList));
nsCOMPtr<nsIURI> uri = aURL->GetURI();
nsCOMPtr<nsIURI> uri = aURL.GetURI();
nsresult rv = uri ? NS_OK : NS_ERROR_FAILURE;
StyleSheet* previousFirstChild = aParent->GetFirstChild();
@ -1874,7 +1865,7 @@ static already_AddRefed<StyleSheet> LoadImportSheet(
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:invalid"));
}
emptySheet->SetURIs(uri, uri, uri);
emptySheet->SetPrincipal(aURL->ExtraData()->Principal());
emptySheet->SetPrincipal(aURL.ExtraData().Principal());
emptySheet->SetComplete();
aParent->PrependStyleSheet(emptySheet);
return emptySheet.forget();
@ -1887,31 +1878,27 @@ static already_AddRefed<StyleSheet> LoadImportSheet(
StyleSheet* Gecko_LoadStyleSheet(Loader* aLoader, StyleSheet* aParent,
SheetLoadData* aParentLoadData,
LoaderReusableStyleSheets* aReusableSheets,
StyleStrong<RawServoCssUrlData> aCssUrl,
const StyleCssUrl* aUrl,
StyleStrong<RawServoMediaList> aMediaList) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aUrl);
// The CORS mode in the URLValue is irrelevant here.
// (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
RefPtr<URLValue> url = new URLValue(aCssUrl.Consume(), CORS_NONE);
return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
url, aMediaList.Consume())
*aUrl, aMediaList.Consume())
.take();
}
void Gecko_LoadStyleSheetAsync(SheetLoadDataHolder* aParentData,
StyleStrong<RawServoCssUrlData> aCssUrl,
const StyleCssUrl* aUrl,
StyleStrong<RawServoMediaList> aMediaList,
StyleStrong<RawServoImportRule> aImportRule) {
MOZ_ASSERT(aUrl);
RefPtr<SheetLoadDataHolder> loadData = aParentData;
// The CORS mode in the URLValue is irrelevant here.
// (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
RefPtr<URLValue> urlVal = new URLValue(aCssUrl.Consume(), 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),
[data = std::move(loadData), url = StyleCssUrl(*aUrl),
media = std::move(mediaList), import = std::move(importRule)]() mutable {
MOZ_ASSERT(NS_IsMainThread());
SheetLoadData* d = data->get();
@ -2100,3 +2087,8 @@ bool Gecko_AssertClassAttrValueIsSane(const nsAttrValue* aValue) {
.IsEmpty());
return true;
}
void Gecko_LoadData_DeregisterLoad(const StyleLoadData* aData) {
MOZ_ASSERT(aData->load_id != 0);
ImageLoader::DeregisterCSSImageFromAllLoaders(*aData);
}

View File

@ -61,6 +61,8 @@ const bool GECKO_IS_NIGHTLY = false;
extern "C" {
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsIURI, nsIURI);
// Debugging stuff.
void Gecko_Element_DebugListAttributes(const mozilla::dom::Element*,
nsCString*);
@ -115,11 +117,11 @@ mozilla::StyleSheet* Gecko_LoadStyleSheet(
mozilla::css::Loader* loader, mozilla::StyleSheet* parent,
mozilla::css::SheetLoadData* parent_load_data,
mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
mozilla::StyleStrong<RawServoCssUrlData> url,
const mozilla::StyleCssUrl* url,
mozilla::StyleStrong<RawServoMediaList> media_list);
void Gecko_LoadStyleSheetAsync(mozilla::css::SheetLoadDataHolder* parent_data,
mozilla::StyleStrong<RawServoCssUrlData>,
const mozilla::StyleCssUrl* url,
mozilla::StyleStrong<RawServoMediaList>,
mozilla::StyleStrong<RawServoImportRule>);
@ -340,7 +342,7 @@ void Gecko_SetGradientImageValue(nsStyleImage* image,
nsStyleGradient* gradient);
void Gecko_SetLayerImageImageValue(nsStyleImage* image,
mozilla::css::URLValue* image_value);
const mozilla::StyleComputedImageUrl* url);
void Gecko_SetImageElement(nsStyleImage* image, nsAtom* atom);
void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
@ -357,8 +359,8 @@ 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::URLValue* aImageValue);
void Gecko_SetListStyleImageImageValue(
nsStyleList* style_struct, const mozilla::StyleComputedImageUrl* url);
void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
@ -366,12 +368,12 @@ void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
void Gecko_SetCursorArrayLength(nsStyleUI* ui, size_t len);
void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
mozilla::css::URLValue* aImageValue);
const mozilla::StyleComputedImageUrl* url);
void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
void Gecko_SetContentDataImageValue(nsStyleContentData* aList,
mozilla::css::URLValue* aImageValue);
const mozilla::StyleComputedImageUrl* url);
nsStyleContentData::CounterFunction* Gecko_SetCounterFunction(
nsStyleContentData* content_data, mozilla::StyleContentType);
@ -535,13 +537,13 @@ void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);
void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest);
void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* effects,
mozilla::css::URLValue* uri);
const mozilla::StyleComputedUrl* url);
void Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* dest,
const nsStyleSVGPaint* src);
void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint,
mozilla::css::URLValue* uri);
const mozilla::StyleComputedUrl* url);
void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* paint);
@ -554,20 +556,14 @@ void Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* svg, uint32_t len);
void Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* dst,
const nsStyleSVG* src);
mozilla::css::URLValue* Gecko_URLValue_Create(
mozilla::StyleStrong<RawServoCssUrlData> url, mozilla::CORSMode aCORSMode);
size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);
void Gecko_GetComputedURLSpec(const mozilla::css::URLValue* url,
void Gecko_GetComputedURLSpec(const mozilla::StyleComputedUrl* url,
nsCString* spec);
void Gecko_GetComputedImageURLSpec(const mozilla::css::URLValue* url,
void Gecko_GetComputedImageURLSpec(const mozilla::StyleComputedUrl* url,
nsCString* spec);
void Gecko_nsIURI_Debug(nsIURI*, nsCString* spec);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::URLValue, CSSURLValue);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::URLExtraData, URLExtraData);
void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len);
@ -579,6 +575,8 @@ float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,
float aFloatValue);
void Gecko_LoadData_DeregisterLoad(const mozilla::StyleLoadData*);
float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle);
void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*);
void Gecko_FontSlantStyle_SetItalic(mozilla::FontSlantStyle*);

View File

@ -205,23 +205,23 @@ void ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
"We should only add to one map iff we also add to the other map.");
}
imgRequestProxy* ImageLoader::RegisterCSSImage(URLValue* aImage) {
imgRequestProxy* ImageLoader::RegisterCSSImage(const StyleLoadData& aData) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aImage);
uint64_t loadId = aData.load_id;
if (aImage->LoadID() == 0) {
if (loadId == 0) {
MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
return nullptr;
}
if (imgRequestProxy* request = mRegisteredImages.GetWeak(aImage->LoadID())) {
if (imgRequestProxy* request = mRegisteredImages.GetWeak(loadId)) {
// This document already has a request.
return request;
}
imgRequestProxy* canonicalRequest = nullptr;
{
auto entry = sImages->Lookup(aImage->LoadID());
auto entry = sImages->Lookup(loadId);
if (entry) {
canonicalRequest = entry.Data()->mCanonicalRequest;
}
@ -242,19 +242,16 @@ imgRequestProxy* ImageLoader::RegisterCSSImage(URLValue* aImage) {
canonicalRequest->SyncClone(this, mDocument, getter_AddRefs(request));
mInClone = false;
MOZ_ASSERT(!mRegisteredImages.Contains(aImage->LoadID()));
MOZ_ASSERT(!mRegisteredImages.Contains(loadId));
imgRequestProxy* requestWeak = request;
mRegisteredImages.Put(aImage->LoadID(), request.forget());
mRegisteredImages.Put(loadId, request.forget());
return requestWeak;
}
/* static */
void ImageLoader::DeregisterCSSImageFromAllLoaders(URLValue* aImage) {
MOZ_ASSERT(aImage);
uint64_t loadID = aImage->LoadID();
void ImageLoader::DeregisterCSSImageFromAllLoaders(const StyleLoadData& aData) {
uint64_t loadID = aData.load_id;
if (loadID == 0) {
MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
return;
@ -426,13 +423,11 @@ void ImageLoader::ClearFrames(nsPresContext* aPresContext) {
}
/* static */
void ImageLoader::LoadImage(URLValue* aImage, Document* aLoadingDoc) {
void ImageLoader::LoadImage(const StyleComputedImageUrl& aImage,
Document& aLoadingDoc) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aLoadingDoc);
MOZ_ASSERT(aImage);
MOZ_ASSERT(aImage->LoadID() != 0);
if (aImage->LoadID() == 0) {
uint64_t loadId = aImage.LoadData().load_id;
if (loadId == 0) {
MOZ_ASSERT_UNREACHABLE("Image should have a valid LoadID");
return;
}
@ -440,29 +435,29 @@ void ImageLoader::LoadImage(URLValue* aImage, Document* aLoadingDoc) {
ImageTableEntry* entry;
{
auto lookup = sImages->LookupForAdd(aImage->LoadID());
auto lookup = sImages->LookupForAdd(loadId);
if (lookup) {
// This css::URLValue has already been loaded.
// This url has already been loaded.
return;
}
entry = lookup.OrInsert([]() { return new ImageTableEntry(); });
}
nsIURI* uri = aImage->GetURI();
nsIURI* uri = aImage.GetURI();
if (!uri) {
return;
}
int32_t loadFlags =
nsIRequest::LOAD_NORMAL |
nsContentUtils::CORSModeToLoadImageFlags(aImage->CorsMode());
nsContentUtils::CORSModeToLoadImageFlags(aImage.CorsMode());
URLExtraData* data = aImage->ExtraData();
const URLExtraData& data = aImage.ExtraData();
RefPtr<imgRequestProxy> request;
nsresult rv = nsContentUtils::LoadImage(
uri, aLoadingDoc, aLoadingDoc, data->Principal(), 0, data->GetReferrer(),
data->GetReferrerPolicy(), nullptr, loadFlags, NS_LITERAL_STRING("css"),
uri, &aLoadingDoc, &aLoadingDoc, data.Principal(), 0, data.GetReferrer(),
data.GetReferrerPolicy(), nullptr, loadFlags, NS_LITERAL_STRING("css"),
getter_AddRefs(request));
if (NS_FAILED(rv) || !request) {

View File

@ -34,8 +34,6 @@ class Document;
namespace css {
struct URLValue;
/**
* NOTE: All methods must be called from the main thread unless otherwise
* specified.
@ -63,7 +61,7 @@ class ImageLoader final : public imgINotificationObserver {
void DropDocumentReference();
imgRequestProxy* RegisterCSSImage(URLValue* aImage);
imgRequestProxy* RegisterCSSImage(const StyleLoadData& aImage);
void AssociateRequestToFrame(imgIRequest* aRequest, nsIFrame* aFrame,
FrameFlags aFlags);
@ -79,13 +77,13 @@ class ImageLoader final : public imgINotificationObserver {
// presshell pointer on the document has been cleared.
void ClearFrames(nsPresContext* aPresContext);
static void LoadImage(URLValue* aImage, dom::Document* aLoadingDoc);
static void LoadImage(const StyleComputedImageUrl& aImage, dom::Document&);
// Cancels the image load for the given css::URLValue and deregisters
// it from any ImageLoaders it was registered with.
// Cancels the image load for the given LoadData and deregisters it from any
// ImageLoaders it was registered with.
//
// May be called from any thread.
static void DeregisterCSSImageFromAllLoaders(URLValue* aImage);
static void DeregisterCSSImageFromAllLoaders(const StyleLoadData&);
void FlushUseCounters();
@ -171,38 +169,37 @@ class ImageLoader final : public imgINotificationObserver {
// A weak pointer to our document. Nulled out by DropDocumentReference.
dom::Document* mDocument;
// A map of css::URLValues, keyed by their LoadID(), to the imgRequestProxy
// A map of css ComputedUrls, 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::URLValues might be destroyed from other
// threads, and we don't want to leave dangling pointers around.
// on the main thread, but Urls 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::URLValue object that has had a load
// started.
// Data associated with every started load.
struct ImageTableEntry {
// Set of all ImageLoaders that have registered this css::URLValue.
// Set of all ImageLoaders that have registered this URL.
nsTHashtable<nsPtrHashKey<ImageLoader>> mImageLoaders;
// The "canonical" image request for this css::URLValue.
// The "canonical" image request for this URL.
//
// 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.
// This request is held on to as long as the specified URL 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::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.
// A table of all loads, keyed by their id 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::URLValues might be destroyed from other threads,
// We use the load id as the key since we can only access sImages on the
// main thread, but LoadData objects might be destroyed from other threads,
// and we don't want to leave dangling pointers around.
static nsClassHashtable<nsUint64HashKey, ImageTableEntry>* sImages;
};

View File

@ -500,6 +500,13 @@ cbindgen-types = [
{ gecko = "StyleGenericTranslate", servo = "values::generics::transform::Translate" },
{ gecko = "StyleAngle", servo = "values::computed::Angle" },
{ gecko = "StyleGenericBorderImageSideWidth", servo = "values::generics::border::BorderImageSideWidth" },
{ gecko = "StyleGenericUrlOrNone", servo = "values::generics::url::UrlOrNone" },
{ gecko = "StyleCssUrl", servo = "gecko::url::CssUrl" },
{ gecko = "StyleSpecifiedUrl", servo = "gecko::url::SpecifiedUrl" },
{ gecko = "StyleSpecifiedImageUrl", servo = "gecko::url::SpecifiedImageUrl" },
{ gecko = "StyleComputedUrl", servo = "gecko::url::ComputedUrl" },
{ gecko = "StyleComputedImageUrl", servo = "gecko::url::ComputedImageUrl" },
{ gecko = "StyleLoadData", servo = "gecko::url::LoadData" },
]
mapped-generic-types = [

View File

@ -22,11 +22,13 @@
# include "mozilla/Span.h"
# include "Units.h"
# include "mozilla/gfx/Types.h"
# include "mozilla/CORSMode.h"
# include "mozilla/MemoryReporting.h"
# include "mozilla/ServoTypes.h"
# include "mozilla/ServoBindingTypes.h"
# include "nsCSSPropertyID.h"
# include "nsCompatibility.h"
# include "nsIURI.h"
# include <atomic>
struct RawServoAnimationValueTable;
@ -35,9 +37,11 @@ struct RawServoAnimationValueMap;
class nsAtom;
class nsIFrame;
class nsINode;
class nsIContent;
class nsCSSPropertyIDSet;
class nsPresContext;
class nsSimpleContentList;
class imgRequestProxy;
struct nsCSSValueSharedList;
struct nsTimingFunction;
@ -97,7 +101,6 @@ class Loader;
class LoaderReusableStyleSheets;
class SheetLoadData;
using SheetLoadDataHolder = nsMainThreadPtrHolder<SheetLoadData>;
struct URLValue;
enum SheetParsingMode : uint8_t;
} // namespace css
@ -115,7 +118,6 @@ class Document;
using StyleLoader = css::Loader;
using StyleLoaderReusableStyleSheets = css::LoaderReusableStyleSheets;
using StyleCallerType = dom::CallerType;
using StyleURLValue = css::URLValue;
using StyleSheetParsingMode = css::SheetParsingMode;
using StyleSheetLoadData = css::SheetLoadData;
using StyleSheetLoadDataHolder = css::SheetLoadDataHolder;

View File

@ -10,7 +10,10 @@
#define mozilla_ServoStyleConstsInlines_h
#include "mozilla/ServoStyleConsts.h"
#include "mozilla/URLExtraData.h"
#include "nsGkAtoms.h"
#include "MainThreadUtils.h"
#include "nsNetUtil.h"
#include <type_traits>
#include <new>
@ -65,6 +68,30 @@ static constexpr const size_t kStaticRefcount =
std::numeric_limits<size_t>::max();
static constexpr const size_t kMaxRefcount =
std::numeric_limits<intptr_t>::max();
template <typename T>
inline void StyleArcInner<T>::IncrementRef() {
if (count.load(std::memory_order_relaxed) != kStaticRefcount) {
auto old_size = count.fetch_add(1, std::memory_order_relaxed);
if (MOZ_UNLIKELY(old_size > kMaxRefcount)) {
::abort();
}
}
}
// This is a C++ port-ish of Arc::drop().
template <typename T>
inline bool StyleArcInner<T>::DecrementRef() {
if (count.load(std::memory_order_relaxed) == kStaticRefcount) {
return false;
}
if (count.fetch_sub(1, std::memory_order_release) != 1) {
return false;
}
count.load(std::memory_order_acquire);
return true;
}
static constexpr const uint64_t kArcSliceCanary = 0xf3f3f3f3f3f3f3f3;
#define ASSERT_CANARY \
@ -73,18 +100,14 @@ static constexpr const uint64_t kArcSliceCanary = 0xf3f3f3f3f3f3f3f3;
template <typename T>
inline StyleArcSlice<T>::StyleArcSlice() {
_0.ptr = reinterpret_cast<decltype(_0.ptr)>(Servo_StyleArcSlice_EmptyPtr());
ASSERT_CANARY
}
template <typename T>
inline StyleArcSlice<T>::StyleArcSlice(const StyleArcSlice& aOther) {
MOZ_DIAGNOSTIC_ASSERT(aOther._0.ptr);
_0.ptr = aOther._0.ptr;
if (_0.ptr->count.load(std::memory_order_relaxed) != kStaticRefcount) {
auto old_size = _0.ptr->count.fetch_add(1, std::memory_order_relaxed);
if (MOZ_UNLIKELY(old_size > kMaxRefcount)) {
::abort();
}
}
_0.ptr->IncrementRef();
ASSERT_CANARY
}
@ -125,17 +148,12 @@ inline bool StyleArcSlice<T>::operator!=(const StyleArcSlice& aOther) const {
return !(*this == aOther);
}
// This is a C++ port-ish of Arc::drop().
template <typename T>
inline StyleArcSlice<T>::~StyleArcSlice() {
ASSERT_CANARY
if (_0.ptr->count.load(std::memory_order_relaxed) == kStaticRefcount) {
if (MOZ_LIKELY(!_0.ptr->DecrementRef())) {
return;
}
if (_0.ptr->count.fetch_sub(1, std::memory_order_release) != 1) {
return;
}
_0.ptr->count.load(std::memory_order_acquire);
for (T& elem : MakeSpan(_0.ptr->data.slice, Length())) {
elem.~T();
}
@ -144,11 +162,46 @@ inline StyleArcSlice<T>::~StyleArcSlice() {
#undef ASSERT_CANARY
template <typename T>
inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) {
p->IncrementRef();
}
template <typename T>
inline void StyleArc<T>::Release() {
if (MOZ_LIKELY(!p->DecrementRef())) {
return;
}
p->data.~T();
free(p);
}
template <typename T>
inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) {
if (p != aOther.p) {
Release();
p = aOther.p;
p->IncrementRef();
}
return *this;
}
template <typename T>
inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) {
std::swap(p, aOther.p);
return *this;
}
template <typename T>
inline StyleArc<T>::~StyleArc() {
Release();
}
inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); }
inline nsAtom* StyleAtom::AsAtom() const {
if (IsStatic()) {
return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[(_0 & ~1) >> 1]);
return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[_0 >> 1]);
}
return reinterpret_cast<nsAtom*>(_0);
}
@ -191,6 +244,85 @@ inline double StyleAngle::ToRadians() const {
return double(ToDegrees()) * M_PI / 180.0;
}
inline bool StyleUrlExtraData::IsShared() const { return !!(_0 & 1); }
inline StyleUrlExtraData::~StyleUrlExtraData() {
if (!IsShared()) {
reinterpret_cast<URLExtraData*>(_0)->Release();
}
}
inline const URLExtraData& StyleUrlExtraData::get() const {
if (IsShared()) {
return *URLExtraData::sShared[_0 >> 1].get();
}
return *reinterpret_cast<const URLExtraData*>(_0);
}
inline nsDependentCSubstring StyleCssUrl::SpecifiedSerialization() const {
return _0->serialization.AsString();
}
inline const URLExtraData& StyleCssUrl::ExtraData() const {
return _0->extra_data.get();
}
inline StyleLoadData& StyleCssUrl::LoadData() const {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (MOZ_LIKELY(_0->load_data.tag == StyleLoadDataSource::Tag::Owned)) {
return const_cast<StyleLoadData&>(_0->load_data.owned._0);
}
return const_cast<StyleLoadData&>(*Servo_LoadData_GetLazy(&_0->load_data));
}
inline nsIURI* StyleCssUrl::GetURI() const {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
auto& loadData = LoadData();
if (!loadData.tried_to_resolve) {
loadData.tried_to_resolve = true;
NS_NewURI(getter_AddRefs(loadData.resolved), SpecifiedSerialization(),
nullptr, ExtraData().BaseURI());
}
return loadData.resolved.get();
}
inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const {
return _0.SpecifiedSerialization();
}
inline const URLExtraData& StyleComputedUrl::ExtraData() const {
return _0.ExtraData();
}
inline StyleLoadData& StyleComputedUrl::LoadData() const {
return _0.LoadData();
}
inline CORSMode StyleComputedUrl::CorsMode() const {
switch (_0._0->cors_mode) {
case StyleCorsMode::Anonymous:
return CORSMode::CORS_ANONYMOUS;
case StyleCorsMode::None:
return CORSMode::CORS_NONE;
default:
MOZ_ASSERT_UNREACHABLE("Unknown cors-mode from style?");
return CORSMode::CORS_NONE;
}
}
inline nsIURI* StyleComputedUrl::GetURI() const { return _0.GetURI(); }
inline bool StyleComputedUrl::IsLocalRef() const {
return Servo_CssUrl_IsLocalRef(&_0);
}
inline bool StyleComputedUrl::HasRef() const {
if (IsLocalRef()) {
return true;
}
if (nsIURI* uri = GetURI()) {
bool hasRef = false;
return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef;
}
return false;
}
} // namespace mozilla
#endif

View File

@ -163,166 +163,6 @@ void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit) {
}
}
css::URLValue::~URLValue() {
if (mLoadID != 0) {
ImageLoader::DeregisterCSSImageFromAllLoaders(this);
}
}
bool css::URLValue::Equals(const URLValue& aOther) const {
MOZ_ASSERT(NS_IsMainThread());
bool eq;
const URLExtraData* self = ExtraData();
const URLExtraData* other = aOther.ExtraData();
return GetString() == aOther.GetString() &&
(GetURI() == aOther.GetURI() || // handles null == null
(mURI && aOther.mURI &&
NS_SUCCEEDED(mURI->Equals(aOther.mURI, &eq)) && eq)) &&
(self->BaseURI() == other->BaseURI() ||
(NS_SUCCEEDED(self->BaseURI()->Equals(other->BaseURI(), &eq)) &&
eq)) &&
self->Principal()->Equals(other->Principal()) &&
IsLocalRef() == aOther.IsLocalRef();
}
bool css::URLValue::DefinitelyEqualURIs(const URLValue& aOther) const {
if (ExtraData()->BaseURI() != aOther.ExtraData()->BaseURI()) {
return false;
}
return GetString() == aOther.GetString();
}
bool css::URLValue::DefinitelyEqualURIsAndPrincipal(
const URLValue& aOther) const {
return ExtraData()->Principal() == aOther.ExtraData()->Principal() &&
DefinitelyEqualURIs(aOther);
}
nsDependentCSubstring css::URLValue::GetString() const {
const uint8_t* chars;
uint32_t len;
Servo_CssUrlData_GetSerialization(mCssUrl, &chars, &len);
return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
}
nsIURI* css::URLValue::GetURI() const {
MOZ_ASSERT(NS_IsMainThread());
if (!mURIResolved) {
MOZ_ASSERT(!mURI);
nsCOMPtr<nsIURI> newURI;
NS_NewURI(getter_AddRefs(newURI), GetString(), nullptr,
ExtraData()->BaseURI());
mURI = newURI.forget();
mURIResolved = true;
}
return mURI;
}
bool 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::URLValue::ResolveLocalRef(nsIURI* aURI) const {
nsCOMPtr<nsIURI> result = GetURI();
if (result && IsLocalRef()) {
nsCString ref;
mURI->GetRef(ref);
nsresult rv = NS_MutateURI(aURI).SetRef(ref).Finalize(result);
if (NS_FAILED(rv)) {
// If setting the ref failed, just return the original URI.
result = aURI;
}
}
return result.forget();
}
already_AddRefed<nsIURI> css::URLValue::ResolveLocalRef(
nsIContent* aContent) const {
nsCOMPtr<nsIURI> url = aContent->GetBaseURI();
return ResolveLocalRef(url);
}
void 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 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);
}
size_t css::URLValue::SizeOfIncludingThis(
mozilla::MallocSizeOf aMallocSizeOf) const {
// Measurement of the following members may be added later if DMD finds it
// is worthwhile:
// - mURI
// - mString
// Only measure it if it's unshared, to avoid double-counting.
size_t n = 0;
if (mRefCnt <= 1) {
n += aMallocSizeOf(this);
}
return n;
}
imgRequestProxy* css::URLValue::LoadImage(Document* aDocument) {
MOZ_ASSERT(NS_IsMainThread());
static uint64_t sNextLoadID = 1;
if (mLoadID == 0) {
mLoadID = sNextLoadID++;
}
// 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.
Document* loadingDoc = aDocument->GetOriginalDocument();
if (!loadingDoc) {
loadingDoc = aDocument;
}
// Kick off the load in the loading document.
ImageLoader::LoadImage(this, loadingDoc);
// Register the image in the document that's using it.
return aDocument->StyleImageLoader()->RegisterCSSImage(this);
}
size_t mozilla::css::GridTemplateAreasValue::SizeOfIncludingThis(
mozilla::MallocSizeOf aMallocSizeOf) const {
// Only measure it if it's unshared, to avoid double-counting.

View File

@ -98,93 +98,6 @@ bool Servo_CssUrlData_IsLocalRef(const RawServoCssUrlData* url);
namespace mozilla {
namespace css {
struct URLValue final {
public:
// aCssUrl must not be null.
URLValue(already_AddRefed<RawServoCssUrlData> aCssUrl, CORSMode aCORSMode)
: mURIResolved(false), mCssUrl(aCssUrl), mCORSMode(aCORSMode) {
MOZ_ASSERT(mCssUrl);
}
// Returns true iff all fields of the two URLValue objects are equal.
//
// Only safe to call on the main thread, since this will call Equals on the
// nsIURI and nsIPrincipal objects stored on the URLValue objects.
bool Equals(const URLValue& aOther) const;
// Returns true iff we know for sure, by comparing the mBaseURI pointer,
// the specified url() value mString, and IsLocalRef(), that these
// 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 URLValue& aOther) const;
// Smae as DefinitelyEqualURIs but additionally compares the nsIPrincipal
// pointers of the two URLValue objects.
bool DefinitelyEqualURIsAndPrincipal(const URLValue& aOther) const;
nsIURI* GetURI() const;
bool IsLocalRef() const { return Servo_CssUrlData_IsLocalRef(mCssUrl); }
bool HasRef() const;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValue)
// When matching a local ref URL, resolve it against aURI;
// Otherwise, ignore aURL and return mURI 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 IsLocalRef()
// and serializing just the fragment if true.
void GetSourceString(nsString& aRef) const;
nsDependentCSubstring GetString() const;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
imgRequestProxy* LoadImage(mozilla::dom::Document* aDocument);
uint64_t LoadID() const { return mLoadID; }
CORSMode CorsMode() const { return mCORSMode; }
URLExtraData* ExtraData() const {
return Servo_CssUrlData_GetExtraData(mCssUrl);
}
private:
// mURI stores the lazily resolved URI. This may be null if the URI is
// invalid, even once resolved.
mutable nsCOMPtr<nsIURI> mURI;
mutable bool mURIResolved;
RefPtr<RawServoCssUrlData> mCssUrl;
const CORSMode mCORSMode;
// A unique, non-reused ID value for this URLValue over the life of the
// process. This value is only valid after LoadImage has been called.
//
// We use this as a key in some tables in ImageLoader. This is better than
// using the pointer value of the ImageValue object, since we can sometimes
// 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;
~URLValue();
private:
URLValue(const URLValue& aOther) = delete;
URLValue& operator=(const URLValue& aOther) = delete;
};
struct GridNamedArea {
nsString mName;
uint32_t mColumnStart;

View File

@ -619,7 +619,8 @@ static void AddImageURL(nsIURI& aURI, nsTArray<nsString>& aURLs) {
aURLs.AppendElement(NS_ConvertUTF8toUTF16(spec));
}
static void AddImageURL(const css::URLValue& aURL, nsTArray<nsString>& aURLs) {
static void AddImageURL(const StyleComputedUrl& aURL,
nsTArray<nsString>& aURLs) {
if (aURL.IsLocalRef()) {
return;
}
@ -631,9 +632,7 @@ static void AddImageURL(const css::URLValue& aURL, nsTArray<nsString>& aURLs) {
static void AddImageURL(const nsStyleImageRequest& aRequest,
nsTArray<nsString>& aURLs) {
if (auto* value = aRequest.GetImageValue()) {
AddImageURL(*value, aURLs);
}
AddImageURL(aRequest.GetImageValue(), aURLs);
}
static void AddImageURL(const nsStyleImage& aImage, nsTArray<nsString>& aURLs) {
@ -660,9 +659,8 @@ static void AddImageURLs(const nsStyleImageLayers& aLayers,
}
}
// FIXME(stylo-everywhere): This should be `const ComputedStyle&`.
static void CollectImageURLsForProperty(nsCSSPropertyID aProp,
ComputedStyle& aStyle,
const ComputedStyle& aStyle,
nsTArray<nsString>& aURLs) {
if (nsCSSProps::IsShorthand(aProp)) {
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProp,
@ -1221,7 +1219,7 @@ void nsComputedDOMStyle::SetValueToPosition(const Position& aPosition,
aValueList->AppendCSSValue(valY.forget());
}
void nsComputedDOMStyle::SetValueToURLValue(const css::URLValue* aURL,
void nsComputedDOMStyle::SetValueToURLValue(const StyleComputedUrl* aURL,
nsROCSSPrimitiveValue* aValue) {
if (!aURL) {
aValue->SetIdent(eCSSKeyword_none);
@ -1238,9 +1236,7 @@ void nsComputedDOMStyle::SetValueToURLValue(const css::URLValue* aURL,
}
// Otherwise, serialize the specified URL value.
nsAutoString source;
aURL->GetSourceString(source);
NS_ConvertUTF8toUTF16 source(aURL->SpecifiedSerialization());
nsAutoString url;
url.AppendLiteral(u"url(");
nsStyleUtil::AppendEscapedCSSString(source, url, '"');

View File

@ -291,7 +291,7 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
const mozilla::StyleColor& aColor);
void SetValueToPosition(const mozilla::Position& aPosition,
nsDOMCSSValueList* aValueList);
void SetValueToURLValue(const mozilla::css::URLValue* aURL,
void SetValueToURLValue(const mozilla::StyleComputedUrl* aURL,
nsROCSSPrimitiveValue* aValue);
void SetValueToSize(nsROCSSPrimitiveValue* aValue, const mozilla::StyleSize&);

View File

@ -20,6 +20,7 @@
#include "nsCSSProps.h"
#include "nsDeviceContext.h"
#include "nsStyleUtil.h"
#include "nsIURIMutator.h"
#include "nsCOMPtr.h"
@ -60,18 +61,6 @@ static constexpr size_t kStyleStructSizeLimit = 504;
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
static bool DefinitelyEqualURIs(const css::URLValue* aURI1,
const css::URLValue* aURI2) {
return aURI1 == aURI2 ||
(aURI1 && aURI2 && aURI1->DefinitelyEqualURIs(*aURI2));
}
static bool DefinitelyEqualURIsAndPrincipal(const css::URLValue* aURI1,
const css::URLValue* aURI2) {
return aURI1 == aURI2 ||
(aURI1 && aURI2 && aURI1->DefinitelyEqualURIsAndPrincipal(*aURI2));
}
static bool DefinitelyEqualImages(const nsStyleImageRequest* aRequest1,
const nsStyleImageRequest* aRequest2) {
if (aRequest1 == aRequest2) {
@ -85,6 +74,73 @@ static bool DefinitelyEqualImages(const nsStyleImageRequest* aRequest1,
return aRequest1->DefinitelyEquals(*aRequest2);
}
bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
// This very intentionally avoids comparing LoadData and such.
const auto& extra = extra_data.get();
const auto& otherExtra = aOther.extra_data.get();
if (extra.BaseURI() != otherExtra.BaseURI() ||
extra.Principal() != otherExtra.Principal() ||
cors_mode != aOther.cors_mode) {
// NOTE(emilio): This does pointer comparison, but it's what URLValue used
// to do. That's ok though since this is only used for style struct diffing.
return false;
}
return serialization == aOther.serialization;
}
StyleLoadData::~StyleLoadData() {
if (load_id != 0) {
css::ImageLoader::DeregisterCSSImageFromAllLoaders(*this);
}
}
already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(nsIURI* aURI) const {
nsCOMPtr<nsIURI> result = GetURI();
if (result && IsLocalRef()) {
nsCString ref;
result->GetRef(ref);
nsresult rv = NS_MutateURI(aURI).SetRef(ref).Finalize(result);
if (NS_FAILED(rv)) {
// If setting the ref failed, just return the original URI.
result = aURI;
}
}
return result.forget();
}
already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(
const nsIContent* aContent) const {
nsCOMPtr<nsIURI> url = aContent->GetBaseURI();
return ResolveLocalRef(url);
}
imgRequestProxy* StyleComputedUrl::LoadImage(Document& aDocument) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
static uint64_t sNextLoadID = 1;
StyleLoadData& data = LoadData();
if (data.load_id == 0) {
data.load_id = sNextLoadID++;
}
// 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.
Document* loadingDoc = aDocument.GetOriginalDocument();
if (!loadingDoc) {
loadingDoc = &aDocument;
}
// Kick off the load in the loading document.
css::ImageLoader::LoadImage(*this, *loadingDoc);
// Register the image in the document that's using it.
return aDocument.StyleImageLoader()->RegisterCSSImage(data);
}
// --------------------
// nsStyleFont
//
@ -672,6 +728,9 @@ nsChangeHint nsStyleColumn::CalcDifference(
nsStyleSVG::nsStyleSVG(const Document& aDocument)
: mFill(eStyleSVGPaintType_Color), // Will be initialized to NS_RGB(0,0,0)
mStroke(eStyleSVGPaintType_None),
mMarkerEnd(StyleUrlOrNone::None()),
mMarkerMid(StyleUrlOrNone::None()),
mMarkerStart(StyleUrlOrNone::None()),
mMozContextProperties{{}, {0}},
mStrokeDashoffset(LengthPercentage::Zero()),
mStrokeWidth(LengthPercentage::FromPixels(1.0f)),
@ -728,16 +787,14 @@ static bool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
aPaint2.Type() == eStyleSVGPaintType_Server;
}
return aPaint1.Type() == eStyleSVGPaintType_Server &&
!DefinitelyEqualURIs(aPaint1.GetPaintServer(),
aPaint2.GetPaintServer());
aPaint1.GetPaintServer() != aPaint2.GetPaintServer();
}
nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const {
nsChangeHint hint = nsChangeHint(0);
if (!DefinitelyEqualURIs(mMarkerEnd, aNewData.mMarkerEnd) ||
!DefinitelyEqualURIs(mMarkerMid, aNewData.mMarkerMid) ||
!DefinitelyEqualURIs(mMarkerStart, aNewData.mMarkerStart)) {
if (mMarkerEnd != aNewData.mMarkerEnd || mMarkerMid != aNewData.mMarkerMid ||
mMarkerStart != aNewData.mMarkerStart) {
// Markers currently contribute to SVGGeometryFrame::mRect,
// so we need a reflow as well as a repaint. No intrinsic sizes need
// to change, so nsChangeHint_NeedReflow is sufficient.
@ -956,12 +1013,12 @@ void StyleShapeSource::DoDestroy() {
// --------------------
// nsStyleFilter
//
nsStyleFilter::nsStyleFilter() : mType(NS_STYLE_FILTER_NONE), mURL(nullptr) {
nsStyleFilter::nsStyleFilter() : mType(NS_STYLE_FILTER_NONE) {
MOZ_COUNT_CTOR(nsStyleFilter);
}
nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
: mType(NS_STYLE_FILTER_NONE), mURL(nullptr) {
: mType(NS_STYLE_FILTER_NONE) {
MOZ_COUNT_CTOR(nsStyleFilter);
if (aSource.mType == NS_STYLE_FILTER_URL) {
SetURL(aSource.mURL);
@ -1002,7 +1059,7 @@ bool nsStyleFilter::operator==(const nsStyleFilter& aOther) const {
}
if (mType == NS_STYLE_FILTER_URL) {
return DefinitelyEqualURIs(mURL, aOther.mURL);
return mURL == aOther.mURL;
} else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
return mDropShadow == aOther.mDropShadow;
} else if (mType != NS_STYLE_FILTER_NONE) {
@ -1016,10 +1073,8 @@ void nsStyleFilter::ReleaseRef() {
if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
mDropShadow.~StyleSimpleShadow();
} else if (mType == NS_STYLE_FILTER_URL) {
NS_ASSERTION(mURL, "expected pointer");
mURL->Release();
mURL.~StyleComputedUrl();
}
mURL = nullptr;
}
void nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
@ -1029,10 +1084,9 @@ void nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
mType = aType;
}
bool nsStyleFilter::SetURL(css::URLValue* aURL) {
bool nsStyleFilter::SetURL(const StyleComputedUrl& aUrl) {
ReleaseRef();
mURL = aURL;
mURL->AddRef();
new (&mURL) StyleComputedUrl(aUrl);
mType = NS_STYLE_FILTER_URL;
return true;
}
@ -1202,8 +1256,7 @@ void nsStyleSVGPaint::Reset() {
mPaint.mColor = StyleColor::Black();
break;
case eStyleSVGPaintType_Server:
mPaint.mPaintServer->Release();
mPaint.mPaintServer = nullptr;
mPaint.mPaintServer.~StyleComputedUrl();
MOZ_FALLTHROUGH;
case eStyleSVGPaintType_ContextFill:
case eStyleSVGPaintType_ContextStroke:
@ -1266,14 +1319,12 @@ void nsStyleSVGPaint::SetColor(StyleColor aColor) {
mPaint.mColor = aColor;
}
void nsStyleSVGPaint::SetPaintServer(css::URLValue* aPaintServer,
void nsStyleSVGPaint::SetPaintServer(const StyleComputedUrl& aPaintServer,
nsStyleSVGFallbackType aFallbackType,
StyleColor aFallbackColor) {
MOZ_ASSERT(aPaintServer);
Reset();
mType = eStyleSVGPaintType_Server;
mPaint.mPaintServer = aPaintServer;
mPaint.mPaintServer->AddRef();
new (&mPaint.mPaintServer) StyleComputedUrl(aPaintServer);
mFallbackType = aFallbackType;
mFallbackColor = aFallbackColor;
}
@ -1286,8 +1337,7 @@ bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const {
case eStyleSVGPaintType_Color:
return mPaint.mColor == aOther.mPaint.mColor;
case eStyleSVGPaintType_Server:
return DefinitelyEqualURIs(mPaint.mPaintServer,
aOther.mPaint.mPaintServer) &&
return mPaint.mPaintServer == aOther.mPaint.mPaintServer &&
mFallbackType == aOther.mFallbackType &&
mFallbackColor == aOther.mFallbackColor;
case eStyleSVGPaintType_ContextFill:
@ -1808,8 +1858,8 @@ class StyleImageRequestCleanupTask : public mozilla::Runnable {
};
nsStyleImageRequest::nsStyleImageRequest(Mode aModeFlags,
css::URLValue* aImageValue)
: mImageValue(aImageValue), mModeFlags(aModeFlags), mResolved(false) {}
const StyleComputedImageUrl& aImageURL)
: mImageURL(aImageURL), mModeFlags(aModeFlags), mResolved(false) {}
nsStyleImageRequest::~nsStyleImageRequest() {
// We may or may not be being destroyed on the main thread. To clean
@ -1843,7 +1893,7 @@ bool nsStyleImageRequest::Resolve(Document& aDocument,
mResolved = true;
nsIURI* docURI = aDocument.GetDocumentURI();
if (GetImageValue()->HasRef()) {
if (GetImageValue().HasRef()) {
bool isEqualExceptRef = false;
RefPtr<nsIURI> imageURI = GetImageURI();
if (!imageURI) {
@ -1870,11 +1920,12 @@ bool nsStyleImageRequest::Resolve(Document& aDocument,
MOZ_ASSERT(mModeFlags == aOldImageRequest->mModeFlags);
mDocGroup = aOldImageRequest->mDocGroup;
mImageValue = aOldImageRequest->mImageValue;
mImageURL = aOldImageRequest->mImageURL;
mRequestProxy = aOldImageRequest->mRequestProxy;
} else {
mDocGroup = aDocument.GetDocGroup();
imgRequestProxy* request = mImageValue->LoadImage(&aDocument);
imgRequestProxy* request = mImageURL.LoadImage(aDocument);
bool isPrint = !!aDocument.GetOriginalDocument();
if (!isPrint) {
mRequestProxy = request;
@ -1916,7 +1967,7 @@ void nsStyleImageRequest::MaybeTrackAndLock() {
bool nsStyleImageRequest::DefinitelyEquals(
const nsStyleImageRequest& aOther) const {
return DefinitelyEqualURIs(mImageValue, aOther.mImageValue);
return mImageURL == aOther.mImageURL;
}
// --------------------
@ -2105,12 +2156,8 @@ already_AddRefed<nsIURI> nsStyleImageRequest::GetImageURI() const {
}
// If we had some problem resolving the mRequestProxy, use the URL stored
// in the mImageValue.
if (!mImageValue) {
return nullptr;
}
uri = mImageValue->GetURI();
// in the mImageURL.
uri = mImageURL.GetURI();
return uri.forget();
}
@ -2309,8 +2356,8 @@ already_AddRefed<nsIURI> nsStyleImage::GetImageURI() const {
return uri.forget();
}
const css::URLValue* nsStyleImage::GetURLValue() const {
return mType == eStyleImageType_Image ? mImage->GetImageValue() : nullptr;
const StyleComputedImageUrl* nsStyleImage::GetURLValue() const {
return mType == eStyleImageType_Image ? &mImage->GetImageValue() : nullptr;
}
// --------------------
@ -2573,8 +2620,6 @@ bool nsStyleImageLayers::operator==(const nsStyleImageLayers& aOther) const {
for (uint32_t i = 0; i < mLayers.Length(); i++) {
if (mLayers[i].mPosition != aOther.mLayers[i].mPosition ||
!DefinitelyEqualURIs(mLayers[i].mImage.GetURLValue(),
aOther.mLayers[i].mImage.GetURLValue()) ||
mLayers[i].mImage != aOther.mLayers[i].mImage ||
mLayers[i].mSize != aOther.mLayers[i].mSize ||
mLayers[i].mClip != aOther.mLayers[i].mClip ||
@ -2767,11 +2812,17 @@ void nsStyleImageLayers::FillAllLayers(uint32_t aMaxItemCount) {
FillImageLayerList(mLayers, &Layer::mComposite, mCompositeCount, fillCount);
}
static bool UrlValuesEqual(const nsStyleImage& aImage,
const nsStyleImage& aOtherImage) {
auto* url = aImage.GetURLValue();
auto* other = aOtherImage.GetURLValue();
return url == other || (url && other && *url == *other);
}
nsChangeHint nsStyleImageLayers::Layer::CalcDifference(
const nsStyleImageLayers::Layer& aNewLayer) const {
nsChangeHint hint = nsChangeHint(0);
if (!DefinitelyEqualURIs(mImage.GetURLValue(),
aNewLayer.mImage.GetURLValue())) {
if (!UrlValuesEqual(mImage, aNewLayer.mImage)) {
hint |= nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects;
} else if (mAttachment != aNewLayer.mAttachment || mClip != aNewLayer.mClip ||
mOrigin != aNewLayer.mOrigin || mRepeat != aNewLayer.mRepeat ||
@ -2907,7 +2958,8 @@ bool StyleAnimation::operator==(const StyleAnimation& aOther) const {
// nsStyleDisplay
//
nsStyleDisplay::nsStyleDisplay(const Document& aDocument)
: mTransitions(
: mBinding(StyleUrlOrNone::None()),
mTransitions(
nsStyleAutoArray<StyleTransition>::WITH_SINGLE_INITIAL_ELEMENT),
mTransitionTimingFunctionCount(1),
mTransitionDurationCount(1),
@ -3092,9 +3144,8 @@ nsChangeHint nsStyleDisplay::CalcDifference(
const nsStyleDisplay& aNewData) const {
nsChangeHint hint = nsChangeHint(0);
if (!DefinitelyEqualURIsAndPrincipal(mBinding, aNewData.mBinding) ||
mPosition != aNewData.mPosition || mDisplay != aNewData.mDisplay ||
mContain != aNewData.mContain ||
if (mBinding != aNewData.mBinding || mPosition != aNewData.mPosition ||
mDisplay != aNewData.mDisplay || mContain != aNewData.mContain ||
(mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None) ||
mScrollBehavior != aNewData.mScrollBehavior ||
mScrollSnapType != aNewData.mScrollSnapType ||

View File

@ -215,7 +215,7 @@ class nsStyleImageRequest {
// 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::URLValue* aImageValue);
nsStyleImageRequest(Mode aModeFlags, const mozilla::StyleComputedImageUrl&);
bool Resolve(mozilla::dom::Document&,
const nsStyleImageRequest* aOldImageRequest);
@ -234,7 +234,9 @@ class nsStyleImageRequest {
// return true from URLValue::DefinitelyEqualURIs.
bool DefinitelyEquals(const nsStyleImageRequest& aOther) const;
mozilla::css::URLValue* GetImageValue() const { return mImageValue; }
const mozilla::StyleComputedImageUrl& GetImageValue() const {
return mImageURL;
}
already_AddRefed<nsIURI> GetImageURI() const;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsStyleImageRequest);
@ -246,7 +248,7 @@ class nsStyleImageRequest {
void MaybeTrackAndLock();
RefPtr<imgRequestProxy> mRequestProxy;
RefPtr<mozilla::css::URLValue> mImageValue;
mozilla::StyleComputedImageUrl mImageURL;
RefPtr<mozilla::dom::ImageTracker> mImageTracker;
// Cache DocGroup for dispatching events in the destructor.
@ -295,8 +297,6 @@ struct CachedBorderImageData {
* image of type (1)).
*/
struct nsStyleImage {
typedef mozilla::css::URLValue URLValue;
nsStyleImage();
~nsStyleImage();
nsStyleImage(const nsStyleImage& aOther);
@ -346,7 +346,7 @@ struct nsStyleImage {
already_AddRefed<nsIURI> GetImageURI() const;
const URLValue* GetURLValue() const;
const mozilla::StyleComputedImageUrl* GetURLValue() const;
/**
* Compute the actual crop rect in pixels, using the source image bounds.
@ -1603,10 +1603,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
nsChangeHint CalcDifference(const nsStyleDisplay& aNewData) const;
// We guarantee that if mBinding is non-null, so are mBinding->GetURI() and
// mBinding->mOriginPrincipal.
RefPtr<mozilla::css::URLValue> mBinding;
mozilla::StyleUrlOrNone mBinding;
nsStyleAutoArray<mozilla::StyleTransition> mTransitions;
// The number of elements in mTransitions that are not from repeating
// a list due to another property being longer.
@ -2393,10 +2390,10 @@ class nsStyleSVGPaint {
void SetNone();
void SetColor(mozilla::StyleColor aColor);
void SetPaintServer(mozilla::css::URLValue* aPaintServer,
void SetPaintServer(const mozilla::StyleComputedUrl& aPaintServer,
nsStyleSVGFallbackType aFallbackType,
mozilla::StyleColor aFallbackColor);
void SetPaintServer(mozilla::css::URLValue* aPaintServer) {
void SetPaintServer(const mozilla::StyleComputedUrl& aPaintServer) {
SetPaintServer(aPaintServer, eStyleSVGFallbackType_NotSet,
mozilla::StyleColor::Black());
}
@ -2413,7 +2410,7 @@ class nsStyleSVGPaint {
return mPaint.mColor.CalcColor(*aComputedStyle);
}
mozilla::css::URLValue* GetPaintServer() const {
const mozilla::StyleComputedUrl& GetPaintServer() const {
MOZ_ASSERT(mType == eStyleSVGPaintType_Server);
return mPaint.mPaintServer;
}
@ -2438,7 +2435,7 @@ class nsStyleSVGPaint {
union ColorOrPaintServer {
mozilla::StyleColor mColor;
mozilla::css::URLValue* mPaintServer;
mozilla::StyleComputedUrl mPaintServer;
explicit ColorOrPaintServer(mozilla::StyleColor c) : mColor(c) {}
~ColorOrPaintServer() {} // Caller must call Reset().
};
@ -2459,9 +2456,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG {
nsStyleSVGPaint mFill;
nsStyleSVGPaint mStroke;
RefPtr<mozilla::css::URLValue> mMarkerEnd;
RefPtr<mozilla::css::URLValue> mMarkerMid;
RefPtr<mozilla::css::URLValue> mMarkerStart;
mozilla::StyleUrlOrNone mMarkerEnd;
mozilla::StyleUrlOrNone mMarkerMid;
mozilla::StyleUrlOrNone mMarkerStart;
nsTArray<mozilla::NonNegativeLengthPercentage> mStrokeDasharray;
mozilla::StyleMozContextProperties mMozContextProperties;
@ -2508,7 +2505,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG {
return mContextFlags & STROKE_WIDTH_CONTEXT;
}
bool HasMarker() const { return mMarkerStart || mMarkerMid || mMarkerEnd; }
bool HasMarker() const {
return mMarkerStart.IsUrl() || mMarkerMid.IsUrl() || mMarkerEnd.IsUrl();
}
/**
* Returns true if the stroke is not "none" and the stroke-opacity is greater
@ -2572,12 +2571,12 @@ struct nsStyleFilter {
}
void SetFilterParameter(const nsStyleCoord& aFilterParameter, int32_t aType);
mozilla::css::URLValue* GetURL() const {
const mozilla::StyleComputedUrl& GetURL() const {
MOZ_ASSERT(mType == NS_STYLE_FILTER_URL, "wrong filter type");
return mURL;
}
bool SetURL(mozilla::css::URLValue* aValue);
bool SetURL(const mozilla::StyleComputedUrl& aUrl);
const mozilla::StyleSimpleShadow& GetDropShadow() const {
NS_ASSERTION(mType == NS_STYLE_FILTER_DROP_SHADOW, "wrong filter type");
@ -2591,7 +2590,7 @@ struct nsStyleFilter {
uint32_t mType; // NS_STYLE_FILTER_*
nsStyleCoord mFilterParameter; // coord, percent, factor, angle
union {
mozilla::css::URLValue* mURL;
mozilla::StyleComputedUrl mURL;
mozilla::StyleSimpleShadow mDropShadow;
};
};

View File

@ -93,18 +93,14 @@ class URLAndReferrerInfoHashKey : public PLDHashEntryHdr {
};
static already_AddRefed<URLAndReferrerInfo> ResolveURLUsingLocalRef(
nsIFrame* aFrame, const css::URLValue* aURL) {
nsIFrame* aFrame, const StyleComputedImageUrl& aURL) {
MOZ_ASSERT(aFrame);
if (!aURL) {
return nullptr;
}
nsCOMPtr<nsIURI> uri = aURL.GetURI();
nsCOMPtr<nsIURI> uri = aURL->GetURI();
if (aURL->IsLocalRef()) {
if (aURL.IsLocalRef()) {
uri = SVGObserverUtils::GetBaseURLForLocalRef(aFrame->GetContent(), uri);
uri = aURL->ResolveLocalRef(uri);
uri = aURL.ResolveLocalRef(uri);
}
if (!uri) {
@ -112,7 +108,7 @@ static already_AddRefed<URLAndReferrerInfo> ResolveURLUsingLocalRef(
}
RefPtr<URLAndReferrerInfo> info =
new URLAndReferrerInfo(uri, aURL->ExtraData());
new URLAndReferrerInfo(uri, aURL.ExtraData());
return info.forget();
}
@ -703,10 +699,10 @@ SVGFilterObserverList::SVGFilterObserverList(
filterURL = ResolveURLUsingLocalRef(aFilteredFrame, aFilters[i].GetURL());
} else {
nsCOMPtr<nsIURI> resolvedURI =
aFilters[i].GetURL()->ResolveLocalRef(aFilteredElement);
aFilters[i].GetURL().ResolveLocalRef(aFilteredElement);
if (resolvedURI) {
filterURL = new URLAndReferrerInfo(resolvedURI,
aFilters[i].GetURL()->ExtraData());
aFilters[i].GetURL().ExtraData());
}
}
@ -820,8 +816,12 @@ SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame) : mFrame(aFrame) {
const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
const css::URLValue* data = svgReset->mMask.mLayers[i].mImage.GetURLValue();
RefPtr<URLAndReferrerInfo> maskUri = ResolveURLUsingLocalRef(aFrame, data);
const StyleComputedImageUrl* data =
svgReset->mMask.mLayers[i].mImage.GetURLValue();
RefPtr<URLAndReferrerInfo> maskUri;
if (data) {
maskUri = ResolveURLUsingLocalRef(aFrame, *data);
}
bool hasRef = false;
if (maskUri) {
@ -1110,8 +1110,12 @@ static nsSVGPaintingProperty* GetPaintingProperty(
}
static already_AddRefed<URLAndReferrerInfo> GetMarkerURI(
nsIFrame* aFrame, RefPtr<css::URLValue> nsStyleSVG::*aMarker) {
return ResolveURLUsingLocalRef(aFrame, aFrame->StyleSVG()->*aMarker);
nsIFrame* aFrame, const StyleUrlOrNone nsStyleSVG::*aMarker) {
const StyleUrlOrNone& url = aFrame->StyleSVG()->*aMarker;
if (url.IsNone()) {
return nullptr;
}
return ResolveURLUsingLocalRef(aFrame, url.AsUrl());
}
bool SVGObserverUtils::GetAndObserveMarkers(nsIFrame* aMarkedFrame,
@ -1234,11 +1238,10 @@ static nsSVGPaintingProperty* GetOrCreateClipPathObserver(
if (svgStyleReset->mClipPath.GetType() != StyleShapeSourceType::Image) {
return nullptr;
}
const css::URLValue* url =
svgStyleReset->mClipPath.ShapeImage().GetURLValue();
const auto* url = svgStyleReset->mClipPath.ShapeImage().GetURLValue();
MOZ_ASSERT(url);
RefPtr<URLAndReferrerInfo> pathURI =
ResolveURLUsingLocalRef(aClippedFrame, url);
ResolveURLUsingLocalRef(aClippedFrame, *url);
return GetPaintingProperty(pathURI, aClippedFrame, ClipPathProperty());
}

View File

@ -51,10 +51,10 @@ class URLAndReferrerInfo {
MOZ_ASSERT(aURI);
}
URLAndReferrerInfo(nsIURI* aURI, URLExtraData* aExtraData)
URLAndReferrerInfo(nsIURI* aURI, const URLExtraData& aExtraData)
: mURI(aURI),
mReferrer(aExtraData->GetReferrer()),
mReferrerPolicy(aExtraData->GetReferrerPolicy()) {
mReferrer(aExtraData.GetReferrer()),
mReferrerPolicy(aExtraData.GetReferrerPolicy()) {
MOZ_ASSERT(aURI);
}

View File

@ -134,7 +134,7 @@ nsSVGFilterFrame* nsSVGFilterInstance::GetFilterFrame(nsIFrame* aTargetFrame) {
url = urlExtraReferrer->GetURI();
} else {
url = mFilter.GetURL()->ResolveLocalRef(mTargetContent);
url = mFilter.GetURL().ResolveLocalRef(mTargetContent);
}
if (!url) {
@ -147,8 +147,8 @@ nsSVGFilterFrame* nsSVGFilterInstance::GetFilterFrame(nsIFrame* aTargetFrame) {
IDTracker idTracker;
bool watch = false;
idTracker.ResetToURIFragmentID(
mTargetContent, url, mFilter.GetURL()->ExtraData()->GetReferrer(),
mFilter.GetURL()->ExtraData()->GetReferrerPolicy(), watch);
mTargetContent, url, mFilter.GetURL().ExtraData().GetReferrer(),
mFilter.GetURL().ExtraData().GetReferrerPolicy(), watch);
Element* element = idTracker.get();
if (!element) {
// The URL points to no element.

View File

@ -90,6 +90,9 @@ const STATIC_REFCOUNT: usize = usize::MAX;
/// usage of PhantomData.
///
/// [`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
///
/// cbindgen:derive-eq=false
/// cbindgen:derive-neq=false
#[repr(C)]
pub struct Arc<T: ?Sized> {
p: ptr::NonNull<ArcInner<T>>,

View File

@ -55,7 +55,7 @@ impl OneOrMoreSeparated for Source {
#[repr(u8)]
#[allow(missing_docs)]
pub enum FontFaceSourceListComponent {
Url(*const crate::gecko_bindings::structs::mozilla::css::URLValue),
Url(*const crate::gecko::url::CssUrl),
Local(*mut crate::gecko_bindings::structs::nsAtom),
FormatHint {
length: usize,

View File

@ -122,11 +122,11 @@ impl nsStyleImage {
match image {
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
GenericImage::Url(ref url) => unsafe {
bindings::Gecko_SetLayerImageImageValue(self, url.url_value_ptr())
bindings::Gecko_SetLayerImageImageValue(self, url);
},
GenericImage::Rect(ref image_rect) => {
unsafe {
bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.url_value_ptr());
bindings::Gecko_SetLayerImageImageValue(self, &image_rect.url);
bindings::Gecko_InitializeImageCropRect(self);
// Set CropRect
@ -584,9 +584,10 @@ pub mod basic_shape {
impl<'a> From<&'a StyleShapeSource> for ClippingShape {
fn from(other: &'a StyleShapeSource) -> Self {
use crate::values::generics::image::Image as GenericImage;
match other.mType {
StyleShapeSourceType::Image => unsafe {
use crate::values::generics::image::Image as GenericImage;
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image");
match image {

View File

@ -5,13 +5,11 @@
//! Common handling for the specified value CSS url() values.
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs::root::mozilla::css::URLValue;
use crate::gecko_bindings::structs::root::mozilla::CORSMode;
use crate::gecko_bindings::structs::root::nsStyleImageRequest;
use crate::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI};
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsStyleImageRequest;
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::parser::{Parse, ParserContext};
use crate::stylesheets::UrlExtraData;
use crate::stylesheets::{UrlExtraData, CorsMode};
use crate::values::computed::{Context, ToComputedValue};
use cssparser::Parser;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
@ -27,25 +25,63 @@ use to_shmem::{SharedMemoryBuilder, ToShmem};
/// A CSS url() value for gecko.
#[css(function = "url")]
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
#[repr(C)]
pub struct CssUrl(pub Arc<CssUrlData>);
/// Data shared between CssUrls.
#[derive(Clone, Debug, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
///
/// cbindgen:derive-eq=false
/// cbindgen:derive-neq=false
#[derive(Debug, SpecifiedValueInfo, ToCss, ToShmem)]
#[repr(C)]
pub struct CssUrlData {
/// The URL in unresolved string form.
serialization: String,
serialization: crate::OwnedStr,
/// The URL extra data.
#[css(skip)]
pub extra_data: UrlExtraData,
/// The CORS mode that will be used for the load.
#[css(skip)]
cors_mode: CorsMode,
/// Data to trigger a load from Gecko. This is mutable in C++.
///
/// TODO(emilio): Maybe we can eagerly resolve URLs and make this immutable?
#[css(skip)]
load_data: LoadDataSource,
}
impl PartialEq for CssUrlData {
fn eq(&self, other: &Self) -> bool {
self.serialization == other.serialization &&
self.extra_data == other.extra_data &&
self.cors_mode == other.cors_mode
}
}
impl CssUrl {
fn parse_with_cors_mode<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
cors_mode: CorsMode,
) -> Result<Self, ParseError<'i>> {
let url = input.expect_url()?;
Ok(Self::parse_from_string(url.as_ref().to_owned(), context, cors_mode))
}
/// 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 {
pub fn parse_from_string(
url: String,
context: &ParserContext,
cors_mode: CorsMode,
) -> Self {
CssUrl(Arc::new(CssUrlData {
serialization: url,
serialization: url.into(),
extra_data: context.url_data.clone(),
cors_mode,
load_data: LoadDataSource::Owned(LoadData::default()),
}))
}
@ -85,27 +121,12 @@ impl CssUrlData {
}
}
#[cfg(debug_assertions)]
impl Drop for CssUrlData {
fn drop(&mut self) {
assert!(
!URL_VALUE_TABLE
.read()
.unwrap()
.contains_key(&CssUrlDataKey(self as *mut _ as *const _)),
"All CssUrlData objects used as keys in URL_VALUE_TABLE should be \
from shared memory style sheets, and so should never be dropped",
);
}
}
impl Parse for CssUrl {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let url = input.expect_url()?;
Ok(Self::parse_from_string(url.as_ref().to_owned(), context))
Self::parse_with_cors_mode(context, input, CorsMode::None)
}
}
@ -122,143 +143,101 @@ impl MallocSizeOf for CssUrl {
}
}
/// A key type for URL_VALUE_TABLE.
/// A key type for LOAD_DATA_TABLE.
#[derive(Eq, Hash, PartialEq)]
struct CssUrlDataKey(*const CssUrlData);
struct LoadDataKey(*const LoadDataSource);
unsafe impl Sync for CssUrlDataKey {}
unsafe impl Send for CssUrlDataKey {}
unsafe impl Sync for LoadDataKey {}
unsafe impl Send for LoadDataKey {}
/// The source of a Gecko URLValue object for a SpecifiedUrl.
#[derive(Clone, Debug)]
pub enum URLValueSource {
/// A strong reference to a Gecko URLValue object.
URLValue(RefPtr<URLValue>),
/// A CORSMode value used to lazily construct a Gecko URLValue object.
///
/// The lazily created object will be stored in URL_VALUE_TABLE.
CORSMode(CORSMode),
/// The load data for a given URL. This is mutable from C++, for now at least.
#[repr(C)]
#[derive(Debug)]
pub struct LoadData {
resolved: RefPtr<structs::nsIURI>,
load_id: u64,
tried_to_resolve: bool,
}
impl ToShmem for URLValueSource {
impl Drop for LoadData {
fn drop(&mut self) {
if self.load_id != 0 {
unsafe {
bindings::Gecko_LoadData_DeregisterLoad(self);
}
}
}
}
impl Default for LoadData {
fn default() -> Self {
Self {
resolved: RefPtr::null(),
load_id: 0,
tried_to_resolve: false,
}
}
}
/// The data for a load, or a lazy-loaded, static member that will be stored in
/// LOAD_DATA_TABLE, keyed by the memory location of this object, which is
/// always in the heap because it's inside the CssUrlData object.
///
/// This type is meant not to be used from C++ so we don't derive helper
/// methods.
///
/// cbindgen:derive-helper-methods=false
#[derive(Debug)]
#[repr(u8, C)]
pub enum LoadDataSource {
/// An owned copy of the load data.
Owned(LoadData),
/// A lazily-resolved copy of it.
Lazy,
}
impl LoadDataSource {
/// Gets the load data associated with the source.
///
/// This relies on the source on being in a stable location if lazy.
#[inline]
pub unsafe fn get(&self) -> *const LoadData {
match *self {
LoadDataSource::Owned(ref d) => return d,
LoadDataSource::Lazy => {},
}
let key = LoadDataKey(self);
{
let guard = LOAD_DATA_TABLE.read().unwrap();
if let Some(r) = guard.get(&key) {
return &**r;
}
}
let mut guard = LOAD_DATA_TABLE.write().unwrap();
let r = guard.entry(key).or_insert_with(Default::default);
&**r
}
}
impl ToShmem for LoadDataSource {
fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> ManuallyDrop<Self> {
ManuallyDrop::new(match self {
URLValueSource::URLValue(r) => URLValueSource::CORSMode(r.mCORSMode),
URLValueSource::CORSMode(c) => URLValueSource::CORSMode(*c),
LoadDataSource::Owned(..) => LoadDataSource::Lazy,
LoadDataSource::Lazy => LoadDataSource::Lazy,
})
}
}
/// A specified non-image `url()` value.
#[derive(Clone, Debug, SpecifiedValueInfo, ToCss, ToShmem)]
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.
///
/// Box this to avoid SpecifiedUrl getting bigger than two words,
/// and increasing the size of PropertyDeclaration.
#[css(skip)]
url_value: Box<URLValueSource>,
}
pub type SpecifiedUrl = CssUrl;
fn make_url_value(url: &CssUrl, cors_mode: CORSMode) -> RefPtr<URLValue> {
unsafe {
let ptr = bindings::Gecko_URLValue_Create(url.0.clone().into_strong(), cors_mode);
// We do not expect Gecko_URLValue_Create returns null.
debug_assert!(!ptr.is_null());
RefPtr::from_addrefed(ptr)
}
}
impl SpecifiedUrl {
/// Parse a URL from a string value.
pub fn parse_from_string(url: String, context: &ParserContext) -> Self {
Self::from_css_url(CssUrl::parse_from_string(url, context))
}
fn from_css_url_with_cors(url: CssUrl, cors: CORSMode) -> Self {
let url_value = Box::new(URLValueSource::URLValue(make_url_value(&url, cors)));
Self { url, url_value }
}
fn from_css_url(url: CssUrl) -> Self {
use crate::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 crate::gecko_bindings::structs::root::mozilla::CORSMode_CORS_ANONYMOUS;
Self::from_css_url_with_cors(url, CORSMode_CORS_ANONYMOUS)
}
fn with_url_value<F, T>(&self, f: F) -> T
where
F: FnOnce(&RefPtr<URLValue>) -> T,
{
match *self.url_value {
URLValueSource::URLValue(ref r) => f(r),
URLValueSource::CORSMode(cors_mode) => {
{
let guard = URL_VALUE_TABLE.read().unwrap();
if let Some(r) = guard.get(&(CssUrlDataKey(&*self.url.0 as *const _))) {
return f(r);
}
}
let mut guard = URL_VALUE_TABLE.write().unwrap();
let r = guard
.entry(CssUrlDataKey(&*self.url.0 as *const _))
.or_insert_with(|| make_url_value(&self.url, cors_mode));
f(r)
},
}
}
/// Clone a new, strong reference to the Gecko URLValue.
pub fn clone_url_value(&self) -> RefPtr<URLValue> {
self.with_url_value(RefPtr::clone)
}
/// Get a raw pointer to the URLValue held by this SpecifiedUrl, for FFI.
pub fn url_value_ptr(&self) -> *mut URLValue {
self.with_url_value(RefPtr::get)
}
}
/// Clears URL_VALUE_TABLE. Entries in this table, which are for specified URL
/// Clears LOAD_DATA_TABLE. Entries in this table, which are for specified URL
/// values that come from shared memory style sheets, would otherwise persist
/// until the end of the process and be reported as leaks.
pub fn shutdown() {
URL_VALUE_TABLE.write().unwrap().clear();
}
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 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_ptr()) };
n
}
LOAD_DATA_TABLE.write().unwrap().clear();
}
impl ToComputedValue for SpecifiedUrl {
@ -277,12 +256,13 @@ impl ToComputedValue for SpecifiedUrl {
/// A specified image `url()` value.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
#[repr(C)]
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))
SpecifiedImageUrl(SpecifiedUrl::parse_from_string(url, context, CorsMode::None))
}
/// Provides an alternate method for parsing that associates the URL
@ -291,9 +271,11 @@ impl SpecifiedImageUrl {
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)
Ok(SpecifiedImageUrl(SpecifiedUrl::parse_with_cors_mode(
context,
input,
CorsMode::Anonymous,
)?))
}
}
@ -320,59 +302,39 @@ impl ToComputedValue for SpecifiedImageUrl {
}
}
fn serialize_computed_url<W>(
url_value: &URLValue,
dest: &mut CssWriter<W>,
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, &mut string);
string.as_str_unchecked().to_css(dest)?;
}
dest.write_char(')')
}
/// 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)]
#[repr(C)]
pub struct ComputedUrl(pub SpecifiedUrl);
impl ComputedUrl {
fn serialize_with<W>(
&self,
function: unsafe extern "C" fn(*const Self, *mut nsCString),
dest: &mut CssWriter<W>,
) -> fmt::Result
where
W: Write,
{
dest.write_str("url(")?;
unsafe {
let mut string = nsCString::new();
function(self, &mut string);
string.as_str_unchecked().to_css(dest)?;
}
dest.write_char(')')
}
}
impl ToCss for ComputedUrl {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.0
.with_url_value(|r| serialize_computed_url(r, dest, bindings::Gecko_GetComputedURLSpec))
}
}
impl ComputedUrl {
/// Convert from RefPtr<URLValue> to ComputedUrl.
pub unsafe fn from_url_value(url_value: RefPtr<URLValue>) -> Self {
let css_url = &*url_value.mCssUrl.mRawPtr;
let url = CssUrl(CssUrlData::as_arc(&css_url).clone_arc());
ComputedUrl(SpecifiedUrl {
url,
url_value: Box::new(URLValueSource::URLValue(url_value)),
})
}
/// Clone a new, strong reference to the Gecko URLValue.
pub fn clone_url_value(&self) -> RefPtr<URLValue> {
self.0.clone_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_ptr()
self.serialize_with(bindings::Gecko_GetComputedURLSpec, dest)
}
}
@ -380,39 +342,26 @@ impl ComputedUrl {
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
pub struct ComputedImageUrl(pub ComputedUrl);
impl ComputedImageUrl {
/// Convert from nsStyleImageRequest to ComputedImageUrl.
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
image_request.mImageURL.clone()
}
}
impl ToCss for ComputedImageUrl {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
(self.0).0.with_url_value(|r| {
serialize_computed_url(r, dest, bindings::Gecko_GetComputedImageURLSpec)
})
}
}
impl ComputedImageUrl {
/// Convert from nsStyleImageReques to ComputedImageUrl.
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Self {
let url_value = image_request.mImageValue.to_safe();
ComputedImageUrl(ComputedUrl::from_url_value(url_value))
}
/// Clone a new, strong reference to the Gecko URLValue.
pub fn clone_url_value(&self) -> RefPtr<URLValue> {
self.0.clone_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.url_value_ptr()
self.0.serialize_with(bindings::Gecko_GetComputedImageURLSpec, dest)
}
}
lazy_static! {
/// A table mapping CssUrlData objects to their lazily created Gecko
/// URLValue objects.
static ref URL_VALUE_TABLE: RwLock<HashMap<CssUrlDataKey, RefPtr<URLValue>>> = {
/// A table mapping CssUrlData objects to their lazily created LoadData
/// objects.
static ref LOAD_DATA_TABLE: RwLock<HashMap<LoadDataKey, Box<LoadData>>> = {
Default::default()
};
}

View File

@ -63,15 +63,25 @@ impl<T: RefCounted> RefPtr<T> {
}
}
/// Returns whether the current pointer is null.
pub fn is_null(&self) -> bool {
self.ptr.is_null()
}
/// Returns a null pointer.
pub fn null() -> Self {
Self {
ptr: ptr::null_mut(),
_marker: PhantomData,
}
}
/// Create a new RefPtr from a pointer obtained from FFI.
///
/// The pointer must be valid and non null.
///
/// This method calls addref() internally
pub unsafe fn new(ptr: *mut T) -> Self {
debug_assert!(!ptr.is_null());
let ret = RefPtr {
ptr: ptr,
ptr,
_marker: PhantomData,
};
ret.addref();
@ -97,8 +107,10 @@ impl<T: RefCounted> RefPtr<T> {
/// Addref the inner data, obviously leaky on its own.
pub fn addref(&self) {
unsafe {
(*self.ptr).addref();
if !self.ptr.is_null() {
unsafe {
(*self.ptr).addref();
}
}
}
@ -106,7 +118,9 @@ impl<T: RefCounted> RefPtr<T> {
///
/// Call only when the data actually needs releasing.
pub unsafe fn release(&self) {
(*self.ptr).release();
if !self.ptr.is_null() {
(*self.ptr).release();
}
}
}
@ -130,6 +144,7 @@ impl<T: RefCounted> UniqueRefPtr<T> {
impl<T: RefCounted> Deref for RefPtr<T> {
type Target = T;
fn deref(&self) -> &T {
debug_assert!(!self.ptr.is_null());
unsafe { &*self.ptr }
}
}
@ -152,7 +167,6 @@ impl<T: RefCounted> structs::RefPtr<T> {
///
/// Must be called on a valid, non-null structs::RefPtr<T>.
pub unsafe fn to_safe(&self) -> RefPtr<T> {
debug_assert!(!self.mRawPtr.is_null());
let r = RefPtr {
ptr: self.mRawPtr,
_marker: PhantomData,
@ -290,9 +304,9 @@ impl_threadsafe_refcount!(
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
);
impl_threadsafe_refcount!(
structs::mozilla::css::URLValue,
bindings::Gecko_AddRefCSSURLValueArbitraryThread,
bindings::Gecko_ReleaseCSSURLValueArbitraryThread
structs::nsIURI,
bindings::Gecko_AddRefnsIURIArbitraryThread,
bindings::Gecko_ReleasensIURIArbitraryThread
);
impl_threadsafe_refcount!(
structs::mozilla::css::GridTemplateAreasValue,

View File

@ -278,7 +278,7 @@ impl ComputedValuesInner {
#[allow(non_snake_case)]
pub fn has_moz_binding(&self) -> bool {
!self.get_box().gecko.mBinding.mRawPtr.is_null()
!self.get_box().gecko.mBinding.is_none()
}
}
@ -550,7 +550,7 @@ def set_gecko_property(ffi_name, expr):
unsafe {
bindings::Gecko_nsStyleSVGPaint_SetURLValue(
paint,
url.url_value_ptr(),
&url
)
}
}
@ -591,7 +591,6 @@ def set_gecko_property(ffi_name, expr):
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use crate::values::computed::url::ComputedUrl;
use crate::values::generics::svg::{SVGPaint, SVGPaintKind};
use self::structs::nsStyleSVGPaintType;
use self::structs::nsStyleSVGFallbackType;
@ -613,8 +612,7 @@ def set_gecko_property(ffi_name, expr):
nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke => SVGPaintKind::ContextStroke,
nsStyleSVGPaintType::eStyleSVGPaintType_Server => {
SVGPaintKind::PaintServer(unsafe {
let url = RefPtr::new(*paint.mPaint.mPaintServer.as_ref());
ComputedUrl::from_url_value(url)
paint.mPaint.mPaintServer.as_ref().clone()
})
}
nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
@ -735,45 +733,6 @@ def set_gecko_property(ffi_name, expr):
}
</%def>
<%def name="impl_css_url(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
match v {
UrlOrNone::Url(ref url) => {
self.gecko.${gecko_ffi_name}.set_move(url.clone_url_value())
}
UrlOrNone::None => {
unsafe {
self.gecko.${gecko_ffi_name}.clear();
}
}
}
}
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
unsafe {
self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name});
}
}
#[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) {
self.copy_${ident}_from(other)
}
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use crate::values::computed::url::ComputedUrl;
if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() {
return UrlOrNone::none()
}
UrlOrNone::Url(unsafe {
ComputedUrl::from_url_value(self.gecko.${gecko_ffi_name}.to_safe())
})
}
</%def>
<%def name="impl_logical(name, **kwargs)">
${helpers.logical_setter(name)}
</%def>
@ -879,7 +838,6 @@ impl Clone for ${style_struct.gecko_struct_name} {
"SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint,
"SVGWidth": impl_svg_length,
"url::UrlOrNone": impl_css_url,
}
def longhand_method(longhand):
@ -2164,8 +2122,7 @@ fn static_assert() {
animation-iteration-count animation-timing-function
clear transition-duration transition-delay
transition-timing-function transition-property
transform-style -moz-binding shape-outside
-webkit-line-clamp""" %>
transform-style shape-outside -webkit-line-clamp""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
#[inline]
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
@ -2205,7 +2162,6 @@ fn static_assert() {
gecko_inexhaustive=True,
) %>
${impl_keyword('clear', 'mBreakType', clear_keyword)}
${impl_css_url('_moz_binding', 'mBinding')}
${impl_transition_time_value('delay', 'Delay')}
${impl_transition_time_value('duration', 'Duration')}
${impl_transition_timing_function()}
@ -2834,10 +2790,7 @@ fn static_assert() {
}
UrlOrNone::Url(ref url) => {
unsafe {
Gecko_SetListStyleImageImageValue(
&mut *self.gecko,
url.url_value_ptr(),
);
Gecko_SetListStyleImageImageValue(&mut *self.gecko, url);
}
}
}
@ -3145,7 +3098,7 @@ fn static_assert() {
},
Url(ref url) => {
unsafe {
bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.url_value_ptr());
bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url);
}
},
}
@ -3164,7 +3117,6 @@ fn static_assert() {
pub fn clone_filter(&self) -> longhands::filter::computed_value::T {
use crate::values::generics::effects::Filter;
use crate::values::computed::url::ComputedUrl;
use crate::gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
use crate::gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
use crate::gecko_bindings::structs::NS_STYLE_FILTER_CONTRAST;
@ -3205,8 +3157,7 @@ fn static_assert() {
},
NS_STYLE_FILTER_URL => {
Filter::Url(unsafe {
let url = RefPtr::new(*filter.__bindgen_anon_1.mURL.as_ref());
ComputedUrl::from_url_value(url)
filter.__bindgen_anon_1.mURL.as_ref().clone()
})
}
_ => unreachable!("Unknown filter function?"),
@ -3550,7 +3501,7 @@ clip-path
unsafe {
Gecko_SetCursorImageValue(
&mut self.gecko.mCursorImages[i],
v.images[i].url.url_value_ptr(),
&v.images[i].url
);
}
@ -3769,7 +3720,7 @@ clip-path
unsafe {
bindings::Gecko_SetContentDataImageValue(
&mut self.gecko.mContents[i],
url.url_value_ptr(),
url,
)
}
}

View File

@ -644,7 +644,6 @@ ${helpers.predefined_type(
"basic_shape::FloatAreaShape",
"generics::basic_shape::ShapeSource::None",
products="gecko",
boxed=True,
animation_value_type="basic_shape::FloatAreaShape",
flags="APPLIES_TO_FIRST_LETTER",
spec="https://drafts.csswg.org/css-shapes/#shape-outside-property",

View File

@ -63,9 +63,15 @@ pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentSt
pub use self::supports_rule::SupportsRule;
pub use self::viewport_rule::ViewportRule;
/// Extra data that the backend may need to resolve url values.
#[cfg(not(feature = "gecko"))]
pub type UrlExtraData = ::servo_url::ServoUrl;
/// The CORS mode used for a CSS load.
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, ToShmem)]
pub enum CorsMode {
/// No CORS mode, so cross-origin loads can be done.
None,
/// Anonymous CORS request.
Anonymous,
}
/// Extra data that the backend may need to resolve url values.
///
@ -82,8 +88,13 @@ pub type UrlExtraData = ::servo_url::ServoUrl;
/// `from_ptr_ref` can work.
#[cfg(feature = "gecko")]
#[derive(PartialEq)]
#[repr(C)]
pub struct UrlExtraData(usize);
/// Extra data that the backend may need to resolve url values.
#[cfg(not(feature = "gecko"))]
pub type UrlExtraData = ::servo_url::ServoUrl;
#[cfg(feature = "gecko")]
impl Clone for UrlExtraData {
fn clone(&self) -> UrlExtraData {

View File

@ -20,7 +20,7 @@ use crate::stylesheets::stylesheet::Namespaces;
use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::viewport_rule;
use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
use crate::stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
use crate::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
use crate::values::computed::font::FamilyName;
use crate::values::{CssUrl, CustomIdent, KeyframesName};
@ -197,7 +197,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
}
let url_string = input.expect_url_or_string()?.as_ref().to_owned();
let url = CssUrl::parse_from_string(url_string, &self.context);
let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
let media = MediaList::parse(&self.context, input);
let media = Arc::new(self.shared_lock.wrap(media));

View File

@ -5,6 +5,8 @@
//! Generic types for url properties.
/// An image url or none, used for example in list-style-image
///
/// cbindgen:derive-tagged-enum-copy-constructor=true
#[derive(
Animate,
Clone,
@ -21,16 +23,27 @@
ToResolvedValue,
ToShmem,
)]
pub enum UrlOrNone<Url> {
#[repr(C, u8)]
pub enum GenericUrlOrNone<U> {
/// `none`
None,
/// `A URL`
Url(Url),
/// A URL.
Url(U),
}
pub use self::GenericUrlOrNone as UrlOrNone;
impl<Url> UrlOrNone<Url> {
/// Initial "none" value for properties such as `list-style-image`
pub fn none() -> Self {
UrlOrNone::None
}
/// Returns whether the value is `none`.
pub fn is_none(&self) -> bool {
match *self {
UrlOrNone::None => true,
UrlOrNone::Url(..) => false,
}
}
}

View File

@ -4,7 +4,7 @@
//! Common handling for the specified value CSS url() values.
use crate::values::generics::url::UrlOrNone as GenericUrlOrNone;
use crate::values::generics::url::GenericUrlOrNone;
#[cfg(feature = "gecko")]
pub use crate::gecko::url::{SpecifiedImageUrl, SpecifiedUrl};

View File

@ -140,6 +140,9 @@ include = [
"Scale",
"Translate",
"BorderImageWidth",
"ComputedUrl",
"ComputedImageUrl",
"UrlOrNone",
]
item_types = ["enums", "structs", "typedefs", "functions"]
renaming_overrides_prefixing = true
@ -148,6 +151,7 @@ renaming_overrides_prefixing = true
[export.rename]
"nscolor" = "nscolor"
"nsAtom" = "nsAtom"
"nsIURI" = "nsIURI"
"nsCompatibility" = "nsCompatibility"
"SharedFontList" = "SharedFontList"
"nsSimpleContentList" = "nsSimpleContentList"
@ -390,6 +394,13 @@ renaming_overrides_prefixing = true
}
"""
"ArcInner" = """
// Increase the reference count.
inline void IncrementRef();
// Release the reference count, and return whether the result must be freed or not.
MOZ_MUST_USE inline bool DecrementRef();
"""
"ArcSlice" = """
inline StyleArcSlice();
inline StyleArcSlice(const StyleArcSlice& aOther);
@ -407,6 +418,33 @@ renaming_overrides_prefixing = true
inline bool operator!=(const StyleArcSlice& other) const;
"""
"Arc" = """
StyleArc() = delete;
inline StyleArc(const StyleArc& Other);
private:
inline void Release();
public:
inline ~StyleArc();
inline StyleArc& operator=(const StyleArc&);
inline StyleArc& operator=(StyleArc&&);
const T* operator->() const {
MOZ_DIAGNOSTIC_ASSERT(p, "Arc shouldn't be null");
return &p->data;
}
const T& operator*() const {
MOZ_DIAGNOSTIC_ASSERT(p, "Arc shouldn't be null");
return p->data;
}
bool operator==(const StyleArc& other) const {
return p == other.p || *(*this) == *other;
}
bool operator!=(const StyleArc& other) const {
return !(*this == other);
}
"""
"CustomIdent" = """
inline nsAtom* AsAtom() const;
"""
@ -441,6 +479,14 @@ renaming_overrides_prefixing = true
public:
"""
"GenericUrlOrNone" = """
private:
// Private default constructor without initialization so that the helper
// constructor functions still work as expected. They take care of
// initializing the fields properly.
StyleGenericUrlOrNone() {}
public:
"""
"Angle" = """
inline static StyleAngle Zero();
inline float ToDegrees() const;
@ -471,3 +517,50 @@ renaming_overrides_prefixing = true
second(StyleTextOverflowSide::Clip()),
sides_are_logical(true) {}
"""
"UrlExtraData" = """
StyleUrlExtraData() = delete;
// Could be implemented if wanted.
StyleUrlExtraData(const StyleUrlExtraData&) = delete;
StyleUrlExtraData& operator=(const StyleUrlExtraData&) = delete;
inline bool IsShared() const;
inline ~StyleUrlExtraData();
inline const URLExtraData& get() const;
"""
"CssUrlData" = """
// Implemented in nsStyleStruct.cpp
bool operator==(const StyleCssUrlData& other) const;
bool operator!=(const StyleCssUrlData& other) const {
return !(*this == other);
}
"""
"LoadData" = """
~StyleLoadData();
"""
"CssUrl" = """
inline nsDependentCSubstring SpecifiedSerialization() const;
inline const URLExtraData& ExtraData() const;
inline StyleLoadData& LoadData() const;
inline nsIURI* GetURI() const;
"""
"ComputedUrl" = """
// Forwarded from CssUrl.
inline nsDependentCSubstring SpecifiedSerialization() const;
inline const URLExtraData& ExtraData() const;
inline nsIURI* GetURI() const;
inline StyleLoadData& LoadData() const;
inline bool IsLocalRef() const;
inline bool HasRef() const;
inline CORSMode CorsMode() const;
already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aBase) const;
already_AddRefed<nsIURI> ResolveLocalRef(const nsIContent* aContent) const;
imgRequestProxy* LoadImage(mozilla::dom::Document&);
"""

View File

@ -35,7 +35,7 @@ use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyle
use style::gecko::restyle_damage::GeckoRestyleDamage;
use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
use style::gecko::traversal::RecalcStyleOnly;
use style::gecko::url::{self, CssUrlData};
use style::gecko::url;
use style::gecko::wrapper::{GeckoElement, GeckoNode};
use style::gecko_bindings::bindings;
use style::gecko_bindings::bindings::nsACString;
@ -50,13 +50,12 @@ use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
use style::gecko_bindings::structs;
use style::gecko_bindings::structs::{Element as RawGeckoElement, nsINode as RawGeckoNode};
use style::gecko_bindings::structs::{
RawServoStyleSet, RawServoAuthorStyles,
RawServoCssUrlData, RawServoDeclarationBlock, RawServoMediaList,
RawServoCounterStyleRule, RawServoAnimationValue, RawServoSupportsRule,
RawServoKeyframesRule, ServoCssRules, RawServoStyleSheetContents,
RawServoPageRule, RawServoNamespaceRule, RawServoMozDocumentRule,
RawServoKeyframe, RawServoMediaRule, RawServoImportRule,
RawServoFontFaceRule, RawServoFontFeatureValuesRule,
RawServoStyleSet, RawServoAuthorStyles, RawServoDeclarationBlock,
RawServoMediaList, RawServoCounterStyleRule, RawServoAnimationValue,
RawServoSupportsRule, RawServoKeyframesRule, ServoCssRules,
RawServoStyleSheetContents, RawServoPageRule, RawServoNamespaceRule,
RawServoMozDocumentRule, RawServoKeyframe, RawServoMediaRule,
RawServoImportRule, RawServoFontFaceRule, RawServoFontFeatureValuesRule,
RawServoSharedMemoryBuilder
};
use style::gecko_bindings::structs::gfxFontFeatureValueSet;
@ -2786,7 +2785,7 @@ pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
for source in sources.iter() {
match *source {
Source::Url(ref url) => {
set_next(FontFaceSourceListComponent::Url(url.url.url_value_ptr()));
set_next(FontFaceSourceListComponent::Url(&url.url));
for hint in url.format_hints.iter() {
set_next(FontFaceSourceListComponent::FormatHint {
length: hint.len(),
@ -6021,27 +6020,8 @@ pub extern "C" fn Servo_GetCustomPropertyNameAt(
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CssUrlData_GetSerialization(
url: &RawServoCssUrlData,
utf8_chars: *mut *const u8,
utf8_len: *mut u32,
) {
let url_data = CssUrlData::as_arc(&url);
let string = url_data.as_str();
*utf8_len = string.len() as u32;
*utf8_chars = string.as_ptr();
}
#[no_mangle]
pub extern "C" fn Servo_CssUrlData_GetExtraData(
url: &RawServoCssUrlData,
) -> &mut URLExtraData {
unsafe { &mut *CssUrlData::as_arc(&url).extra_data.ptr() }
}
#[no_mangle]
pub extern "C" fn Servo_CssUrlData_IsLocalRef(url: &RawServoCssUrlData) -> bool {
CssUrlData::as_arc(&url).is_fragment()
pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
url.is_fragment()
}
#[no_mangle]
@ -6596,3 +6576,8 @@ pub unsafe extern "C" fn Servo_CloneBasicShape(v: &computed::basic_shape::BasicS
pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_LoadData_GetLazy(source: &url::LoadDataSource) -> *const url::LoadData {
source.get()
}

View File

@ -63,7 +63,7 @@ impl StyleStylesheetLoader for StylesheetLoader {
self.1,
self.2,
self.3,
url.0.clone().into_strong(),
&url,
media.into_strong(),
)
};
@ -171,7 +171,7 @@ impl StyleStylesheetLoader for AsyncStylesheetParser {
unsafe {
bindings::Gecko_LoadStyleSheetAsync(
self.load_data.get(),
url.0.into_strong(),
&url,
media.into_strong(),
rule.clone().into_strong(),
);

View File

@ -62,18 +62,18 @@ size_of_test!(
608
);
size_of_test!(test_size_of_computed_image, computed::image::Image, 24);
size_of_test!(test_size_of_specified_image, specified::image::Image, 24);
size_of_test!(test_size_of_computed_image, computed::image::Image, 16);
size_of_test!(test_size_of_specified_image, specified::image::Image, 16);
// FIXME(bz): These can shrink if we move the None_ value inside the
// enum instead of paying an extra word for the Either discriminant.
size_of_test!(
test_size_of_computed_image_layer,
computed::image::ImageLayer,
24
16
);
size_of_test!(
test_size_of_specified_image_layer,
specified::image::ImageLayer,
24
16
);