Bug 1118105 - Make SurfaceCache::Insert let you know if you try to insert a duplicate surface. r=dholbert

This commit is contained in:
Seth Fowler 2015-01-11 22:29:35 -08:00
Родитель 9fff103bae
Коммит 9ef0e5680a
3 изменённых файлов: 42 добавлений и 29 удалений

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

@ -368,13 +368,13 @@ Decoder::InternalAddFrame(uint32_t aFrameNum,
return RawAccessFrameRef(); return RawAccessFrameRef();
} }
bool succeeded = InsertOutcome outcome =
SurfaceCache::Insert(frame, ImageKey(&mImage), SurfaceCache::Insert(frame, ImageKey(&mImage),
RasterSurfaceKey(imageSize.ToIntSize(), RasterSurfaceKey(imageSize.ToIntSize(),
aDecodeFlags, aDecodeFlags,
aFrameNum), aFrameNum),
Lifetime::Persistent); Lifetime::Persistent);
if (!succeeded) { if (outcome != InsertOutcome::SUCCESS) {
ref->Abort(); ref->Abort();
return RawAccessFrameRef(); return RawAccessFrameRef();
} }

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

@ -304,19 +304,22 @@ public:
Mutex& GetMutex() { return mMutex; } Mutex& GetMutex() { return mMutex; }
bool Insert(imgFrame* aSurface, InsertOutcome Insert(imgFrame* aSurface,
const Cost aCost, const Cost aCost,
const ImageKey aImageKey, const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey, const SurfaceKey& aSurfaceKey,
Lifetime aLifetime) Lifetime aLifetime)
{ {
MOZ_ASSERT(!Lookup(aImageKey, aSurfaceKey), // If this is a duplicate surface, refuse to replace the original.
"Inserting a duplicate surface into the SurfaceCache"); if (MOZ_UNLIKELY(Lookup(aImageKey, aSurfaceKey))) {
return InsertOutcome::FAILURE_ALREADY_PRESENT;
}
// If this is bigger than we can hold after discarding everything we can, // If this is bigger than we can hold after discarding everything we can,
// refuse to cache it. // refuse to cache it.
if (!CanHoldAfterDiscarding(aCost)) if (MOZ_UNLIKELY(!CanHoldAfterDiscarding(aCost))) {
return false; return InsertOutcome::FAILURE;
}
// Remove elements in order of cost until we can fit this in the cache. Note // Remove elements in order of cost until we can fit this in the cache. Note
// that locked surfaces aren't in mCosts, so we never remove them here. // that locked surfaces aren't in mCosts, so we never remove them here.
@ -341,7 +344,7 @@ public:
if (cache->IsLocked() && aLifetime == Lifetime::Persistent) { if (cache->IsLocked() && aLifetime == Lifetime::Persistent) {
surface->SetLocked(true); surface->SetLocked(true);
if (!surface->IsLocked()) { if (!surface->IsLocked()) {
return false; return InsertOutcome::FAILURE;
} }
} }
@ -350,7 +353,7 @@ public:
cache->Insert(aSurfaceKey, surface); cache->Insert(aSurfaceKey, surface);
StartTracking(surface); StartTracking(surface);
return true; return InsertOutcome::SUCCESS;
} }
void Remove(CachedSurface* aSurface) void Remove(CachedSurface* aSurface)
@ -795,14 +798,14 @@ SurfaceCache::Lookup(const ImageKey aImageKey,
return sInstance->Lookup(aImageKey, aSurfaceKey); return sInstance->Lookup(aImageKey, aSurfaceKey);
} }
/* static */ bool /* static */ InsertOutcome
SurfaceCache::Insert(imgFrame* aSurface, SurfaceCache::Insert(imgFrame* aSurface,
const ImageKey aImageKey, const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey, const SurfaceKey& aSurfaceKey,
Lifetime aLifetime) Lifetime aLifetime)
{ {
if (!sInstance) { if (!sInstance) {
return false; return InsertOutcome::FAILURE;
} }
MutexAutoLock lock(sInstance->GetMutex()); MutexAutoLock lock(sInstance->GetMutex());

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

@ -114,6 +114,12 @@ MOZ_BEGIN_ENUM_CLASS(Lifetime, uint8_t)
Persistent Persistent
MOZ_END_ENUM_CLASS(Lifetime) MOZ_END_ENUM_CLASS(Lifetime)
MOZ_BEGIN_ENUM_CLASS(InsertOutcome, uint8_t)
SUCCESS, // Success (but see Insert documentation).
FAILURE, // Couldn't insert (e.g., for capacity reasons).
FAILURE_ALREADY_PRESENT // A surface with the same key is already present.
MOZ_END_ENUM_CLASS(InsertOutcome)
/** /**
* SurfaceCache is an imagelib-global service that allows caching of temporary * SurfaceCache is an imagelib-global service that allows caching of temporary
* surfaces. Surfaces normally expire from the cache automatically if they go * surfaces. Surfaces normally expire from the cache automatically if they go
@ -173,9 +179,8 @@ struct SurfaceCache
const SurfaceKey& aSurfaceKey); const SurfaceKey& aSurfaceKey);
/** /**
* Insert a surface into the cache. It is an error to call this function * Insert a surface into the cache. If a surface with the same ImageKey and
* without first calling Lookup to verify that the surface is not already in * SurfaceKey is already in the cache, Insert returns FAILURE_ALREADY_PRESENT.
* the cache.
* *
* Each surface in the cache has a lifetime, either Transient or Persistent. * Each surface in the cache has a lifetime, either Transient or Persistent.
* Transient surfaces can expire from the cache at any time. Persistent * Transient surfaces can expire from the cache at any time. Persistent
@ -187,13 +192,14 @@ struct SurfaceCache
* LockImage() gets called. * LockImage() gets called.
* *
* If a surface cannot be rematerialized, it may be important to know whether * If a surface cannot be rematerialized, it may be important to know whether
* it was inserted into the cache successfully. Insert() returns false if it * it was inserted into the cache successfully. Insert() returns FAILURE if it
* failed to insert the surface, which could happen because of capacity * failed to insert the surface, which could happen because of capacity
* reasons, or because it was already freed by the OS. If you aren't inserting * reasons, or because it was already freed by the OS. If you aren't inserting
* a surface with persistent lifetime, or if the surface isn't associated with * a surface with persistent lifetime, or if the surface isn't associated with
* a locked image, the return value is useless: the surface might expire * a locked image, checking for SUCCESS or FAILURE is useless: the surface
* immediately after being inserted, even though Insert() returned true. Thus, * might expire immediately after being inserted, even though Insert()
* most callers do not need to check the return value. * returned SUCCESS. Thus, many callers do not need to check the result of
* Insert() at all.
* *
* @param aTarget The new surface (wrapped in an imgFrame) to insert into * @param aTarget The new surface (wrapped in an imgFrame) to insert into
* the cache. * the cache.
@ -202,14 +208,18 @@ struct SurfaceCache
* @param aLifetime Whether this is a transient surface that can always be * @param aLifetime Whether this is a transient surface that can always be
* allowed to expire, or a persistent surface that * allowed to expire, or a persistent surface that
* shouldn't expire if the image is locked. * shouldn't expire if the image is locked.
* @return false if the surface could not be inserted. Only check this if * @return SUCCESS if the surface was inserted successfully. (But see above
* inserting a persistent surface associated with a locked image (see * for more information about when you should check this.)
* above for more information). * FAILURE if the surface could not be inserted, e.g. for capacity
* reasons. (But see above for more information about when you
* should check this.)
* FAILURE_ALREADY_PRESENT if a surface with the same ImageKey and
* SurfaceKey already exists in the cache.
*/ */
static bool Insert(imgFrame* aSurface, static InsertOutcome Insert(imgFrame* aSurface,
const ImageKey aImageKey, const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey, const SurfaceKey& aSurfaceKey,
Lifetime aLifetime); Lifetime aLifetime);
/** /**
* Checks if a surface of a given size could possibly be stored in the cache. * Checks if a surface of a given size could possibly be stored in the cache.