author | Seth Fowler <seth@mozilla.com> |
Thu, 08 Jan 2015 00:01:25 -0800 | |
changeset 222731 | 0933c1aef19729d4163d61f8962f11c473a26103 |
parent 222730 | 94bd476efa143f7d07844968a7f9c77f440d0672 |
child 222732 | c96ef32cd8a5852e04e7e3924dd52cd48c709433 |
push id | 28073 |
push user | kwierso@gmail.com |
push date | Fri, 09 Jan 2015 01:08:23 +0000 |
treeherder | mozilla-central@b3f84cf78dc2 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | tn |
bugs | 1116735 |
milestone | 37.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -34,27 +34,32 @@ GetBMPLog() } #endif // Convert from row (1..height) to absolute line (0..height-1) #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1)) #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col) nsBMPDecoder::nsBMPDecoder(RasterImage& aImage) - : Decoder(aImage) -{ - mColors = nullptr; - mRow = nullptr; - mCurPos = mPos = mNumColors = mRowBytes = 0; - mOldLine = mCurLine = 1; // Otherwise decoder will never start - mState = eRLEStateInitial; - mStateData = 0; - mLOH = WIN_V3_HEADER_LENGTH; - mUseAlphaData = mHaveAlphaData = false; -} + : Decoder(aImage) + , mPos(0) + , mLOH(WIN_V3_HEADER_LENGTH) + , mNumColors(0) + , mColors(nullptr) + , mRow(nullptr) + , mRowBytes(0) + , mCurLine(1) // Otherwise decoder will never start. + , mOldLine(1) + , mCurPos(0) + , mState(eRLEStateInitial) + , mStateData(0) + , mProcessedHeader(false) + , mUseAlphaData(false) + , mHaveAlphaData(false) +{ } nsBMPDecoder::~nsBMPDecoder() { delete[] mColors; if (mRow) { moz_free(mRow); } } @@ -322,20 +327,22 @@ nsBMPDecoder::WriteInternal(const char* aCount -= toCopy; aBuffer += toCopy; } // At this point mPos should be >= mLOH unless aBuffer did not have enough // data. In the latter case aCount should be 0. MOZ_ASSERT(mPos >= mLOH || aCount == 0); - // HasSize is called to ensure that if at this point mPos == mLOH but - // we have no data left to process, the next time WriteInternal is called + // mProcessedHeader is checked to ensure that if at this point mPos == mLOH + // but we have no data left to process, the next time WriteInternal is called // we won't enter this condition again. - if (mPos == mLOH && !HasSize()) { + if (mPos == mLOH && !mProcessedHeader) { + mProcessedHeader = true; + ProcessInfoHeader(); PR_LOG(GetBMPLog(), PR_LOG_DEBUG, ("BMP is %lix%lix%lu. compression=%lu\n", mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression)); // Verify we support this bit depth if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 && mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) { PostDataError();
--- a/image/decoders/nsBMPDecoder.h +++ b/image/decoders/nsBMPDecoder.h @@ -89,16 +89,19 @@ private: /// Set mBFH from the raw data in mRawBuf, converting from little-endian /// data to native data as necessary void ProcessFileHeader(); /// Set mBIH from the raw data in mRawBuf, converting from little-endian /// data to native data as necessary void ProcessInfoHeader(); + /// True if we've already processed the BMP header. + bool mProcessedHeader; + // Stores whether the image data may store alpha data, or if // the alpha data is unspecified and filled with a padding byte of 0. // When a 32BPP bitmap is stored in an ICO or CUR file, its 4th byte // is used for alpha transparency. When it is stored in a BMP, its // 4th byte is reserved and is always 0. // Reference: // http://en.wikipedia.org/wiki/ICO_(file_format)#cite_note-9 // Bitmaps where the alpha bytes are all 0 should be fully visible.
--- a/image/src/Decoder.cpp +++ b/image/src/Decoder.cpp @@ -1,21 +1,27 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Decoder.h" + +#include "mozilla/gfx/2D.h" +#include "imgIContainer.h" #include "nsIConsoleService.h" #include "nsIScriptError.h" #include "GeckoProfiler.h" #include "nsServiceManagerUtils.h" #include "nsComponentManagerUtils.h" +using mozilla::gfx::IntSize; +using mozilla::gfx::SurfaceFormat; + namespace mozilla { namespace image { Decoder::Decoder(RasterImage &aImage) : mImage(aImage) , mProgress(NoProgress) , mImageData(nullptr) , mColormap(nullptr) @@ -77,16 +83,17 @@ Decoder::InitSharedDecoder(uint8_t* aIma mImageData = aImageData; mImageDataLength = aImageDataLength; mColormap = aColormap; mColormapSize = aColormapSize; mCurrentFrame = Move(aFrameRef); // We have all the frame data, so we've started the frame. if (!IsSizeDecode()) { + mFrameCount++; PostFrameStart(); } // Implementation-specific initialization InitInternal(); mInitialized = true; } @@ -227,29 +234,29 @@ Decoder::FinishSharedDecoder() } nsresult Decoder::AllocateFrame() { MOZ_ASSERT(mNeedsNewFrame); MOZ_ASSERT(NS_IsMainThread()); - mCurrentFrame = mImage.EnsureFrame(mNewFrameData.mFrameNum, - mNewFrameData.mFrameRect, - mDecodeFlags, - mNewFrameData.mFormat, - mNewFrameData.mPaletteDepth, - mCurrentFrame.get()); + mCurrentFrame = EnsureFrame(mNewFrameData.mFrameNum, + mNewFrameData.mFrameRect, + mDecodeFlags, + mNewFrameData.mFormat, + mNewFrameData.mPaletteDepth, + mCurrentFrame.get()); if (mCurrentFrame) { // Gather the raw pointers the decoders will use. mCurrentFrame->GetImageData(&mImageData, &mImageDataLength); mCurrentFrame->GetPaletteData(&mColormap, &mColormapSize); - if (mNewFrameData.mFrameNum == mFrameCount) { + if (mNewFrameData.mFrameNum + 1 == mFrameCount) { PostFrameStart(); } } else { PostDataError(); } // Mark ourselves as not needing another frame before talking to anyone else // so they can tell us if they need yet another. @@ -259,16 +266,151 @@ Decoder::AllocateFrame() // be flushed now that we have a frame to decode into. if (mBytesDecoded > 0) { mNeedsToFlushData = true; } return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE; } +RawAccessFrameRef +Decoder::EnsureFrame(uint32_t aFrameNum, + const nsIntRect& aFrameRect, + uint32_t aDecodeFlags, + SurfaceFormat aFormat, + uint8_t aPaletteDepth, + imgFrame* aPreviousFrame) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (mDataError || NS_FAILED(mFailCode)) { + return RawAccessFrameRef(); + } + + MOZ_ASSERT(aFrameNum <= mFrameCount, "Invalid frame index!"); + if (aFrameNum > mFrameCount) { + return RawAccessFrameRef(); + } + + // Adding a frame that doesn't already exist. This is the normal case. + if (aFrameNum == mFrameCount) { + return InternalAddFrame(aFrameNum, aFrameRect, aDecodeFlags, aFormat, + aPaletteDepth, aPreviousFrame); + } + + // We're replacing a frame. It must be the first frame; there's no reason to + // ever replace any other frame, since the first frame is the only one we + // speculatively allocate without knowing what the decoder really needs. + // XXX(seth): I'm not convinced there's any reason to support this at all. We + // should figure out how to avoid triggering this and rip it out. + MOZ_ASSERT(aFrameNum == 0, "Replacing a frame other than the first?"); + MOZ_ASSERT(mFrameCount == 1, "Should have only one frame"); + MOZ_ASSERT(aPreviousFrame, "Need the previous frame to replace"); + if (aFrameNum != 0 || !aPreviousFrame || mFrameCount != 1) { + return RawAccessFrameRef(); + } + + MOZ_ASSERT(!aPreviousFrame->GetRect().IsEqualEdges(aFrameRect) || + aPreviousFrame->GetFormat() != aFormat || + aPreviousFrame->GetPaletteDepth() != aPaletteDepth, + "Replacing first frame with the same kind of frame?"); + + // Remove the old frame from the SurfaceCache. + IntSize prevFrameSize = aPreviousFrame->GetImageSize(); + SurfaceCache::RemoveSurface(ImageKey(&mImage), + RasterSurfaceKey(prevFrameSize, aDecodeFlags, 0)); + mFrameCount = 0; + mInFrame = false; + + // Add the new frame as usual. + return InternalAddFrame(aFrameNum, aFrameRect, aDecodeFlags, aFormat, + aPaletteDepth, nullptr); +} + +RawAccessFrameRef +Decoder::InternalAddFrame(uint32_t aFrameNum, + const nsIntRect& aFrameRect, + uint32_t aDecodeFlags, + SurfaceFormat aFormat, + uint8_t aPaletteDepth, + imgFrame* aPreviousFrame) +{ + MOZ_ASSERT(aFrameNum <= mFrameCount, "Invalid frame index!"); + if (aFrameNum > mFrameCount) { + return RawAccessFrameRef(); + } + + MOZ_ASSERT(mImageMetadata.HasSize()); + nsIntSize imageSize(mImageMetadata.GetWidth(), mImageMetadata.GetHeight()); + if (imageSize.width <= 0 || imageSize.height <= 0 || + aFrameRect.width <= 0 || aFrameRect.height <= 0) { + NS_WARNING("Trying to add frame with zero or negative size"); + return RawAccessFrameRef(); + } + + if (!SurfaceCache::CanHold(imageSize.ToIntSize())) { + NS_WARNING("Trying to add frame that's too large for the SurfaceCache"); + return RawAccessFrameRef(); + } + + nsRefPtr<imgFrame> frame = new imgFrame(); + if (NS_FAILED(frame->InitForDecoder(imageSize, aFrameRect, aFormat, + aPaletteDepth))) { + NS_WARNING("imgFrame::Init should succeed"); + return RawAccessFrameRef(); + } + frame->SetAsNonPremult(aDecodeFlags & + imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA); + + RawAccessFrameRef ref = frame->RawAccessRef(); + if (!ref) { + return RawAccessFrameRef(); + } + + bool succeeded = + SurfaceCache::Insert(frame, ImageKey(&mImage), + RasterSurfaceKey(imageSize.ToIntSize(), + aDecodeFlags, + aFrameNum), + Lifetime::Persistent); + if (!succeeded) { + return RawAccessFrameRef(); + } + + nsIntRect refreshArea; + + if (aFrameNum == 1) { + MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated"); + aPreviousFrame->SetRawAccessOnly(); + + // If we dispose of the first frame by clearing it, then the first frame's + // refresh area is all of itself. + // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR). + DisposalMethod disposalMethod = aPreviousFrame->GetDisposalMethod(); + if (disposalMethod == DisposalMethod::CLEAR || + disposalMethod == DisposalMethod::CLEAR_ALL || + disposalMethod == DisposalMethod::RESTORE_PREVIOUS) { + refreshArea = aPreviousFrame->GetRect(); + } + } + + if (aFrameNum > 0) { + ref->SetRawAccessOnly(); + + // Some GIFs are huge but only have a small area that they animate. We only + // need to refresh that small area when frame 0 comes around again. + refreshArea.UnionRect(refreshArea, frame->GetRect()); + } + + mFrameCount++; + mImage.OnAddedFrame(mFrameCount, refreshArea); + + return ref; +} + void Decoder::SetSizeOnImage() { MOZ_ASSERT(mImageMetadata.HasSize(), "Should have size"); MOZ_ASSERT(mImageMetadata.HasOrientation(), "Should have orientation"); mImage.SetSize(mImageMetadata.GetWidth(), mImageMetadata.GetHeight(), @@ -311,30 +453,23 @@ Decoder::PostHasTransparency() void Decoder::PostFrameStart() { // We shouldn't already be mid-frame NS_ABORT_IF_FALSE(!mInFrame, "Starting new frame but not done with old one!"); // Update our state to reflect the new frame - mFrameCount++; mInFrame = true; // If we just became animated, record that fact. if (mFrameCount > 1) { mIsAnimated = true; mProgress |= FLAG_IS_ANIMATED; } - - // Decoder implementations should only call this method if they successfully - // appended the frame to the image. So mFrameCount should always match that - // reported by the Image. - MOZ_ASSERT(mFrameCount == mImage.GetNumFrames(), - "Decoder frame count doesn't match image's!"); } void Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */, DisposalMethod aDisposalMethod /* = DisposalMethod::KEEP */, int32_t aTimeout /* = 0 */, BlendMethod aBlendMethod /* = BlendMethod::OVER */) {
--- a/image/src/Decoder.h +++ b/image/src/Decoder.h @@ -154,16 +154,21 @@ public: }; void SetDecodeFlags(uint32_t aFlags) { mDecodeFlags = aFlags; } uint32_t GetDecodeFlags() { return mDecodeFlags; } bool HasSize() const { return mImageMetadata.HasSize(); } void SetSizeOnImage(); + void SetSize(const nsIntSize& aSize, const Orientation& aOrientation) + { + PostSize(aSize.width, aSize.height, aOrientation); + } + // Use HistogramCount as an invalid Histogram ID virtual Telemetry::ID SpeedHistogram() { return Telemetry::HistogramCount; } ImageMetadata& GetImageMetadata() { return mImageMetadata; } // Tell the decoder infrastructure to allocate a frame. By default, frame 0 // is created as an ARGB frame with no offset and with size width * height. // If decoders need something different, they must ask for it. @@ -260,16 +265,37 @@ protected: // For animated images, specify the loop count. -1 means loop forever, 0 // means a single iteration, stopping on the last frame. void PostDecodeDone(int32_t aLoopCount = 0); // Data errors are the fault of the source data, decoder errors are our fault void PostDataError(); void PostDecoderError(nsresult aFailCode); + /** + * Ensures that a given frame number exists with the given parameters, and + * returns a RawAccessFrameRef for that frame. + * It is not possible to create sparse frame arrays; you can only append + * frames to the current frame array, or if there is only one frame in the + * array, replace that frame. + * If a non-paletted frame is desired, pass 0 for aPaletteDepth. + */ + RawAccessFrameRef EnsureFrame(uint32_t aFrameNum, + const nsIntRect& aFrameRect, + uint32_t aDecodeFlags, + gfx::SurfaceFormat aFormat, + uint8_t aPaletteDepth, + imgFrame* aPreviousFrame); + + RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum, + const nsIntRect& aFrameRect, + uint32_t aDecodeFlags, + gfx::SurfaceFormat aFormat, + uint8_t aPaletteDepth, + imgFrame* aPreviousFrame); /* * Member variables. * */ RasterImage &mImage; RawAccessFrameRef mCurrentFrame; ImageMetadata mImageMetadata; nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame.
--- a/image/src/FrameAnimator.cpp +++ b/image/src/FrameAnimator.cpp @@ -242,22 +242,16 @@ FrameAnimator::InitAnimationFrameTimeIfN void FrameAnimator::SetAnimationFrameTime(const TimeStamp& aTime) { mCurrentAnimationFrameTime = aTime; } void -FrameAnimator::SetFirstFrameRefreshArea(const nsIntRect& aRect) -{ - mFirstFrameRefreshArea = aRect; -} - -void FrameAnimator::UnionFirstFrameRefreshArea(const nsIntRect& aRect) { mFirstFrameRefreshArea.UnionRect(mFirstFrameRefreshArea, aRect); } uint32_t FrameAnimator::GetCurrentAnimationFrameIndex() const {
--- a/image/src/FrameAnimator.h +++ b/image/src/FrameAnimator.h @@ -95,21 +95,16 @@ public: /** * The animation mode of the image. * * Constants defined in imgIContainer.idl. */ void SetAnimationMode(uint16_t aAnimationMode); /** - * Set the area to refresh when we loop around to the first frame. - */ - void SetFirstFrameRefreshArea(const nsIntRect& aRect); - - /** * Union the area to refresh when we loop around to the first frame with this * rect. */ void UnionFirstFrameRefreshArea(const nsIntRect& aRect); /** * If the animation frame time has not yet been set, set it to * TimeStamp::Now().
--- a/image/src/ImageMetadata.h +++ b/image/src/ImageMetadata.h @@ -37,18 +37,20 @@ public: } void SetLoopCount(int32_t loopcount) { mLoopCount = loopcount; } void SetSize(int32_t width, int32_t height, Orientation orientation) { - mSize.emplace(nsIntSize(width, height)); - mOrientation.emplace(orientation); + if (!HasSize()) { + mSize.emplace(nsIntSize(width, height)); + mOrientation.emplace(orientation); + } } bool HasSize() const { return mSize.isSome(); } bool HasOrientation() const { return mOrientation.isSome(); } int32_t GetWidth() const { return mSize->width; } int32_t GetHeight() const { return mSize->height; } Orientation GetOrientation() const { return *mOrientation; }
--- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -925,110 +925,50 @@ RasterImage::SizeOfDecoded(gfxMemoryLoca size_t n = 0; n += SurfaceCache::SizeOfSurfaces(ImageKey(this), aLocation, aMallocSizeOf); if (mAnim) { n += mAnim->SizeOfCompositingFrames(aLocation, aMallocSizeOf); } return n; } -RawAccessFrameRef -RasterImage::InternalAddFrame(uint32_t aFrameNum, - const nsIntRect& aFrameRect, - uint32_t aDecodeFlags, - SurfaceFormat aFormat, - uint8_t aPaletteDepth, - imgFrame* aPreviousFrame) +void +RasterImage::OnAddedFrame(uint32_t aNewFrameCount, + const nsIntRect& aNewRefreshArea) { - // We assume that we're in the middle of decoding because we unlock the - // previous frame when we create a new frame, and only when decoding do we - // lock frames. - MOZ_ASSERT(mDecoder, "Only decoders may add frames!"); - - MOZ_ASSERT(aFrameNum <= GetNumFrames(), "Invalid frame index!"); - if (aFrameNum > GetNumFrames()) { - return RawAccessFrameRef(); - } - - if (mSize.width <= 0 || mSize.height <= 0) { - NS_WARNING("Trying to add frame with zero or negative size"); - return RawAccessFrameRef(); - } - - if (!SurfaceCache::CanHold(mSize.ToIntSize())) { - NS_WARNING("Trying to add frame that's too large for the SurfaceCache"); - return RawAccessFrameRef(); - } - - nsRefPtr<imgFrame> frame = new imgFrame(); - if (NS_FAILED(frame->InitForDecoder(mSize, aFrameRect, aFormat, - aPaletteDepth))) { - NS_WARNING("imgFrame::Init should succeed"); - return RawAccessFrameRef(); - } - frame->SetAsNonPremult(aDecodeFlags & FLAG_DECODE_NO_PREMULTIPLY_ALPHA); - - RawAccessFrameRef ref = frame->RawAccessRef(); - if (!ref) { - return RawAccessFrameRef(); - } - - bool succeeded = - SurfaceCache::Insert(frame, ImageKey(this), - RasterSurfaceKey(mSize.ToIntSize(), - aDecodeFlags, - aFrameNum), - Lifetime::Persistent); - if (!succeeded) { - return RawAccessFrameRef(); - } - - if (aFrameNum == 1) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT((mFrameCount == 1 && aNewFrameCount == 1) || + mFrameCount < aNewFrameCount, + "Frame count running backwards"); + + mFrameCount = aNewFrameCount; + + if (aNewFrameCount == 2) { // We're becoming animated, so initialize animation stuff. MOZ_ASSERT(!mAnim, "Already have animation state?"); mAnim = MakeUnique<FrameAnimator>(this, mSize.ToIntSize(), mAnimationMode); // We don't support discarding animated images (See bug 414259). // Lock the image and throw away the key. // // Note that this is inefficient, since we could get rid of the source data // too. However, doing this is actually hard, because we're probably // mid-decode, and thus we're decoding out of the source buffer. Since we're // going to fix this anyway later, and since we didn't kill the source data // in the old world either, locking is acceptable for the moment. LockImage(); - MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated"); - aPreviousFrame->SetRawAccessOnly(); - - // If we dispose of the first frame by clearing it, then the first frame's - // refresh area is all of itself. - // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR). - DisposalMethod disposalMethod = aPreviousFrame->GetDisposalMethod(); - if (disposalMethod == DisposalMethod::CLEAR || - disposalMethod == DisposalMethod::CLEAR_ALL || - disposalMethod == DisposalMethod::RESTORE_PREVIOUS) { - mAnim->SetFirstFrameRefreshArea(aPreviousFrame->GetRect()); - } - if (mPendingAnimation && ShouldAnimate()) { StartAnimation(); } } - if (aFrameNum > 0) { - ref->SetRawAccessOnly(); - - // Some GIFs are huge but only have a small area that they animate. We only - // need to refresh that small area when frame 0 comes around again. - mAnim->UnionFirstFrameRefreshArea(frame->GetRect()); + if (aNewFrameCount > 1) { + mAnim->UnionFirstFrameRefreshArea(aNewRefreshArea); } - - mFrameCount++; - return ref; } nsresult RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation) { MOZ_ASSERT(NS_IsMainThread()); mDecodingMonitor.AssertCurrentThreadIn(); @@ -1059,68 +999,16 @@ RasterImage::SetSize(int32_t aWidth, int // Set the size and flag that we have it mSize.SizeTo(aWidth, aHeight); mOrientation = aOrientation; mHasSize = true; return NS_OK; } -RawAccessFrameRef -RasterImage::EnsureFrame(uint32_t aFrameNum, - const nsIntRect& aFrameRect, - uint32_t aDecodeFlags, - SurfaceFormat aFormat, - uint8_t aPaletteDepth, - imgFrame* aPreviousFrame) -{ - if (mError) { - return RawAccessFrameRef(); - } - - MOZ_ASSERT(aFrameNum <= GetNumFrames(), "Invalid frame index!"); - if (aFrameNum > GetNumFrames()) { - return RawAccessFrameRef(); - } - - // Adding a frame that doesn't already exist. This is the normal case. - if (aFrameNum == GetNumFrames()) { - return InternalAddFrame(aFrameNum, aFrameRect, aDecodeFlags, aFormat, - aPaletteDepth, aPreviousFrame); - } - - // We're replacing a frame. It must be the first frame; there's no reason to - // ever replace any other frame, since the first frame is the only one we - // speculatively allocate without knowing what the decoder really needs. - // XXX(seth): I'm not convinced there's any reason to support this at all. We - // should figure out how to avoid triggering this and rip it out. - MOZ_ASSERT(aFrameNum == 0, "Replacing a frame other than the first?"); - MOZ_ASSERT(GetNumFrames() == 1, "Should have only one frame"); - MOZ_ASSERT(aPreviousFrame, "Need the previous frame to replace"); - MOZ_ASSERT(!mAnim, "Shouldn't be animated"); - if (aFrameNum != 0 || !aPreviousFrame || GetNumFrames() != 1) { - return RawAccessFrameRef(); - } - - MOZ_ASSERT(!aPreviousFrame->GetRect().IsEqualEdges(aFrameRect) || - aPreviousFrame->GetFormat() != aFormat || - aPreviousFrame->GetPaletteDepth() != aPaletteDepth, - "Replacing first frame with the same kind of frame?"); - - // Remove the old frame from the SurfaceCache. - IntSize prevFrameSize = aPreviousFrame->GetImageSize(); - SurfaceCache::RemoveSurface(ImageKey(this), - RasterSurfaceKey(prevFrameSize, aDecodeFlags, 0)); - mFrameCount = 0; - - // Add the new frame as usual. - return InternalAddFrame(aFrameNum, aFrameRect, aDecodeFlags, aFormat, - aPaletteDepth, nullptr); -} - void RasterImage::DecodingComplete(imgFrame* aFinalFrame) { MOZ_ASSERT(NS_IsMainThread()); if (mError) { return; } @@ -1626,16 +1514,17 @@ RasterImage::InitDecoder(bool aDoSizeDec // Initialize the decoder mDecoder->SetSizeDecode(aDoSizeDecode); mDecoder->SetDecodeFlags(mFrameDecodeFlags); if (!aDoSizeDecode) { // We already have the size; tell the decoder so it can preallocate a // frame. By default, we create an ARGB frame with no offset. If decoders // need a different type, they need to ask for it themselves. + mDecoder->SetSize(mSize, mOrientation); mDecoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height, SurfaceFormat::B8G8R8A8); mDecoder->AllocateFrame(); } mDecoder->Init(); CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError()); if (!aDoSizeDecode) {
--- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -172,47 +172,42 @@ public: virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; /* Triggers discarding. */ void Discard(); - /* Callbacks for decoders */ + + ////////////////////////////////////////////////////////////////////////////// + // Decoder callbacks. + ////////////////////////////////////////////////////////////////////////////// + + void OnAddedFrame(uint32_t aNewFrameCount, const nsIntRect& aNewRefreshArea); /** Sets the size and inherent orientation of the container. This should only * be called by the decoder. This function may be called multiple times, but * will throw an error if subsequent calls do not match the first. */ nsresult SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation); /** - * Ensures that a given frame number exists with the given parameters, and - * returns a RawAccessFrameRef for that frame. - * It is not possible to create sparse frame arrays; you can only append - * frames to the current frame array, or if there is only one frame in the - * array, replace that frame. - * If a non-paletted frame is desired, pass 0 for aPaletteDepth. + * Number of times to loop the image. + * @note -1 means forever. */ - RawAccessFrameRef EnsureFrame(uint32_t aFrameNum, - const nsIntRect& aFrameRect, - uint32_t aDecodeFlags, - gfx::SurfaceFormat aFormat, - uint8_t aPaletteDepth, - imgFrame* aPreviousFrame); + void SetLoopCount(int32_t aLoopCount); /* notification that the entire image has been decoded */ void DecodingComplete(imgFrame* aFinalFrame); - /** - * Number of times to loop the image. - * @note -1 means forever. - */ - void SetLoopCount(int32_t aLoopCount); + + ////////////////////////////////////////////////////////////////////////////// + // Network callbacks. + ////////////////////////////////////////////////////////////////////////////// /* Add compressed source data to the imgContainer. * * The decoder will use this data, either immediately or at draw time, to * decode the image. * * XXX This method's only caller (WriteToContainer) ignores the return * value. Should this just return void? @@ -304,22 +299,16 @@ private: uint32_t GetCurrentFrameIndex() const; uint32_t GetRequestedFrameIndex(uint32_t aWhichFrame) const; nsIntRect GetFirstFrameRect(); size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const; - RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum, - const nsIntRect& aFrameRect, - uint32_t aDecodeFlags, - gfx::SurfaceFormat aFormat, - uint8_t aPaletteDepth, - imgFrame* aPreviousFrame); nsresult DoImageDataComplete(); already_AddRefed<layers::Image> GetCurrentImage(); void UpdateImageContainer(); enum RequestDecodeType { ASYNCHRONOUS, SYNCHRONOUS_NOTIFY,