Bug 1288302 - Part 3: Add nsStyleImageRequest. r=xidorn,bholley

MozReview-Commit-ID: F763Dv0Nfzp
This commit is contained in:
Cameron McCormack 2016-10-20 08:36:21 +08:00
Родитель 0387dc2875
Коммит 2216900ad3
5 изменённых файлов: 295 добавлений и 7 удалений

Просмотреть файл

@ -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,

Просмотреть файл

@ -869,6 +869,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>

Просмотреть файл

@ -93,6 +93,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)
@ -1871,6 +1886,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
//

Просмотреть файл

@ -287,6 +287,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,