Bug 545513: Flush surfaces and mark them dirty at the correct points. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Thu, 25 Feb 2010 10:14:30 -0800
changeset 38698 7c7debeec5a2a455216c852cf0ab7fc4416c2074
parent 38697 58c60f220da285f1847dacc839350c1828b8e40d
child 38699 17da12c3ab044f8597f7be6c311308615737766d
child 38703 a63b772a20ada27109f5df5791a0832da576479c
push id11807
push userbschouten@mozilla.com
push dateThu, 25 Feb 2010 18:15:10 +0000
treeherderautoland@7c7debeec5a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs545513
milestone1.9.3a2pre
Bug 545513: Flush surfaces and mark them dirty at the correct points. r=jrmuizel
modules/libpr0n/src/imgContainer.cpp
modules/libpr0n/src/imgFrame.cpp
modules/libpr0n/src/imgFrame.h
--- a/modules/libpr0n/src/imgContainer.cpp
+++ b/modules/libpr0n/src/imgContainer.cpp
@@ -663,41 +663,57 @@ nsresult imgContainer::InternalAddFrameH
 
   nsAutoPtr<imgFrame> frame(aFrame);
 
   if (paletteData && paletteLength)
     frame->GetPaletteData(paletteData, paletteLength);
 
   frame->GetImageData(imageData, imageLength);
 
