Bug 1079627 (Part 4) - Support multiple decoders in the presence of frame preallocation. r=tn a=lmandel
authorSeth Fowler <seth@mozilla.com>
Thu, 15 Jan 2015 15:11:36 -0800
changeset 249807 10510070c482dafaa4e9a7e957d732864bc1b555
parent 249806 83bcdb8506673b2164f3202ed04f589cb3ea0563
child 249808 5586653fe1255091a0a5a0b41673f990321d1619
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
bugs1079627
milestone37.0a2
Bug 1079627 (Part 4) - Support multiple decoders in the presence of frame preallocation. r=tn a=lmandel
image/src/Decoder.cpp
image/src/Decoder.h
image/src/imgFrame.cpp
image/src/imgFrame.h
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -399,28 +399,35 @@ Decoder::EnsureFrame(uint32_t aFrameNum,
     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 and release our reference to it.
-  IntSize prevFrameSize = aPreviousFrame->GetImageSize();
-  SurfaceCache::RemoveSurface(ImageKey(&mImage),
-                              RasterSurfaceKey(prevFrameSize, aDecodeFlags, 0));
-  mFrameCount = 0;
+  // Reset our state.
   mInFrame = false;
-  mCurrentFrame->Abort();
-  mCurrentFrame = RawAccessFrameRef();
+  RawAccessFrameRef ref = Move(mCurrentFrame);
+
+  MOZ_ASSERT(ref, "No ref to current frame?");
 
-  // Add the new frame as usual.
-  return InternalAddFrame(aFrameNum, aFrameRect, aDecodeFlags, aFormat,
-                          aPaletteDepth, nullptr);
+  // 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))) {
+    NS_WARNING("imgFrame::ReinitForDecoder should succeed");
+    mFrameCount = 0;
+    aPreviousFrame->Abort();
+    return RawAccessFrameRef();
+  }
+
+  return ref;
 }
 
 RawAccessFrameRef
 Decoder::InternalAddFrame(uint32_t aFrameNum,
                           const nsIntRect& aFrameRect,
                           uint32_t aDecodeFlags,
                           SurfaceFormat aFormat,
                           uint8_t aPaletteDepth,
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -268,16 +268,28 @@ public:
   }
 
   RawAccessFrameRef GetCurrentFrameRef()
   {
     return mCurrentFrame ? mCurrentFrame->RawAccessRef()
                          : RawAccessFrameRef();
   }
 
+  /**
+   * Writes data to the decoder. Only public for the benefit of nsICODecoder;
+   * other callers should use Decode().
+   *
+   * @param aBuffer buffer containing the data to be written
+   * @param aCount the number of bytes to write
+   *
+   * Any errors are reported by setting the appropriate state on the decoder.
+   */
+  void Write(const char* aBuffer, uint32_t aCount);
+
+
 protected:
   virtual ~Decoder();
 
   /*
    * Internal hooks. Decoder implementations may override these and
    * only these methods.
    */
   virtual void InitInternal();
@@ -359,25 +371,16 @@ protected:
                                 imgFrame* aPreviousFrame);
 
   RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum,
                                      const nsIntRect& aFrameRect,
                                      uint32_t aDecodeFlags,
                                      gfx::SurfaceFormat aFormat,
                                      uint8_t aPaletteDepth,
                                      imgFrame* aPreviousFrame);
-  /**
-   * Writes data to the decoder.
-   *
-   * @param aBuffer buffer containing the data to be written
-   * @param aCount the number of bytes to write
-   *
-   * Any errors are reported by setting the appropriate state on the decoder.
-   */
-  void Write(const char* aBuffer, uint32_t aCount);
 
   /*
    * Member variables.
    *
    */
   nsRefPtr<RasterImage> mImage;
   Maybe<SourceBufferIterator> mIterator;
   RawAccessFrameRef mCurrentFrame;
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -161,16 +161,90 @@ imgFrame::~imgFrame()
   MOZ_ASSERT(mAborted || IsImageCompleteInternal());
 #endif
 
   moz_free(mPalettedImageData);
   mPalettedImageData = nullptr;
 }
 
 nsresult
