Bug 1155332 - If we don't have enough memory to fully decode an image, discard it immediately. r=tn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Thu, 07 May 2015 09:25:12 -0700
changeset 242834 914258721d1f01fb00e242b5b39ddd276c099daf
parent 242833 b6db7c0824d63402fec6a1685bd22cd5def8d9fe
child 242835 3c8a77e2a83faceccbf691f3d2d7d1840c10f989
push id28713
push userkwierso@gmail.com
push dateFri, 08 May 2015 17:06:43 +0000
treeherdermozilla-central@fd5e9b7eec13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1155332
milestone40.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 1155332 - If we don't have enough memory to fully decode an image, discard it immediately. r=tn
image/src/Decoder.cpp
image/src/RasterImage.cpp
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -495,22 +495,25 @@ Decoder::InternalAddFrame(uint32_t aFram
   }
 
   InsertOutcome outcome =
     SurfaceCache::Insert(frame, ImageKey(mImage.get()),
                          RasterSurfaceKey(aTargetSize,
                                           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
-    // abort this decoder rather than treat this as a real error.
+  if (outcome == InsertOutcome::FAILURE) {
+    // We couldn't insert the surface, almost certainly due to low memory. We
+    // treat this as a permanent error to help the system recover; otherwise, we
+    // might just end up attempting to decode this image again immediately.
+    ref->Abort();
+    return RawAccessFrameRef();
+  } else if (outcome == InsertOutcome::FAILURE_ALREADY_PRESENT) {
+    // Another decoder beat us to decoding this frame. We abort this decoder
+    // rather than treat this as a real error.
     mDecodeAborted = true;
     ref->Abort();
     return RawAccessFrameRef();
   }
 
   nsIntRect refreshArea;
 
   if (aFrameNum == 1) {
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1941,16 +1941,32 @@ RasterImage::DoError()
   if (!NS_IsMainThread()) {
     HandleErrorWorker::DispatchIfNeeded(this);
     return;
   }
 
   // Put the container in an error state.
   mError = true;
 
+  // Stop animation and release our FrameAnimator.
+  if (mAnimating) {
+    StopAnimation();
+  }
+  mAnim.release();
+
+  // Release all locks.
+  mLockCount = 0;
+  SurfaceCache::UnlockImage(ImageKey(this));
+
+  // Release all frames from the surface cache.
+  SurfaceCache::RemoveImage(ImageKey(this));
+
+  // Invalidate to get rid of any partially-drawn image content.
+  NotifyProgress(NoProgress, IntRect(0, 0, mSize.width, mSize.height));
+
   // Log our error
   LOG_CONTAINER_ERROR;
 }
 
 /* static */ void
 RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
 {
   nsRefPtr<HandleErrorWorker> worker = new HandleErrorWorker(aImage);