Bug 1296147 (Part 1) - Add a DrawableSurface smart pointer type to allow lazy surface generation. r=dholbert,edwin

This commit is contained in:
Seth Fowler 2016-08-17 17:50:31 -07:00
Родитель c6c3b7b266
Коммит 8d183cc877
9 изменённых файлов: 162 добавлений и 79 удалений

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

@ -38,11 +38,11 @@ public:
//////////////////////////////////////////////////////////////////////////////
public:
DrawableFrameRef DrawableRef() override;
bool IsFinished() const override;
size_t LogicalSizeInBytes() const override;
protected:
DrawableFrameRef DrawableRef() override;
bool IsLocked() const override { return bool(mLockRef); }
void SetLocked(bool aLocked) override;

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

@ -301,7 +301,8 @@ FrameAnimator::GetCompositedFrame(uint32_t aFrameNum)
// If we have a composited version of this frame, return that.
if (mLastCompositedFrameIndex == int32_t(aFrameNum)) {
return LookupResult(mCompositingFrame->DrawableRef(), MatchType::EXACT);
return LookupResult(DrawableSurface(mCompositingFrame->DrawableRef()),
MatchType::EXACT);
}
// Otherwise return the raw frame. DoBlend is required to ensure that we only
@ -311,7 +312,7 @@ FrameAnimator::GetCompositedFrame(uint32_t aFrameNum)
RasterSurfaceKey(mSize,
DefaultSurfaceFlags(),
aFrameNum));
MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(),
MOZ_ASSERT(!result || !result.Surface()->GetIsPaletted(),
"About to return a paletted frame");
return result;
}
@ -381,7 +382,7 @@ FrameAnimator::GetRawFrame(uint32_t aFrameNum) const
RasterSurfaceKey(mSize,
DefaultSurfaceFlags(),
aFrameNum));
return result ? result.DrawableRef()->RawAccessRef()
return result ? result.Surface()->RawAccessRef()
: RawAccessFrameRef();
}

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