+imgFrame::ReinitForDecoder(const nsIntSize& aImageSize,
+                           const nsIntRect& aRect,
+                           SurfaceFormat aFormat,
+                           uint8_t aPaletteDepth /* = 0 */,
+                           bool aNonPremult /* = false */)
+{
+  MonitorAutoLock lock(mMonitor);
+
+  if (mDecoded.x != 0 || mDecoded.y != 0 ||
+      mDecoded.width != 0 || mDecoded.height != 0) {
+    MOZ_ASSERT_UNREACHABLE("Shouldn't reinit after write");
+    return NS_ERROR_FAILURE;
+  }
+  if (mAborted) {
+    MOZ_ASSERT_UNREACHABLE("Shouldn't reinit if aborted");
+    return NS_ERROR_FAILURE;
+  }
+  if (mLockCount < 1) {
+    MOZ_ASSERT_UNREACHABLE("Shouldn't reinit unless locked");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Restore everything (except mLockCount, which we need to keep) to how it was
+  // when we were first created.
+  // XXX(seth): This is probably a little excessive, but I want to be *really*
+  // sure that nothing got missed.
+  mDecoded = nsIntRect(0, 0, 0, 0);
+  mTimeout = 100;
+  mDisposalMethod = DisposalMethod::NOT_SPECIFIED;
+  mBlendMethod = BlendMethod::OVER;
+  mHasNoAlpha = false;
+  mAborted = false;
+  mPaletteDepth = 0;
+  mNonPremult = false;
+  mSinglePixel = false;
+  mCompositingFailed = false;
+  mOptimizable = false;
+  mImageSize = IntSize();
+  mSize = IntSize();
+  mOffset = nsIntPoint();
+  mSinglePixelColor = Color();
+
+  // Release all surfaces.
+  mImageSurface = nullptr;
+  mOptSurface = nullptr;
+  mVBuf = nullptr;
+  mVBufPtr = nullptr;
+  moz_free(mPalettedImageData);
+  mPalettedImageData = nullptr;
+
+  // Reinitialize.
+  nsresult rv = InitForDecoder(aImageSize, aRect, aFormat,
+                               aPaletteDepth, aNonPremult);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  // We were locked before; perform the same actions we would've performed when
+  // we originally got locked.
+  if (mImageSurface) {
+    mVBufPtr = mVBuf;
+    return NS_OK;
+  }
+
+  if (!mPalettedImageData) {
+    MOZ_ASSERT_UNREACHABLE("We got optimized somehow during reinit");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Paletted images don't have surfaces, so there's nothing to do.
+  return NS_OK;
+}
+
+nsresult
 imgFrame::InitForDecoder(const nsIntSize& aImageSize,
                          const nsIntRect& aRect,
                          SurfaceFormat aFormat,
                          uint8_t aPaletteDepth /* = 0 */,
                          bool aNonPremult /* = false */)
 {
   // Assert for properties that should be verified by decoders,
   // warn for properties related to bad content.
@@ -1010,19 +1084,17 @@ imgFrame::GetScalingData() const
 void
 imgFrame::Abort()
 {
   MonitorAutoLock lock(mMonitor);
 
   mAborted = true;
 
   // Wake up anyone who's waiting.
-  if (IsImageCompleteInternal()) {
-    mMonitor.NotifyAll();
-  }
+  mMonitor.NotifyAll();
 }
 
 bool
 imgFrame::IsImageComplete() const
 {
   MonitorAutoLock lock(mMonitor);
   return IsImageCompleteInternal();
 }
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -154,16 +154,29 @@ public:
    * more expensive than in the InitForDecoder() case.
    */
   nsresult InitWithDrawable(gfxDrawable* aDrawable,
                             const nsIntSize& aSize,
                             const SurfaceFormat aFormat,
                             GraphicsFilter aFilter,
                             uint32_t aImageFlags);
 
+  /**
+   * Reinitializes an existing imgFrame with new parameters. You must be holding
+   * a RawAccessFrameRef to the imgFrame, and it must never have been written
+   * to, marked finished, or aborted.
+   *
+   * XXX(seth): We will remove this in bug 1117607.
+   */
+  nsresult ReinitForDecoder(const nsIntSize& aImageSize,
+                            const nsIntRect& aRect,
+                            SurfaceFormat aFormat,
+                            uint8_t aPaletteDepth = 0,
+                            bool aNonPremult = false);
+
   DrawableFrameRef DrawableRef();
   RawAccessFrameRef RawAccessRef();
 
   /**
    * Make this imgFrame permanently available for raw access.
    *
    * This is irrevocable, and should be avoided whenever possible, since it
    * prevents this imgFrame from being optimized and makes it impossible for its