Bug 1119774 (Part 5) - Make it possible to pass a target size to Decoder::AllocateFrame. r=tn
☠☠ backed out by e56e7cffe0f4 ☠ ☠
authorSeth Fowler <seth@mozilla.com>
Mon, 12 Jan 2015 03:24:26 -0800
changeset 249172 560042809ee78b57ed4fa3873c586530ca7fc446
parent 249171 02d04afc91b51ffd0be8ded22595e5bba47286c1
child 249173 2eefd792306d61b25a5215828f1a76da193b1cb7
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1119774
milestone37.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
Bug 1119774 (Part 5) - Make it possible to pass a target size to Decoder::AllocateFrame. r=tn
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/src/Decoder.cpp
image/src/Decoder.h
image/src/ImageMetadata.h
image/src/RasterImage.cpp
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -633,29 +633,29 @@ nsICODecoder::NeedsNewFrame() const
   if (mContainedDecoder) {
     return mContainedDecoder->NeedsNewFrame();
   }
 
   return Decoder::NeedsNewFrame();
 }
 
 nsresult
-nsICODecoder::AllocateFrame()
+nsICODecoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
 {
   nsresult rv;
 
   if (mContainedDecoder) {
-    rv = mContainedDecoder->AllocateFrame();
+    rv = mContainedDecoder->AllocateFrame(aTargetSize);
     mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
     mProgress |= mContainedDecoder->TakeProgress();
     mInvalidRect.Union(mContainedDecoder->TakeInvalidRect());
     return rv;
   }
 
   // Grab a strong ref that we'll later hand over to the contained decoder. This
   // lets us avoid creating a RawAccessFrameRef off-main-thread.
-  rv = Decoder::AllocateFrame();
+  rv = Decoder::AllocateFrame(aTargetSize);
   mRefForContainedDecoder = GetCurrentFrameRef();
   return rv;
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -35,17 +35,18 @@ public:
   // Obtains the height of the icon directory entry
   uint32_t GetRealHeight() const
   {
     return mDirEntry.mHeight == 0 ? 256 : mDirEntry.mHeight;
   }
 
   virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
   virtual void FinishInternal() MOZ_OVERRIDE;
-  virtual nsresult AllocateFrame() MOZ_OVERRIDE;
+  virtual nsresult AllocateFrame(const nsIntSize& aTargetSize
+                                   /* = nsIntSize() */) MOZ_OVERRIDE;
 
 protected:
   virtual bool NeedsNewFrame() const MOZ_OVERRIDE;
 
 private:
   // Writes to the contained decoder and sets the appropriate errors
   // Returns true if there are no errors.
   bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -323,21 +323,28 @@ Decoder::FinishSharedDecoder()
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!HasError()) {
     FinishInternal();
   }
 }
 
 nsresult