@ -11,6 +11,7 @@
#ifndef mozilla_image_ISurfaceProvider_h
#define mozilla_image_ISurfaceProvider_h
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/NotNull.h"
#include "mozilla/TimeStamp.h"
@ -24,6 +25,7 @@ namespace mozilla {
namespace image {
class CachedSurface;
class DrawableSurface;
/**
* An interface for objects which can either store a surface or dynamically
@ -37,8 +39,8 @@ public:
NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
/// @return a drawable reference to a surface.
virtual DrawableFrameRef DrawableRef() = 0;
/// @return a (potentially lazily computed) drawable reference to a surface.
virtual DrawableSurface Surface();
/// @return true if DrawableRef() will return a completely decoded surface.
virtual bool IsFinished() const = 0;
@ -62,6 +64,9 @@ protected:
virtual ~ISurfaceProvider() { }
/// @return an eagerly computed drawable reference to a surface.
virtual DrawableFrameRef DrawableRef() = 0;
/// @return true if this ISurfaceProvider is locked. (@see SetLocked())
/// Should only be called from SurfaceCache code as it relies on SurfaceCache
/// for synchronization.
@ -74,10 +79,91 @@ protected:
private:
friend class CachedSurface;
friend class DrawableSurface;
AvailabilityState mAvailability;
};
/**
* A reference to a surface (stored in an imgFrame) that holds the surface in
* memory, guaranteeing that it can be drawn. If you have a DrawableSurface
* |surf| and |if (surf)| returns true, then calls to |surf->Draw()| and
* |surf->GetSurface()| are guaranteed to succeed.
*
* Note that the surface may be computed lazily, so a DrawableSurface should not
* be dereferenced (i.e., operator->() should not be called) until you're
* sure that you want to draw it.
*/
class MOZ_STACK_CLASS DrawableSurface final
{
public:
DrawableSurface() : mHaveSurface(false) { }
explicit DrawableSurface(DrawableFrameRef&& aDrawableRef)
: mDrawableRef(Move(aDrawableRef))
, mHaveSurface(bool(mDrawableRef))
{ }
explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
: mProvider(aProvider)
, mHaveSurface(true)
{ }
DrawableSurface(DrawableSurface&& aOther)
: mDrawableRef(Move(aOther.mDrawableRef))
, mProvider(Move(aOther.mProvider))
, mHaveSurface(aOther.mHaveSurface)
{
aOther.mHaveSurface = false;
}
DrawableSurface& operator=(DrawableSurface&& aOther)
{
MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
mDrawableRef = Move(aOther.mDrawableRef);
mProvider = Move(aOther.mProvider);
mHaveSurface = aOther.mHaveSurface;
aOther.mHaveSurface = false;
return *this;
}
explicit operator bool() const { return mHaveSurface; }
imgFrame* operator->() { return DrawableRef().get(); }
private:
DrawableSurface(const DrawableSurface& aOther) = delete;
DrawableSurface& operator=(const DrawableSurface& aOther) = delete;
DrawableFrameRef& DrawableRef()
{
MOZ_ASSERT(mHaveSurface);
// If we weren't created with a DrawableFrameRef directly, we should've been
// created with an ISurfaceProvider which can give us one.
if (!mDrawableRef) {
MOZ_ASSERT(mProvider);
mDrawableRef = mProvider->DrawableRef();
}
MOZ_ASSERT(mDrawableRef);
return mDrawableRef;
}
DrawableFrameRef mDrawableRef;
RefPtr<ISurfaceProvider> mProvider;
bool mHaveSurface;
};
// Surface() is implemented here so that DrawableSurface's definition is visible.
inline DrawableSurface
ISurfaceProvider::Surface()
{
return DrawableSurface(DrawableRef());
}
/**
* An ISurfaceProvider that stores a single surface.
*/
@ -91,7 +177,6 @@ public:
, mSurface(aSurface)
{ }
DrawableFrameRef DrawableRef() override { return mSurface->DrawableRef(); }
bool IsFinished() const override { return mSurface->IsFinished(); }
size_t LogicalSizeInBytes() const override
@ -101,6 +186,7 @@ public:
}
protected:
DrawableFrameRef DrawableRef() override { return mSurface->DrawableRef(); }
bool IsLocked() const override { return bool(mLockRef); }
void SetLocked(bool aLocked) override

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

@ -13,7 +13,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "imgFrame.h"
#include "ISurfaceProvider.h"
namespace mozilla {
namespace image {
@ -44,35 +44,35 @@ public:
}
LookupResult(LookupResult&& aOther)
: mDrawableRef(Move(aOther.mDrawableRef))
: mSurface(Move(aOther.mSurface))
, mMatchType(aOther.mMatchType)
{ }
LookupResult(DrawableFrameRef&& aDrawableRef, MatchType aMatchType)
: mDrawableRef(Move(aDrawableRef))
LookupResult(DrawableSurface&& aSurface, MatchType aMatchType)
: mSurface(Move(aSurface))
, mMatchType(aMatchType)
{
MOZ_ASSERT(!mDrawableRef || !(mMatchType == MatchType::NOT_FOUND ||
mMatchType == MatchType::PENDING),
MOZ_ASSERT(!mSurface || !(mMatchType == MatchType::NOT_FOUND ||
mMatchType == MatchType::PENDING),
"Only NOT_FOUND or PENDING make sense with no surface");
MOZ_ASSERT(mDrawableRef || mMatchType == MatchType::NOT_FOUND ||
mMatchType == MatchType::PENDING,
MOZ_ASSERT(mSurface || mMatchType == MatchType::NOT_FOUND ||
mMatchType == MatchType::PENDING,
"NOT_FOUND or PENDING do not make sense with a surface");
}
LookupResult& operator=(LookupResult&& aOther)
{
MOZ_ASSERT(&aOther != this, "Self-move-assignment is not supported");
mDrawableRef = Move(aOther.mDrawableRef);
mSurface = Move(aOther.mSurface);
mMatchType = aOther.mMatchType;
return *this;
}
DrawableFrameRef& DrawableRef() { return mDrawableRef; }
const DrawableFrameRef& DrawableRef() const { return mDrawableRef; }
DrawableSurface& Surface() { return mSurface; }
const DrawableSurface& Surface() const { return mSurface; }
/// @return true if this LookupResult contains a surface.
explicit operator bool() const { return bool(mDrawableRef); }
explicit operator bool() const { return bool(mSurface); }
/// @return what kind of match this is (exact, substitute, etc.)
MatchType Type() const { return mMatchType; }
@ -80,7 +80,7 @@ public:
private:
LookupResult(const LookupResult&) = delete;
DrawableFrameRef mDrawableRef;
DrawableSurface mSurface;
MatchType mMatchType;
};

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

@ -306,7 +306,7 @@ RasterImage::LookupFrameInternal(uint32_t aFrameNum,
aFrameNum));
}
DrawableFrameRef
DrawableSurface
RasterImage::LookupFrame(uint32_t aFrameNum,
const IntSize& aSize,
uint32_t aFlags)
@ -322,14 +322,14 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
? aSize : mSize;
if (requestedSize.IsEmpty()) {
return DrawableFrameRef(); // Can't decode to a surface of zero size.
return DrawableSurface(); // Can't decode to a surface of zero size.
}
LookupResult result = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
if (!result && !mHasSize) {
// We can't request a decode without knowing our intrinsic size. Give up.
return DrawableFrameRef();
return DrawableSurface();
}
if (result.Type() == MatchType::NOT_FOUND ||
@ -351,21 +351,21 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
if (!result) {
// We still weren't able to get a frame. Give up.
return DrawableFrameRef();
return DrawableSurface();
}
if (result.DrawableRef()->GetCompositingFailed()) {
return DrawableFrameRef();
if (result.Surface()->GetCompositingFailed()) {
return DrawableSurface();
}
MOZ_ASSERT(!result.DrawableRef()->GetIsPaletted(),
MOZ_ASSERT(!result.Surface()->GetIsPaletted(),
"Should not have a paletted frame");
// Sync decoding guarantees that we got the frame, but if it's owned by an
// async decoder that's currently running, the contents of the frame may not
// be available yet. Make sure we get everything.
if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) {
result.DrawableRef()->WaitUntilFinished();
result.Surface()->WaitUntilFinished();
}
// If we could have done some decoding in this function we need to check if
@ -373,11 +373,11 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
// to avoid calling IsAborted if we weren't passed any sync decode flag because
// IsAborted acquires the monitor for the imgFrame.
if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) &&
result.DrawableRef()->IsAborted()) {
return DrawableFrameRef();
result.Surface()->IsAborted()) {
return DrawableSurface();
}
return Move(result.DrawableRef());
return Move(result.Surface());
}
uint32_t
@ -507,20 +507,20 @@ RasterImage::GetFrameInternal(const IntSize& aSize,
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE
DrawableFrameRef frameRef =
DrawableSurface surface =
LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, aFlags);
if (!frameRef) {
if (!surface) {
// The OS threw this frame away and we couldn't redecode it.
return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
}
RefPtr<SourceSurface> frameSurf = frameRef->GetSurface();
RefPtr<SourceSurface> sourceSurface = surface->GetSurface();
if (!frameRef->IsFinished()) {
return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
if (!surface->IsFinished()) {
return MakePair(DrawResult::INCOMPLETE, Move(sourceSurface));
}
return MakePair(DrawResult::SUCCESS, Move(frameSurf));
return MakePair(DrawResult::SUCCESS, Move(sourceSurface));
}
Pair<DrawResult, RefPtr<layers::Image>>
@ -1266,7 +1266,7 @@ RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
}
DrawResult
RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
RasterImage::DrawInternal(DrawableSurface&& aSurface,
gfxContext* aContext,
const IntSize& aSize,
const ImageRegion& aRegion,
@ -1275,11 +1275,11 @@ RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
{
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
ImageRegion region(aRegion);
bool frameIsFinished = aFrameRef->IsFinished();
bool frameIsFinished = aSurface->IsFinished();
// By now we may have a frame with the requested size. If not, we need to
// adjust the drawing parameters accordingly.
IntSize finalSize = aFrameRef->GetImageSize();
IntSize finalSize = aSurface->GetImageSize();
bool couldRedecodeForBetterFrame = false;
if (finalSize != aSize) {
gfx::Size scale(double(aSize.width) / finalSize.width,
@ -1290,7 +1290,7 @@ RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
}
if (!aFrameRef->Draw(aContext, region, aSamplingFilter, aFlags)) {
if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags)) {
RecoverFromInvalidFrames(aSize, aFlags);
return DrawResult::TEMPORARY_ERROR;
}
@ -1342,9 +1342,9 @@ RasterImage::Draw(gfxContext* aContext,
? aFlags
: aFlags & ~FLAG_HIGH_QUALITY_SCALING;
DrawableFrameRef ref =
DrawableSurface surface =
LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, flags);
if (!ref) {
if (!surface) {
// Getting the frame (above) touches the image and kicks off decoding.
if (mDrawStartTime.IsNull()) {
mDrawStartTime = TimeStamp::Now();
@ -1353,9 +1353,9 @@ RasterImage::Draw(gfxContext* aContext,
}
bool shouldRecordTelemetry = !mDrawStartTime.IsNull() &&
ref->IsFinished();
surface->IsFinished();
auto result = DrawInternal(Move(ref), aContext, aSize,
auto result = DrawInternal(Move(surface), aContext, aSize,
aRegion, aSamplingFilter, flags);
if (shouldRecordTelemetry) {

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

@ -22,13 +22,13 @@
#include "imgIContainer.h"
#include "nsIProperties.h"
#include "nsTArray.h"
#include "imgFrame.h"
#include "LookupResult.h"
#include "nsThreadUtils.h"
#include "DecodePool.h"
#include "DecoderFactory.h"
#include "FrameAnimator.h"
#include "ImageMetadata.h"
#include "ISurfaceProvider.h"
#include "Orientation.h"
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
@ -273,7 +273,7 @@ public:
private:
nsresult Init(const char* aMimeType, uint32_t aFlags);
DrawResult DrawInternal(DrawableFrameRef&& aFrameRef,
DrawResult DrawInternal(DrawableSurface&& aSurface,
gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,
@ -288,9 +288,9 @@ private:
LookupResult LookupFrameInternal(uint32_t aFrameNum,
const gfx::IntSize& aSize,
uint32_t aFlags);
DrawableFrameRef LookupFrame(uint32_t aFrameNum,
const nsIntSize& aSize,
uint32_t aFlags);
DrawableSurface LookupFrame(uint32_t aFrameNum,
const nsIntSize& aSize,
uint32_t aFlags);
uint32_t GetCurrentFrameIndex() const;
uint32_t GetRequestedFrameIndex(uint32_t aWhichFrame) const;

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

@ -146,14 +146,14 @@ public:
MOZ_ASSERT(mImageKey, "Must have a valid image key");
}
DrawableFrameRef DrawableRef() const
DrawableSurface GetDrawableSurface() const
{
if (MOZ_UNLIKELY(IsPlaceholder())) {
MOZ_ASSERT_UNREACHABLE("Shouldn't call DrawableRef() on a placeholder");
return DrawableFrameRef();
MOZ_ASSERT_UNREACHABLE("Called GetDrawableSurface() on a placeholder");
return DrawableSurface();
}
return mProvider->DrawableRef();
return mProvider->Surface();
}
void SetLocked(bool aLocked)
@ -199,12 +199,12 @@ public:
aCachedSurface->IsLocked());
if (!aCachedSurface->IsPlaceholder()) {
DrawableFrameRef surfaceRef = aCachedSurface->DrawableRef();
if (surfaceRef) {
counter.SubframeSize() = Some(surfaceRef->GetSize());
DrawableSurface drawableSurface = aCachedSurface->GetDrawableSurface();
if (drawableSurface) {
counter.SubframeSize() = Some(drawableSurface->GetSize());
size_t heap = 0, nonHeap = 0;
surfaceRef->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap);
drawableSurface->AddSizeOfExcludingThis(mMallocSizeOf, heap, nonHeap);
counter.Values().SetDecodedHeap(heap);
counter.Values().SetDecodedNonHeap(nonHeap);
}
@ -221,7 +221,6 @@ public:
private:
nsExpirationState mExpirationState;
RefPtr<ISurfaceProvider> mProvider;
DrawableFrameRef mDrawableRef;
const Cost mCost;
const ImageKey mImageKey;
const SurfaceKey mSurfaceKey;
@ -599,8 +598,8 @@ public:
return LookupResult(MatchType::PENDING);
}
DrawableFrameRef ref = surface->DrawableRef();
if (!ref) {
DrawableSurface drawableSurface = surface->GetDrawableSurface();
if (!drawableSurface) {
// The surface was released by the operating system. Remove the cache
// entry as well.
Remove(surface);
@ -613,7 +612,7 @@ public:
MOZ_ASSERT(surface->GetSurfaceKey() == aSurfaceKey,
"Lookup() not returning an exact match?");
return LookupResult(Move(ref), MatchType::EXACT);
return LookupResult(Move(drawableSurface), MatchType::EXACT);
}
LookupResult LookupBestMatch(const ImageKey aImageKey,
@ -632,7 +631,7 @@ public:
// encounter a performance problem here we can revisit this.
RefPtr<CachedSurface> surface;
DrawableFrameRef ref;
DrawableSurface drawableSurface;
MatchType matchType = MatchType::NOT_FOUND;
while (true) {
Tie(surface, matchType) = cache->LookupBestMatch(aSurfaceKey);
@ -641,8 +640,8 @@ public:
return LookupResult(matchType); // Lookup in the per-image cache missed.
}
ref = surface->DrawableRef();
if (ref) {
drawableSurface = surface->GetDrawableSurface();
if (drawableSurface) {
break;
}
@ -663,7 +662,7 @@ public:
MarkUsed(surface, cache);
}
return LookupResult(Move(ref), matchType);
return LookupResult(Move(drawableSurface), matchType);
}
bool CanHold(const Cost aCost) const

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

@ -212,9 +212,8 @@ struct SurfaceCache
* belongs to.
* @param aSurfaceKey Key data which uniquely identifies the requested
* cache entry.
* @return a LookupResult, which will either contain a
* DrawableFrameRef to a surface, or an empty
* DrawableFrameRef if the cache entry was not found.
* @return a LookupResult which will contain a DrawableSurface
* if the cache entry was found.
*/
static LookupResult Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey);
@ -229,13 +228,11 @@ struct SurfaceCache
* belongs to.
* @param aSurfaceKey Key data which uniquely identifies the requested
* cache entry.
* @return a LookupResult, which will either contain a
* DrawableFrameRef to a surface similar to the
* the one the caller requested, or an empty
* DrawableFrameRef if no acceptable match was found.
* Callers can use LookupResult::IsExactMatch() to check
* whether the returned surface exactly matches
* @aSurfaceKey.
* @return a LookupResult which will contain a DrawableSurface
* if a cache entry similar to the one the caller
* requested could be found. Callers can use
* LookupResult::IsExactMatch() to check whether the
* returned surface exactly matches @aSurfaceKey.
*/
static LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey);

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

@ -872,10 +872,10 @@ VectorImage::Draw(gfxContext* aContext,
// Draw.
if (result) {
RefPtr<SourceSurface> surface = result.DrawableRef()->GetSurface();
if (surface) {
RefPtr<SourceSurface> sourceSurface = result.Surface()->GetSurface();
if (sourceSurface) {
RefPtr<gfxDrawable> svgDrawable =
new gfxSurfaceDrawable(surface, result.DrawableRef()->GetSize());
new gfxSurfaceDrawable(sourceSurface, result.Surface()->GetSize());
Show(svgDrawable, params);
return DrawResult::SUCCESS;
}