зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1288302 - Part 3: Add nsStyleImageRequest. r=xidorn,bholley
MozReview-Commit-ID: F763Dv0Nfzp
This commit is contained in:
Родитель
2c0304b286
Коммит
195dbb2d2a
|
@ -25,6 +25,7 @@
|
|||
#include "nsStyleUtil.h"
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -365,6 +366,17 @@ imgRequestProxy* nsCSSValue::GetImageValue(nsIDocument* aDocument) const
|
|||
return mValue.mImage->mRequests.GetWeak(aDocument);
|
||||
}
|
||||
|
||||
already_AddRefed<imgRequestProxy>
|
||||
nsCSSValue::GetPossiblyStaticImageValue(nsIDocument* aDocument,
|
||||
nsPresContext* aPresContext) const
|
||||
{
|
||||
imgRequestProxy* req = GetImageValue(aDocument);
|
||||
if (aPresContext->IsDynamic()) {
|
||||
return do_AddRef(req);
|
||||
}
|
||||
return nsContentUtils::GetStaticRequest(req);
|
||||
}
|
||||
|
||||
nscoord nsCSSValue::GetFixedLength(nsPresContext* aPresContext) const
|
||||
{
|
||||
MOZ_ASSERT(mUnit == eCSSUnit_PhysicalMillimeter,
|
||||
|
|
|
@ -873,6 +873,11 @@ public:
|
|||
// all over.
|
||||
imgRequestProxy* GetImageValue(nsIDocument* aDocument) const;
|
||||
|
||||
// Like GetImageValue, but additionally will pass the imgRequestProxy
|
||||
// through nsContentUtils::GetStaticRequest if aPresContent is static.
|
||||
already_AddRefed<imgRequestProxy> GetPossiblyStaticImageValue(
|
||||
nsIDocument* aDocument, nsPresContext* aPresContext) const;
|
||||
|
||||
nscoord GetFixedLength(nsPresContext* aPresContext) const;
|
||||
nscoord GetPixelLength() const;
|
||||
|
||||
|
|
|
@ -128,13 +128,10 @@ SetImageRequest(function<void(imgRequestProxy*)> aCallback,
|
|||
nsPresContext* aPresContext,
|
||||
const nsCSSValue& aValue)
|
||||
{
|
||||
imgRequestProxy* req = GetImageRequest(aPresContext, aValue);
|
||||
if (aPresContext->IsDynamic()) {
|
||||
aCallback(req);
|
||||
} else {
|
||||
RefPtr<imgRequestProxy> staticReq = nsContentUtils::GetStaticRequest(req);
|
||||
aCallback(staticReq);
|
||||
}
|
||||
RefPtr<imgRequestProxy> req =
|
||||
aValue.GetPossiblyStaticImageValue(aPresContext->Document(),
|
||||
aPresContext);
|
||||
aCallback(req);
|
||||
}
|
||||
|
||||
template<typename ReferenceBox>
|
||||
|
|
|
@ -91,6 +91,21 @@ EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
|
|||
return EqualURIs(uri1, uri2);
|
||||
}
|
||||
|
||||
static bool
|
||||
DefinitelyEqualImages(nsStyleImageRequest* aRequest1,
|
||||
nsStyleImageRequest* aRequest2)
|
||||
{
|
||||
if (aRequest1 == aRequest2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aRequest1 || !aRequest2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aRequest1->DefinitelyEquals(*aRequest2);
|
||||
}
|
||||
|
||||
// A nullsafe wrapper for strcmp. We depend on null-safety.
|
||||
static int
|
||||
safe_strcmp(const char16_t* a, const char16_t* b)
|
||||
|
@ -1869,6 +1884,174 @@ nsStyleGradient::HasCalc()
|
|||
mRadiusX.IsCalcUnit() || mRadiusY.IsCalcUnit();
|
||||
}
|
||||
|
||||
|
||||
// --------------------
|
||||
// nsStyleImageRequest
|
||||
|
||||
/**
|
||||
* Runnable to release the nsStyleImageRequest's mRequestProxy,
|
||||
* mImageValue and mImageValue on the main thread, and to perform
|
||||
* any necessary unlocking and untracking of the image.
|
||||
*/
|
||||
class StyleImageRequestCleanupTask : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
typedef nsStyleImageRequest::Mode Mode;
|
||||
|
||||
StyleImageRequestCleanupTask(Mode aModeFlags,
|
||||
already_AddRefed<imgRequestProxy> aRequestProxy,
|
||||
already_AddRefed<css::ImageValue> aImageValue,
|
||||
already_AddRefed<ImageTracker> aImageTracker)
|
||||
: mModeFlags(aModeFlags)
|
||||
, mRequestProxy(aRequestProxy)
|
||||
, mImageValue(aImageValue)
|
||||
, mImageTracker(aImageTracker)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() final
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mRequestProxy) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mImageTracker);
|
||||
|
||||
if (mModeFlags & Mode::Lock) {
|
||||
mRequestProxy->UnlockImage();
|
||||
}
|
||||
|
||||
if (mModeFlags & Mode::Discard) {
|
||||
mRequestProxy->RequestDiscard();
|
||||
}
|
||||
|
||||
if (mModeFlags & Mode::Track) {
|
||||
mImageTracker->Remove(mRequestProxy);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~StyleImageRequestCleanupTask() { MOZ_ASSERT(NS_IsMainThread()); }
|
||||
|
||||
private:
|
||||
Mode mModeFlags;
|
||||
// Since we always dispatch this runnable to the main thread, these will be
|
||||
// released on the main thread when the runnable itself is released.
|
||||
RefPtr<imgRequestProxy> mRequestProxy;
|
||||
RefPtr<css::ImageValue> mImageValue;
|
||||
RefPtr<ImageTracker> mImageTracker;
|
||||
};
|
||||
|
||||
nsStyleImageRequest::nsStyleImageRequest(Mode aModeFlags,
|
||||
imgRequestProxy* aRequestProxy,
|
||||
css::ImageValue* aImageValue,
|
||||
ImageTracker* aImageTracker)
|
||||
: mRequestProxy(aRequestProxy)
|
||||
, mImageValue(aImageValue)
|
||||
, mImageTracker(aImageTracker)
|
||||
, mModeFlags(aModeFlags)
|
||||
, mResolved(true)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRequestProxy);
|
||||
MOZ_ASSERT(aImageValue);
|
||||
MOZ_ASSERT(aImageTracker);
|
||||
|
||||
MaybeTrackAndLock();
|
||||
}
|
||||
|
||||
nsStyleImageRequest::nsStyleImageRequest(
|
||||
Mode aModeFlags,
|
||||
nsStringBuffer* aURLBuffer,
|
||||
already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
|
||||
already_AddRefed<PtrHolder<nsIURI>> aReferrer,
|
||||
already_AddRefed<PtrHolder<nsIPrincipal>> aPrincipal)
|
||||
: mModeFlags(aModeFlags)
|
||||
, mResolved(false)
|
||||
{
|
||||
mImageValue = new css::ImageValue(aURLBuffer, Move(aBaseURI),
|
||||
Move(aReferrer), Move(aPrincipal));
|
||||
}
|
||||
|
||||
nsStyleImageRequest::~nsStyleImageRequest()
|
||||
{
|
||||
// We may or may not be being destroyed on the main thread. To clean
|
||||
// up, we must untrack and unlock the image (depending on mModeFlags),
|
||||
// and release mRequestProxy and mImageValue, all on the main thread.
|
||||
{
|
||||
RefPtr<StyleImageRequestCleanupTask> task =
|
||||
new StyleImageRequestCleanupTask(mModeFlags,
|
||||
mRequestProxy.forget(),
|
||||
mImageValue.forget(),
|
||||
mImageTracker.forget());
|
||||
if (NS_IsMainThread()) {
|
||||
task->Run();
|
||||
} else {
|
||||
NS_DispatchToMainThread(task.forget());
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mRequestProxy);
|
||||
MOZ_ASSERT(!mImageValue);
|
||||
MOZ_ASSERT(!mImageTracker);
|
||||
}
|
||||
|
||||
bool
|
||||
nsStyleImageRequest::Resolve(nsPresContext* aPresContext)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsResolved(), "already resolved");
|
||||
|
||||
mResolved = true;
|
||||
|
||||
// For now, just have unique nsCSSValue/ImageValue objects. We should
|
||||
// really store the ImageValue on the Servo specified value, so that we can
|
||||
// share imgRequestProxys that come from the same rule in the same
|
||||
// document.
|
||||
mImageValue->Initialize(aPresContext->Document());
|
||||
|
||||
nsCSSValue value;
|
||||
value.SetImageValue(mImageValue);
|
||||
mRequestProxy = value.GetPossiblyStaticImageValue(aPresContext->Document(),
|
||||
aPresContext);
|
||||
|
||||
if (!mRequestProxy) {
|
||||
// The URL resolution or image load failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
mImageTracker = aPresContext->Document()->ImageTracker();
|
||||
MaybeTrackAndLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleImageRequest::MaybeTrackAndLock()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(IsResolved());
|
||||
MOZ_ASSERT(mRequestProxy);
|
||||
MOZ_ASSERT(mImageTracker);
|
||||
|
||||
if (mModeFlags & Mode::Track) {
|
||||
mImageTracker->Add(mRequestProxy);
|
||||
}
|
||||
|
||||
if (mModeFlags & Mode::Lock) {
|
||||
mRequestProxy->LockImage();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsStyleImageRequest::DefinitelyEquals(const nsStyleImageRequest& aOther) const
|
||||
{
|
||||
return DefinitelyEqualURIs(mImageValue, aOther.mImageValue);
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// CachedBorderImageData
|
||||
//
|
||||
|
|
|
@ -282,6 +282,97 @@ private:
|
|||
nsStyleGradient& operator=(const nsStyleGradient& aOther) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* A wrapper for an imgRequestProxy that supports off-main-thread creation
|
||||
* and equality comparison.
|
||||
*
|
||||
* An nsStyleImageRequest can be created in two ways:
|
||||
*
|
||||
* 1. Using the constructor that takes an imgRequestProxy. This must
|
||||
* be called from the main thread. The nsStyleImageRequest is
|
||||
* immediately considered "resolved", and the get() method that
|
||||
* returns the imgRequestProxy can be called.
|
||||
*
|
||||
* 2. Using the constructor that takes the URL, base URI, referrer
|
||||
* and principal that can be used to inititiate an image load and
|
||||
* produce an imgRequestProxy later. This can be called from
|
||||
* any thread. The nsStyleImageRequest is not considered "resolved"
|
||||
* at this point, and the Resolve() method must be called later
|
||||
* to initiate the image load and make calls to get() valid.
|
||||
*
|
||||
* Calls to TrackImage(), UntrackImage(), LockImage(), UnlockImage() and
|
||||
* RequestDiscard() are made to the imgRequestProxy and ImageTracker as
|
||||
* appropriate, according to the mode flags passed in to the constructor.
|
||||
*
|
||||
* The main thread constructor takes a pointer to the css::ImageValue that
|
||||
* is the specified url() value, while the off-main-thread constructor
|
||||
* creates a new css::ImageValue to represent the url() information passed
|
||||
* to the constructor. This ImageValue is held on to for the comparisons done
|
||||
* in DefinitelyEquals(), so that we don't need to call into the non-OMT-safe
|
||||
* Equals() on the nsIURI objects returned from imgRequestProxy::GetURI().
|
||||
*/
|
||||
class nsStyleImageRequest
|
||||
{
|
||||
public:
|
||||
// Flags describing whether the imgRequestProxy must be tracked in the
|
||||
// ImageTracker, whether LockImage/UnlockImage calls will be made
|
||||
// when obtaining and releasing the imgRequestProxy, and whether
|
||||
// RequestDiscard will be called on release.
|
||||
enum class Mode : uint8_t {
|
||||
Track = 0x1, // used by all except nsCursorImage
|
||||
Lock = 0x2, // used by all except nsStyleContentData
|
||||
Discard = 0x4, // used only by nsCursorImage
|
||||
};
|
||||
|
||||
// Must be called from the main thread.
|
||||
nsStyleImageRequest(Mode aModeFlags,
|
||||
imgRequestProxy* aRequestProxy,
|
||||
mozilla::css::ImageValue* aImageValue,
|
||||
mozilla::dom::ImageTracker* aImageTracker);
|
||||
|
||||
// Can be called from any thread, but Resolve() must be called later
|
||||
// on the main thread before get() can be used.
|
||||
nsStyleImageRequest(
|
||||
Mode aModeFlags,
|
||||
nsStringBuffer* aURLBuffer,
|
||||
already_AddRefed<mozilla::PtrHolder<nsIURI>> aBaseURI,
|
||||
already_AddRefed<mozilla::PtrHolder<nsIURI>> aReferrer,
|
||||
already_AddRefed<mozilla::PtrHolder<nsIPrincipal>> aPrincipal);
|
||||
|
||||
bool Resolve(nsPresContext* aPresContext);
|
||||
bool IsResolved() const { return mResolved; }
|
||||
|
||||
imgRequestProxy* get() {
|
||||
MOZ_ASSERT(IsResolved(), "Resolve() must be called first");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mRequestProxy.get();
|
||||
}
|
||||
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;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsStyleImageRequest);
|
||||
|
||||
private:
|
||||
~nsStyleImageRequest();
|
||||
nsStyleImageRequest& operator=(const nsStyleImageRequest& aOther) = delete;
|
||||
|
||||
void MaybeTrackAndLock();
|
||||
|
||||
RefPtr<imgRequestProxy> mRequestProxy;
|
||||
RefPtr<mozilla::css::ImageValue> mImageValue;
|
||||
RefPtr<mozilla::dom::ImageTracker> mImageTracker;
|
||||
|
||||
Mode mModeFlags;
|
||||
bool mResolved;
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsStyleImageRequest::Mode)
|
||||
|
||||
enum nsStyleImageType {
|
||||
eStyleImageType_Null,
|
||||
eStyleImageType_Image,
|
||||
|
|
Загрузка…
Ссылка в новой задаче