+  // We are in the middle of decoding. This will be unlocked when we finish the
+  // decoder->Write() call.
+  frame->LockImageData();
+
   mFrames.InsertElementAt(framenum, frame.forget());
 
   return NS_OK;
 }
                                   
 nsresult imgContainer::InternalAddFrame(PRUint32 framenum,
                                         PRInt32 aX, PRInt32 aY,
                                         PRInt32 aWidth, PRInt32 aHeight,
                                         gfxASurface::gfxImageFormat aFormat,
                                         PRUint8 aPaletteDepth,
                                         PRUint8 **imageData,
                                         PRUint32 *imageLength,
                                         PRUint32 **paletteData,
                                         PRUint32 *paletteLength)
 {
+  // 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.
+  NS_ABORT_IF_FALSE(mInDecoder, "Only decoders may add frames!");
+
   NS_ABORT_IF_FALSE(framenum <= mFrames.Length(), "Invalid frame index!");
   if (framenum > mFrames.Length())
     return NS_ERROR_INVALID_ARG;
 
   nsAutoPtr<imgFrame> frame(new imgFrame());
   NS_ENSURE_TRUE(frame, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // We know we are in a decoder. Therefore, we must unlock the previous frame
+  // when we move on to decoding into the next frame.
+  if (mFrames.Length() > 0) {
+    imgFrame *prevframe = mFrames.ElementAt(mFrames.Length() - 1);
+    prevframe->UnlockImageData();
+  }
+
   if (mFrames.Length() == 0) {
     return InternalAddFrameHelper(framenum, frame.forget(), imageData, imageLength, 
                                   paletteData, paletteLength);
   }
 
   if (mFrames.Length() == 1) {
     // Since we're about to add our second frame, initialize animation stuff
     if (!ensureAnimExists())
@@ -2184,20 +2200,38 @@ imgContainer::ShutdownDecoder(eShutdownI
 
 // Writes the data to the decoder, updating the total number of bytes written.
 nsresult
 imgContainer::WriteToDecoder(const char *aBuffer, PRUint32 aCount)
 {
   // We should have a decoder
   NS_ABORT_IF_FALSE(mDecoder, "Trying to write to null decoder!");
 
+  // The decoder will start decoding into the current frame (if we have one).
+  // When it needs to add another frame, we will unlock this frame and lock the
+  // new frame.
+  // Our invariant is that, while in the decoder, the last frame is always
+  // locked, and all others are unlocked.
+  if (mFrames.Length() > 0) {
+    imgFrame *curframe = mFrames.ElementAt(mFrames.Length() - 1);
+    curframe->LockImageData();
+  }
+
   // Write
   mInDecoder = PR_TRUE;
   nsresult rv = mDecoder->Write(aBuffer, aCount);
   mInDecoder = PR_FALSE;
+
+  // We unlock the current frame, even if that frame is different from the
+  // frame we entered the decoder with. (See above.)
+  if (mFrames.Length() > 0) {
+    imgFrame *curframe = mFrames.ElementAt(mFrames.Length() - 1);
+    curframe->UnlockImageData();
+  }
+
   CONTAINER_ENSURE_SUCCESS(rv);
 
   // Keep track of the total number of bytes written over the lifetime of the
   // decoder
   mBytesDecoded += aCount;
 
   return NS_OK;
 }
--- a/modules/libpr0n/src/imgFrame.cpp
+++ b/modules/libpr0n/src/imgFrame.cpp
@@ -152,16 +152,17 @@ imgFrame::imgFrame() :
   mBlendMethod(1), /* imgIContainer::kBlendOver */
   mSinglePixel(PR_FALSE),
   mNeverUseDeviceSurface(PR_FALSE),
   mFormatChanged(PR_FALSE),
   mCompositingFailed(PR_FALSE)
 #ifdef USE_WIN_SURFACE
   , mIsDDBSurface(PR_FALSE)
 #endif
+  , mLocked(PR_FALSE)
 {
   static PRBool hasCheckedOptimize = PR_FALSE;
   if (!hasCheckedOptimize) {
     if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
       gDisableOptimize = PR_TRUE;
     }
     hasCheckedOptimize = PR_TRUE;
   }
@@ -808,16 +809,22 @@ void imgFrame::GetPaletteData(PRUint32 *
   }
 }
 
 nsresult imgFrame::LockImageData()
 {
   if (mPalettedImageData)
     return NS_ERROR_NOT_AVAILABLE;
 
+  NS_ABORT_IF_FALSE(!mLocked, "Trying to lock already locked image data.");
+  if (mLocked) {
+    return NS_ERROR_FAILURE;
+  }
+  mLocked = PR_TRUE;
+
   if ((mOptSurface || mSinglePixel) && !mImageSurface) {
     // Recover the pixels
     mImageSurface = new gfxImageSurface(gfxIntSize(mSize.width, mSize.height),
                                         gfxImageSurface::ImageFormatARGB32);
     if (!mImageSurface || mImageSurface->CairoStatus())
       return NS_ERROR_OUT_OF_MEMORY;
 
     gfxContext context(mImageSurface);
@@ -840,16 +847,23 @@ nsresult imgFrame::LockImageData()
   return NS_OK;
 }
 
 nsresult imgFrame::UnlockImageData()
 {
   if (mPalettedImageData)
     return NS_ERROR_NOT_AVAILABLE;
 
+  NS_ABORT_IF_FALSE(mLocked, "Unlocking an unlocked image!");
+  if (!mLocked) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mLocked = PR_FALSE;
+
 #ifdef XP_MACOSX
   if (mQuartzSurface)
     mQuartzSurface->Flush();
 #endif
   return NS_OK;
 }
 
 PRInt32 imgFrame::GetTimeout() const
--- a/modules/libpr0n/src/imgFrame.h
+++ b/modules/libpr0n/src/imgFrame.h
@@ -167,16 +167,18 @@ private: // data
 
   gfxASurface::gfxImageFormat mFormat;
   PRInt8       mPaletteDepth;
   PRInt8       mBlendMethod;
   PRPackedBool mSinglePixel;
   PRPackedBool mNeverUseDeviceSurface;
   PRPackedBool mFormatChanged;
   PRPackedBool mCompositingFailed;
+  /** Indicates if the image data is currently locked */
+  PRPackedBool mLocked;
 
 #ifdef XP_WIN
   PRPackedBool mIsDDBSurface;
 #endif
 
 };
 
 #endif /* imgFrame_h */