Bug 786444 - Part 2 - Make imgFrame's lock status a count, not a boolean, so you can lock it multiple times and still be correct. r=jlebar
authorJoe Drew <joe@drew.ca>
Wed, 26 Sep 2012 11:33:06 -0400
changeset 115386 d3b69fe15ac3a98c5184a1c23d7985f2808fd44c
parent 115385 b2dba2108722f301dd8865fa2f0a16551f873db7
child 115387 38277196c0991c92fea1a601199711154e15d918
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs786444
milestone18.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 786444 - Part 2 - Make imgFrame's lock status a count, not a boolean, so you can lock it multiple times and still be correct. r=jlebar Also add a bunch of NS_ABORT_IF_FALSEs that verify that the lock status is always valid.
image/src/imgFrame.cpp
image/src/imgFrame.h
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -104,26 +104,26 @@ static bool ShouldUseImageSurfaces()
 }
 
 imgFrame::imgFrame() :
   mDecoded(0, 0, 0, 0),
   mPalettedImageData(nullptr),
   mSinglePixelColor(0),
   mTimeout(100),
   mDisposalMethod(0), /* imgIContainer::kDisposeNotSpecified */
+  mLockCount(0),
   mBlendMethod(1), /* imgIContainer::kBlendOver */
   mSinglePixel(false),
   mNeverUseDeviceSurface(false),
   mFormatChanged(false),
   mCompositingFailed(false),
   mNonPremult(false),
 #ifdef USE_WIN_SURFACE
   mIsDDBSurface(false),
 #endif
-  mLocked(false),
   mInformedDiscardTracker(false)
 {
   static bool hasCheckedOptimize = false;
   if (!hasCheckedOptimize) {
     if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
       gDisableOptimize = true;
     }
     hasCheckedOptimize = true;
@@ -573,16 +573,18 @@ uint32_t imgFrame::GetImageBytesPerRow()
 
 uint32_t imgFrame::GetImageDataLength() const
 {
   return GetImageBytesPerRow() * mSize.height;
 }
 
 void imgFrame::GetImageData(uint8_t **aData, uint32_t *length) const
 {
+  NS_ABORT_IF_FALSE(mLockCount != 0, "Can't GetImageData unless frame is locked");
+
   if (mImageSurface)
     *aData = mImageSurface->Data();
   else if (mPalettedImageData)
     *aData = mPalettedImageData + PaletteDataLength();
   else
     *aData = nullptr;
 
   *length = GetImageDataLength();
@@ -595,35 +597,44 @@ bool imgFrame::GetIsPaletted() const
 
 bool imgFrame::GetHasAlpha() const
 {
   return mFormat == gfxASurface::ImageFormatARGB32;
 }
 
 void imgFrame::GetPaletteData(uint32_t **aPalette, uint32_t *length) const
 {
+  NS_ABORT_IF_FALSE(mLockCount != 0, "Can't GetPaletteData unless frame is locked");
+
   if (!mPalettedImageData) {
     *aPalette = nullptr;
     *length = 0;
   } else {
     *aPalette = (uint32_t *) mPalettedImageData;
     *length = PaletteDataLength();
   }
 }
 
 nsresult imgFrame::LockImageData()
 {
-  if (mPalettedImageData)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  NS_ABORT_IF_FALSE(!mLocked, "Trying to lock already locked image data.");
-  if (mLocked) {
+  NS_ABORT_IF_FALSE(mLockCount >= 0, "Unbalanced locks and unlocks");
+  if (mLockCount < 0) {
     return NS_ERROR_FAILURE;
   }
-  mLocked = true;
+
+  mLockCount++;
+
+  // If we are not the first lock, there's nothing to do.
+  if (mLockCount != 1) {
+    return NS_OK;
+  }
+
+  // Paletted images don't have surfaces, so there's nothing to do.
+  if (mPalettedImageData)
+    return NS_OK;
 
   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;
 
@@ -654,25 +665,36 @@ nsresult imgFrame::LockImageData()
     mWinSurface->Flush();
 #endif
 
   return NS_OK;
 }
 
 nsresult imgFrame::UnlockImageData()
 {
-  if (mPalettedImageData)
-    return NS_ERROR_NOT_AVAILABLE;
-
-  NS_ABORT_IF_FALSE(mLocked, "Unlocking an unlocked image!");
-  if (!mLocked) {
+  NS_ABORT_IF_FALSE(mLockCount != 0, "Unlocking an unlocked image!");
+  if (mLockCount == 0) {
     return NS_ERROR_FAILURE;
   }
 
-  mLocked = false;
+  mLockCount--;
+
+  NS_ABORT_IF_FALSE(mLockCount >= 0, "Unbalanced locks and unlocks");
+  if (mLockCount < 0) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // If we are not the last lock, there's nothing to do.
+  if (mLockCount != 0) {
+    return NS_OK;
+  }
+
+  // Paletted images don't have surfaces, so there's nothing to do.
+  if (mPalettedImageData)
+    return NS_OK;
 
   // Assume we've been written to.
   if (mImageSurface)
     mImageSurface->MarkDirty();
 
 #ifdef USE_WIN_SURFACE
   if (mWinSurface)
     mWinSurface->MarkDirty();
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -152,26 +152,27 @@ private: // data
   uint8_t*     mPalettedImageData;
 
   // Note that the data stored in gfxRGBA is *non-alpha-premultiplied*.
   gfxRGBA      mSinglePixelColor;
 
   int32_t      mTimeout; // -1 means display forever
   int32_t      mDisposalMethod;
 
+  /** Indicates how many readers currently have locked this frame */
+  int32_t mLockCount;
+
   gfxASurface::gfxImageFormat mFormat;
   uint8_t      mPaletteDepth;
   int8_t       mBlendMethod;
   bool mSinglePixel;
   bool mNeverUseDeviceSurface;
   bool mFormatChanged;
   bool mCompositingFailed;
   bool mNonPremult;
-  /** Indicates if the image data is currently locked */
-  bool mLocked;
 
   /** Have we called DiscardTracker::InformAllocation()? */
   bool mInformedDiscardTracker;
 
 #ifdef XP_WIN
   bool mIsDDBSurface;
 #endif
 };