Bug 1119774 (Part 7) - Make it possible to pass a target size to Decoder::AllocateFrame. r=tn a=lmandel
authorSeth Fowler <seth@mozilla.com>
Sun, 18 Jan 2015 14:02:14 -0800
changeset 249822 86dd3d6b0ecc4e70fa67e09694c5cf19675e31b8
parent 249821 d6163bef24faa0518bb1306156cb6e4ef09d0acc
child 249823 d55d3ca3e6853d17b3b51de4ed6f03f16e8baa33
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, lmandel
bugs1119774
milestone37.0a2
Bug 1119774 (Part 7) - Make it possible to pass a target size to Decoder::AllocateFrame. r=tn a=lmandel
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/src/Decoder.cpp
image/src/Decoder.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
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -278,17 +278,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()
@@ -390,26 +390,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/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1325,20 +1325,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?");