-Decoder::AllocateFrame()
+Decoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
 {
   MOZ_ASSERT(mNeedsNewFrame);
 
+  nsIntSize targetSize = aTargetSize;
+  if (targetSize == nsIntSize()) {
+    MOZ_ASSERT(HasSize());
+    targetSize = mImageMetadata.GetSize();
+  }
+
   mCurrentFrame = EnsureFrame(mNewFrameData.mFrameNum,
+                              targetSize,
                               mNewFrameData.mFrameRect,
                               mDecodeFlags,
                               mNewFrameData.mFormat,
                               mNewFrameData.mPaletteDepth,
                               mCurrentFrame.get());
 
   if (mCurrentFrame) {
     // Gather the raw pointers the decoders will use.
@@ -361,16 +368,17 @@ Decoder::AllocateFrame()
     mNeedsToFlushData = true;
   }
 
   return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE;
 }
 
 RawAccessFrameRef
 Decoder::EnsureFrame(uint32_t aFrameNum,
+                     const nsIntSize& aTargetSize,
                      const nsIntRect& aFrameRect,
                      uint32_t aDecodeFlags,
                      SurfaceFormat aFormat,
                      uint8_t aPaletteDepth,
                      imgFrame* aPreviousFrame)
 {
   if (mDataError || NS_FAILED(mFailCode)) {
     return RawAccessFrameRef();
@@ -378,18 +386,18 @@ Decoder::EnsureFrame(uint32_t aFrameNum,
 
   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);
+    return InternalAddFrame(aFrameNum, aTargetSize, 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?");
@@ -410,70 +418,69 @@ Decoder::EnsureFrame(uint32_t aFrameNum,
 
   MOZ_ASSERT(ref, "No ref to current frame?");
 
   // Reinitialize the old frame.
   nsIntSize oldSize = ThebesIntSize(aPreviousFrame->GetImageSize());
   bool nonPremult =
     aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
   if (NS_FAILED(aPreviousFrame->ReinitForDecoder(oldSize, aFrameRect, aFormat,
-                                               aPaletteDepth, nonPremult))) {
+                                                 aPaletteDepth, nonPremult))) {
     NS_WARNING("imgFrame::ReinitForDecoder should succeed");
     mFrameCount = 0;
     aPreviousFrame->Abort();
     return RawAccessFrameRef();
   }
 
   return ref;
 }
 
 RawAccessFrameRef
 Decoder::InternalAddFrame(uint32_t aFrameNum,
+                          const nsIntSize& aTargetSize,
                           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 ||
+  if (aTargetSize.width <= 0 || aTargetSize.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())) {
+  if (!SurfaceCache::CanHold(aTargetSize.ToIntSize())) {
     NS_WARNING("Trying to add frame that's too large for the SurfaceCache");
     return RawAccessFrameRef();
   }
 
   nsRefPtr<imgFrame> frame = new imgFrame();
   bool nonPremult =
     aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
-  if (NS_FAILED(frame->InitForDecoder(imageSize, aFrameRect, aFormat,
+  if (NS_FAILED(frame->InitForDecoder(aTargetSize, aFrameRect, aFormat,
                                       aPaletteDepth, nonPremult))) {
     NS_WARNING("imgFrame::Init should succeed");
     return RawAccessFrameRef();
   }
 
   RawAccessFrameRef ref = frame->RawAccessRef();
   if (!ref) {
     frame->Abort();
     return RawAccessFrameRef();
   }
 
   InsertOutcome outcome =
     SurfaceCache::Insert(frame, ImageKey(mImage.get()),
-                         RasterSurfaceKey(imageSize.ToIntSize(),
+                         RasterSurfaceKey(aTargetSize.ToIntSize(),
                                           aDecodeFlags,
                                           aFrameNum),
                          Lifetime::Persistent);
   if (outcome != InsertOutcome::SUCCESS) {
     // We either hit InsertOutcome::FAILURE, which is a temporary failure due to
     // low memory (we know it's not permanent because we checked CanHold()
     // above), or InsertOutcome::FAILURE_ALREADY_PRESENT, which means that
     // another decoder beat us to decoding this frame. Either way, we should
@@ -599,17 +606,17 @@ Decoder::PostFrameStop(Opacity aFrameOpa
   // If we're not sending partial invalidations, then we send an invalidation
   // here when the first frame is complete.
   if (!mSendPartialInvalidations && !mIsAnimated) {
     mInvalidRect.UnionRect(mInvalidRect, mCurrentFrame->GetRect());
   }
 }
 
 void
-Decoder::PostInvalidation(nsIntRect& aRect)
+Decoder::PostInvalidation(const nsIntRect& aRect)
 {
   // We should be mid-frame
   NS_ABORT_IF_FALSE(mInFrame, "Can't invalidate when not mid-frame!");
   NS_ABORT_IF_FALSE(mCurrentFrame, "Can't invalidate when not mid-frame!");
 
   // Record this invalidation, unless we're not sending partial invalidations
   // or we're past the first frame.
   if (mSendPartialInvalidations && !mIsAnimated) {
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -272,17 +272,17 @@ public:
                     uint32_t width, uint32_t height,
                     gfx::SurfaceFormat format,
                     uint8_t palette_depth = 0);
   virtual bool NeedsNewFrame() const { return mNeedsNewFrame; }
 
 
   // Try to allocate a frame as described in mNewFrameData and return the
   // status code from that attempt. Clears mNewFrameData.
-  virtual nsresult AllocateFrame();
+  virtual nsresult AllocateFrame(const nsIntSize& aTargetSize = nsIntSize());
 
   already_AddRefed<imgFrame> GetCurrentFrame()
   {
     nsRefPtr<imgFrame> frame = mCurrentFrame.get();
     return frame.forget();
   }
 
   RawAccessFrameRef GetCurrentFrameRef()
@@ -347,17 +347,17 @@ protected:
   // this frame.
   void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
                      DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
                      int32_t aTimeout = 0,
                      BlendMethod aBlendMethod = BlendMethod::OVER);
 
   // Called by the decoders when they have a region to invalidate. We may not
   // actually pass these invalidations on right away.
-  void PostInvalidation(nsIntRect& aRect);
+  void PostInvalidation(const nsIntRect& aRect);
 
   // Called by the decoders when they have successfully decoded the image. This
   // may occur as the result of the decoder getting to the appropriate point in
   // the stream, or by us calling FinishInternal().
   //
   // May not be called mid-frame.
   //
   // For animated images, specify the loop count. -1 means loop forever, 0
@@ -374,26 +374,32 @@ protected:
   bool NeedsToFlushData() const { return mNeedsToFlushData; }
 
   /**
    * 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.
+   * @aTargetSize specifies the target size we're decoding to. If we're not
+   * downscaling during decode, this will always be the same as the image's
+   * intrinsic size.
+   *
    * If a non-paletted frame is desired, pass 0 for aPaletteDepth.
    */
   RawAccessFrameRef EnsureFrame(uint32_t aFrameNum,
+                                const nsIntSize& aTargetSize,
                                 const nsIntRect& aFrameRect,
                                 uint32_t aDecodeFlags,
                                 gfx::SurfaceFormat aFormat,
                                 uint8_t aPaletteDepth,
                                 imgFrame* aPreviousFrame);
 
   RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum,
+                                     const nsIntSize& aTargetSize,
                                      const nsIntRect& aFrameRect,
                                      uint32_t aDecodeFlags,
                                      gfx::SurfaceFormat aFormat,
                                      uint8_t aPaletteDepth,
                                      imgFrame* aPreviousFrame);
 
   /*
    * Member variables.
--- a/image/src/ImageMetadata.h
+++ b/image/src/ImageMetadata.h
@@ -46,16 +46,17 @@ public:
       mSize.emplace(nsIntSize(width, height));
       mOrientation.emplace(orientation);
     }
   }
 
   bool HasSize() const { return mSize.isSome(); }
   bool HasOrientation() const { return mOrientation.isSome(); }
 
+  nsIntSize GetSize() const { return *mSize; }
   int32_t GetWidth() const { return mSize->width; }
   int32_t GetHeight() const { return mSize->height; }
   Orientation GetOrientation() const { return *mOrientation; }
 
 private:
   // The hotspot found on cursors, or -1 if none was found.
   int32_t mHotspotX;
   int32_t mHotspotY;
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1329,20 +1329,22 @@ RasterImage::CreateDecoder(const Maybe<n
   decoder->SetSizeDecode(!aSize);
   decoder->SetSendPartialInvalidations(!mHasBeenDecoded);
   decoder->SetImageIsTransient(mTransient);
   decoder->SetDecodeFlags(DecodeFlags(aFlags));
   if (aSize) {
     // 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.
+    // XXX(seth): Note that we call SetSize() and NeedNewFrame() with the
+    // image's intrinsic size, but AllocateFrame with our target size.
     decoder->SetSize(mSize, mOrientation);
     decoder->NeedNewFrame(0, 0, 0, aSize->width, aSize->height,
                           SurfaceFormat::B8G8R8A8);
-    decoder->AllocateFrame();
+    decoder->AllocateFrame(*aSize);
   }
   decoder->SetIterator(mSourceBuffer->Iterator());
 
   // Set a target size for downscale-during-decode if applicable.
   if (mDownscaleDuringDecode && aSize && *aSize != mSize) {
     DebugOnly<nsresult> rv = decoder->SetTargetSize(*aSize);
     MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE,
                "We're downscale-during-decode but decoder doesn't support it?");