From a21f368c48496bdc7bf842a6ff89ab4120b6e299 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 5 May 2015 22:19:30 -0700 Subject: [PATCH] Bug 1161859 - Compute the size of animated image frames correctly in the SurfaceCache. r=dholbert, a=lmandel --- image/src/Decoder.cpp | 3 ++- image/src/SurfaceCache.cpp | 11 ++++++----- image/src/SurfaceCache.h | 5 ++++- image/src/imgFrame.h | 8 ++++++++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/image/src/Decoder.cpp b/image/src/Decoder.cpp index cf8cff4976cb..d780ba69f4c7 100644 --- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -470,7 +470,8 @@ Decoder::InternalAddFrame(uint32_t aFrameNum, return RawAccessFrameRef(); } - if (!SurfaceCache::CanHold(aTargetSize.ToIntSize())) { + const uint32_t bytesPerPixel = aPaletteDepth == 0 ? 4 : 1; + if (!SurfaceCache::CanHold(aFrameRect.Size(), bytesPerPixel)) { NS_WARNING("Trying to add frame that's too large for the SurfaceCache"); return RawAccessFrameRef(); } diff --git a/image/src/SurfaceCache.cpp b/image/src/SurfaceCache.cpp index 8da3a2bbd71a..08e70241af0c 100644 --- a/image/src/SurfaceCache.cpp +++ b/image/src/SurfaceCache.cpp @@ -65,9 +65,10 @@ static StaticRefPtr sInstance; */ typedef size_t Cost; -static Cost ComputeCost(const IntSize& aSize) +static Cost ComputeCost(const IntSize& aSize, uint32_t aBytesPerPixel) { - return aSize.width * aSize.height * 4; // width * height * 4 bytes (32bpp) + MOZ_ASSERT(aBytesPerPixel == 1 || aBytesPerPixel == 4); + return aSize.width * aSize.height * aBytesPerPixel; } /** @@ -982,18 +983,18 @@ SurfaceCache::Insert(imgFrame* aSurface, } MutexAutoLock lock(sInstance->GetMutex()); - Cost cost = ComputeCost(aSurfaceKey.Size()); + Cost cost = ComputeCost(aSurface->GetSize(), aSurface->GetBytesPerPixel()); return sInstance->Insert(aSurface, cost, aImageKey, aSurfaceKey, aLifetime); } /* static */ bool -SurfaceCache::CanHold(const IntSize& aSize) +SurfaceCache::CanHold(const IntSize& aSize, uint32_t aBytesPerPixel /* = 4 */) { if (!sInstance) { return false; } - Cost cost = ComputeCost(aSize); + Cost cost = ComputeCost(aSize, aBytesPerPixel); return sInstance->CanHold(cost); } diff --git a/image/src/SurfaceCache.h b/image/src/SurfaceCache.h index 24dada6fdb59..050e5f5195ed 100644 --- a/image/src/SurfaceCache.h +++ b/image/src/SurfaceCache.h @@ -280,10 +280,13 @@ struct SurfaceCache * for sure the cache can't hold it. * * @param aSize The dimensions of a surface in pixels. + * @param aBytesPerPixel How many bytes each pixel of the surface requires. + * Defaults to 4, which is appropriate for RGBA or RGBX + * images. * * @return false if the surface cache can't hold a surface of that size. */ - static bool CanHold(const IntSize& aSize); + static bool CanHold(const IntSize& aSize, uint32_t aBytesPerPixel = 4); static bool CanHold(size_t aSize); /** diff --git a/image/src/imgFrame.h b/image/src/imgFrame.h index 2bb64e02757e..97e318d16bd2 100644 --- a/image/src/imgFrame.h +++ b/image/src/imgFrame.h @@ -237,6 +237,14 @@ public: */ void WaitUntilComplete() const; + /** + * Returns the number of bytes per pixel this imgFrame requires. This is a + * worst-case value that does not take into account the effects of format + * changes caused by Optimize(), since an imgFrame is not optimized throughout + * its lifetime. + */ + uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; } + IntSize GetImageSize() { return mImageSize; } nsIntRect GetRect() const; IntSize GetSize() const { return mSize; }