Bug 1310560 - Part 1: Make cursor use nsStyleImageRequest for url() value storage. r=xidorn
MozReview-Commit-ID: JU76TS3kxbz
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2394,30 +2394,39 @@ nsComputedDOMStyle::SetValueToPosition(
aValueList->AppendCSSValue(valY.forget());
}
void
nsComputedDOMStyle::SetValueToURLValue(const css::URLValueData* aURL,
nsROCSSPrimitiveValue* aValue)
{
- if (aURL && aURL->IsLocalRef()) {
- nsString fragment;
- aURL->GetSourceString(fragment);
- fragment.Insert(u"url(\"", 0);
- fragment.Append(u"\")");
- aValue->SetString(fragment);
- } else {
- nsCOMPtr<nsIURI> url;
- if (aURL && (url = aURL->GetURI())) {
- aValue->SetURI(url);
- } else {
- aValue->SetIdent(eCSSKeyword_none);
+ if (!aURL) {
+ aValue->SetIdent(eCSSKeyword_none);
+ return;
+ }
+
+ // If we have a usable nsIURI in the URLValueData, and the url() wasn't
+ // a fragment-only URL, serialize the nsIURI.
+ if (!aURL->IsLocalRef()) {
+ if (nsIURI* uri = aURL->GetURI()) {
+ aValue->SetURI(uri);
+ return;
}
}
+
+ // Otherwise, serialize the specified URL value.
+ nsAutoString source;
+ aURL->GetSourceString(source);
+
+ nsAutoString url;
+ url.AppendLiteral(u"url(");
+ nsStyleUtil::AppendEscapedCSSString(source, url, '"');
+ url.Append(')');
+ aValue->SetString(url);
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetBackgroundPosition()
{
const nsStyleImageLayers& layers = StyleBackground()->mImage;
return DoGetImageLayerPosition(layers);
}
@@ -4115,21 +4124,18 @@ nsComputedDOMStyle::DoGetCursor()
{
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
const nsStyleUserInterface *ui = StyleUserInterface();
for (const nsCursorImage& item : ui->mCursorImages) {
RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
- nsCOMPtr<nsIURI> uri;
- item.GetImage()->GetURI(getter_AddRefs(uri));
-
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetURI(uri);
+ SetValueToURLValue(item.mImage->GetImageValue(), val);
itemList->AppendCSSValue(val.forget());
if (item.mHaveHotspot) {
RefPtr<nsROCSSPrimitiveValue> valX = new nsROCSSPrimitiveValue;
RefPtr<nsROCSSPrimitiveValue> valY = new nsROCSSPrimitiveValue;
valX->SetNumber(item.mHotspotX);
valY->SetNumber(item.mHotspotY);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -104,24 +104,16 @@ nsConditionalResetStyleData::GetConditio
return data;
}
e = e->mNext;
} while (e);
return nullptr;
}
-// Creates and returns an imgRequestProxy based on the specified
-// value in aValue.
-static imgRequestProxy*
-GetImageRequest(nsPresContext* aPresContext, const nsCSSValue& aValue)
-{
- return aValue.GetImageValue(aPresContext->Document());
-}
-
// Creates an imgRequestProxy based on the specified value in
// aValue and calls aCallback with it. If the nsPresContext
// is static (e.g. for printing), then a static request (i.e.
// showing the first frame, without animation) will be created.
// (The expectation is then that aCallback will set the resulting
// imgRequestProxy in a style struct somewhere.)
static void
SetImageRequest(function<void(imgRequestProxy*)> aCallback,
@@ -137,26 +129,23 @@ SetImageRequest(function<void(imgRequest
static void
SetStyleImageRequest(function<void(nsStyleImageRequest*)> aCallback,
nsPresContext* aPresContext,
const nsCSSValue& aValue,
nsStyleImageRequest::Mode aModeFlags =
nsStyleImageRequest::Mode::Track)
{
SetImageRequest([&](imgRequestProxy* aProxy) {
- RefPtr<nsStyleImageRequest> request;
- if (aProxy) {
- css::ImageValue* imageValue = aValue.GetImageStructValue();
- ImageTracker* imageTracker =
- (aModeFlags & nsStyleImageRequest::Mode::Track)
- ? aPresContext->Document()->ImageTracker()
- : nullptr;
- request =
- new nsStyleImageRequest(aModeFlags, aProxy, imageValue, imageTracker);
- }
+ css::ImageValue* imageValue = aValue.GetImageStructValue();
+ ImageTracker* imageTracker =
+ (aModeFlags & nsStyleImageRequest::Mode::Track)
+ ? aPresContext->Document()->ImageTracker()
+ : nullptr;
+ RefPtr<nsStyleImageRequest> request =
+ new nsStyleImageRequest(aModeFlags, aProxy, imageValue, imageTracker);
aCallback(request);
}, aPresContext, aValue);
}
template<typename ReferenceBox>
static void
SetStyleShapeSourceToCSSValue(StyleShapeSource<ReferenceBox>* aShapeSource,
const nsCSSValue* aValue,
@@ -5098,27 +5087,26 @@ nsRuleNode::ComputeUserInterfaceData(voi
else {
// The parser will never create a list that is *all* URL values --
// that's invalid.
MOZ_ASSERT(cursorUnit == eCSSUnit_List || cursorUnit == eCSSUnit_ListDep,
"unrecognized cursor unit");
const nsCSSValueList* list = cursorValue->GetListValue();
for ( ; list->mValue.GetUnit() == eCSSUnit_Array; list = list->mNext) {
nsCSSValue::Array* arr = list->mValue.GetArrayValue();
- imgRequestProxy* req =
- GetImageRequest(aContext->PresContext(), arr->Item(0));
- if (req) {
+ SetStyleImageRequest([&](nsStyleImageRequest* req) {
nsCursorImage* item = ui->mCursorImages.AppendElement();
- item->SetImage(req);
+ item->mImage = req;
if (arr->Item(1).GetUnit() != eCSSUnit_Null) {
item->mHaveHotspot = true;
item->mHotspotX = arr->Item(1).GetFloatValue();
item->mHotspotY = arr->Item(2).GetFloatValue();
}
- }
+ }, aContext->PresContext(), arr->Item(0),
+ nsStyleImageRequest::Mode::Discard);
}
NS_ASSERTION(list, "Must have non-array value at the end");
NS_ASSERTION(list->mValue.GetUnit() == eCSSUnit_Enumerated,
"Unexpected fallback value at end of cursor list");
ui->mCursor = list->mValue.GetIntValue();
}
}
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1974,21 +1974,22 @@ nsStyleImageRequest::nsStyleImageRequest
ImageTracker* aImageTracker)
: mRequestProxy(aRequestProxy)
, mImageValue(aImageValue)
, mImageTracker(aImageTracker)
, mModeFlags(aModeFlags)
, mResolved(true)
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aRequestProxy);
MOZ_ASSERT(aImageValue);
MOZ_ASSERT(!!(aModeFlags & Mode::Track) == !!aImageTracker);
- MaybeTrackAndLock();
+ if (mRequestProxy) {
+ MaybeTrackAndLock();
+ }
}
nsStyleImageRequest::nsStyleImageRequest(
Mode aModeFlags,
nsStringBuffer* aURLBuffer,
already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
already_AddRefed<PtrHolder<nsIURI>> aReferrer,
already_AddRefed<PtrHolder<nsIPrincipal>> aPrincipal)
@@ -3976,33 +3977,28 @@ nsCursorImage::nsCursorImage()
, mHotspotY(0.0f)
{
}
nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
: mHaveHotspot(aOther.mHaveHotspot)
, mHotspotX(aOther.mHotspotX)
, mHotspotY(aOther.mHotspotY)
+ , mImage(aOther.mImage)
{
- SetImage(aOther.GetImage());
-}
-
-nsCursorImage::~nsCursorImage()
-{
- SetImage(nullptr);
}
nsCursorImage&
nsCursorImage::operator=(const nsCursorImage& aOther)
{
if (this != &aOther) {
mHaveHotspot = aOther.mHaveHotspot;
mHotspotX = aOther.mHotspotX;
mHotspotY = aOther.mHotspotY;
- SetImage(aOther.GetImage());
+ mImage = aOther.mImage;
}
return *this;
}
bool
nsCursorImage::operator==(const nsCursorImage& aOther) const
{
@@ -4010,17 +4006,17 @@ nsCursorImage::operator==(const nsCursor
(mHotspotX == 0 && mHotspotY == 0),
"expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
NS_ASSERTION(aOther.mHaveHotspot ||
(aOther.mHotspotX == 0 && aOther.mHotspotY == 0),
"expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
return mHaveHotspot == aOther.mHaveHotspot &&
mHotspotX == aOther.mHotspotX &&
mHotspotY == aOther.mHotspotY &&
- EqualImages(mImage, aOther.mImage);
+ DefinitelyEqualImages(mImage, aOther.mImage);
}
nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
: mUserInput(StyleUserInput::Auto)
, mUserModify(StyleUserModify::ReadOnly)
, mUserFocus(StyleUserFocus::None)
, mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
, mCursor(NS_STYLE_CURSOR_AUTO)
@@ -4039,16 +4035,29 @@ nsStyleUserInterface::nsStyleUserInterfa
MOZ_COUNT_CTOR(nsStyleUserInterface);
}
nsStyleUserInterface::~nsStyleUserInterface()
{
MOZ_COUNT_DTOR(nsStyleUserInterface);
}
+void
+nsStyleUserInterface::FinishStyle(nsPresContext* aPresContext)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
+
+ for (nsCursorImage& cursor : mCursorImages) {
+ if (cursor.mImage && !cursor.mImage->IsResolved()) {
+ cursor.mImage->Resolve(aPresContext);
+ }
+ }
+}
+
nsChangeHint
nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const
{
nsChangeHint hint = nsChangeHint(0);
if (mCursor != aNewData.mCursor) {
hint |= nsChangeHint_UpdateCursor;
}
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -364,16 +364,18 @@ public:
const imgRequestProxy* get() const {
return const_cast<nsStyleImageRequest*>(this)->get();
}
// Returns whether the ImageValue objects in the two nsStyleImageRequests
// return true from URLValueData::DefinitelyEqualURIs.
bool DefinitelyEquals(const nsStyleImageRequest& aOther) const;
+ mozilla::css::ImageValue* GetImageValue() const { return mImageValue; }
+
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsStyleImageRequest);
private:
~nsStyleImageRequest();
nsStyleImageRequest& operator=(const nsStyleImageRequest& aOther) = delete;
void MaybeTrackAndLock();
@@ -3329,53 +3331,41 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
mozilla::StyleWindowDragging mWindowDragging; // [reset]
uint8_t mWindowShadow; // [reset]
};
struct nsCursorImage
{
bool mHaveHotspot;
float mHotspotX, mHotspotY;
+ RefPtr<nsStyleImageRequest> mImage;
nsCursorImage();
nsCursorImage(const nsCursorImage& aOther);
- ~nsCursorImage();
nsCursorImage& operator=(const nsCursorImage& aOther);
bool operator==(const nsCursorImage& aOther) const;
bool operator!=(const nsCursorImage& aOther) const
{
return !(*this == aOther);
}
- void SetImage(imgIRequest *aImage) {
- if (mImage) {
- mImage->UnlockImage();
- mImage->RequestDiscard();
- }
- mImage = aImage;
- if (mImage) {
- mImage->LockImage();
- }
- }
- imgIRequest* GetImage() const {
- return mImage;
- }
-
-private:
- nsCOMPtr<imgIRequest> mImage;
+ imgRequestProxy* GetImage() const {
+ return mImage->get();
+ }
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface
{
explicit nsStyleUserInterface(StyleStructContext aContext);
nsStyleUserInterface(const nsStyleUserInterface& aOther);
~nsStyleUserInterface();
- void FinishStyle(nsPresContext* aPresContext) {}
+
+ void FinishStyle(nsPresContext* aPresContext);
void* operator new(size_t sz, nsStyleUserInterface* aSelf) { return aSelf; }
void* operator new(size_t sz, nsPresContext* aContext) {
return aContext->PresShell()->
AllocateByObjectID(mozilla::eArenaObjectID_nsStyleUserInterface, sz);
}
void Destroy(nsPresContext* aContext) {
this->~nsStyleUserInterface();
--- a/layout/style/test/test_bug379440.html
+++ b/layout/style/test/test_bug379440.html
@@ -51,20 +51,22 @@ https://bugzilla.mozilla.org/show_bug.cg
<script class="testbody" type="text/javascript">
/** Test for Bug 379440 **/
function cur(id) {
return document.defaultView.getComputedStyle($(id), "").cursor;
}
-is(cur("t1"), "url(\"http://example.com/\"), crosshair",
- "Drop unloadable URIs");
-is(cur("t2"), "crosshair", "Drop unloadable URIs again");
-is(cur("t3"), "url(\"http://example.com/\"), crosshair", "URI + fallback");
+is(cur("t1"), 'url("file:///tmp/foo"), url("file:///c|/"), ' +
+ 'url("http://example.com/"), crosshair',
+ "Serialize unloadable URLs using their specified value");
+is(cur("t2"), 'url("file:///tmp/foo"), url("file:///c|/"), crosshair',
+ "Serialize unloadable URLs using their specified value");
+is(cur("t3"), 'url("http://example.com/"), crosshair', "URI + fallback");
is(cur("t4"), "auto", "Must have a fallback");
is(cur("t5"), "auto", "Fallback must be recognized");
is(cur("t6"), "crosshair", "Just a fallback");
is(cur("t7"), "auto", "Invalid fallback means ignore");
</script>
</pre>
</body>