Bug 1126490 (Part 1) - Recover when catastrophic circumstances cause us to lose frames in RasterImage. r=tn a=lmandel
authorSeth Fowler <seth@mozilla.com>
Tue, 03 Feb 2015 16:38:36 -0800
changeset 249867 231329e7bf6916f6af3597eb9a53ff4603fab3b9
parent 249866 604a1b7d114a6a3394e9628be62b7498bdaebd67
child 249868 c66b97f4d60b2014eca861b599fa71e6abd11fe3
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
bugs1126490
milestone37.0a2
Bug 1126490 (Part 1) - Recover when catastrophic circumstances cause us to lose frames in RasterImage. r=tn a=lmandel
image/src/RasterImage.cpp
image/src/RasterImage.h
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -697,16 +697,21 @@ RasterImage::CopyFrame(uint32_t aWhichFr
   nsIntRect intFrameRect = frameRef->GetRect();
   Rect rect(intFrameRect.x, intFrameRect.y,
             intFrameRect.width, intFrameRect.height);
   if (frameRef->IsSinglePixel()) {
     target->FillRect(rect, ColorPattern(frameRef->SinglePixelColor()),
                      DrawOptions(1.0f, CompositionOp::OP_SOURCE));
   } else {
     RefPtr<SourceSurface> srcSurf = frameRef->GetSurface();
+    if (!srcSurf) {
+      RecoverFromLossOfFrames(mSize, aFlags);
+      return nullptr;
+    }
+
     Rect srcRect(0, 0, intFrameRect.width, intFrameRect.height);
     target->DrawSurface(srcSurf, srcRect, rect);
   }
 
   target->Flush();
   surf->Unmap();
 
   return surf;
@@ -1529,16 +1534,40 @@ RasterImage::Decode(const Maybe<nsIntSiz
   }
 
   // Perform an async decode. We also take this path if we don't have all the
   // source data yet, since sync decoding is impossible in that situation.
   DecodePool::Singleton()->AsyncDecode(decoder);
   return NS_OK;
 }
 
+void
+RasterImage::RecoverFromLossOfFrames(const nsIntSize& aSize, uint32_t aFlags)
+{
+  if (!mHasSize) {
+    return;
+  }
+
+  NS_WARNING("An imgFrame became invalid. Attempting to recover...");
+
+  // Discard all existing frames, since they're probably all now invalid.
+  SurfaceCache::RemoveImage(ImageKey(this));
+
+  // Animated images require some special handling, because we normally require
+  // that they never be discarded.
+  if (mAnim) {
+    Decode(Some(mSize), aFlags | FLAG_SYNC_DECODE);
+    ResetAnimation();
+    return;
+  }
+
+  // For non-animated images, it's fine to recover using an async decode.
+  Decode(Some(aSize), aFlags);
+}
+
 bool
 RasterImage::CanScale(GraphicsFilter aFilter,
                       const nsIntSize& aSize,
                       uint32_t aFlags)
 {
 #ifndef MOZ_ENABLE_SKIA
   // The high-quality scaler requires Skia.
   return false;
@@ -1708,17 +1737,19 @@ RasterImage::DrawWithPreDownscaleIfNeede
   IntSize finalSize = frameRef->GetImageSize();
   if (ThebesIntSize(finalSize) != aSize) {
     gfx::Size scale(double(aSize.width) / finalSize.width,
                     double(aSize.height) / finalSize.height);
     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
     region.Scale(1.0 / scale.width, 1.0 / scale.height);
   }
 
-  frameRef->Draw(aContext, region, aFilter, aFlags);
+  if (!frameRef->Draw(aContext, region, aFilter, aFlags)) {
+    RecoverFromLossOfFrames(aSize, aFlags);
+  }
 }
 
 //******************************************************************************
 /* [noscript] void draw(in gfxContext aContext,
  *                      in gfxGraphicsFilter aFilter,
  *                      [const] in gfxMatrix aUserSpaceToImageSpace,
  *                      [const] in gfxRect aFill,
  *                      [const] in nsIntRect aSubimage,
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -341,16 +341,23 @@ private:
   /**
    * Creates a new decoder with a target size of @aSize and decode flags
    * specified by @aFlags. If a size decode is desired, pass Nothing() for
    * @aSize.
    */
   already_AddRefed<Decoder> CreateDecoder(const Maybe<nsIntSize>& aSize,
                                           uint32_t aFlags);
 
+  /**
+   * In catastrophic circumstances like a GPU driver crash, we may lose our
+   * frames even if they're locked. RecoverFromLossOfFrames discards all
+   * existing frames and redecodes using the provided @aSize and @aFlags.
+   */
+  void RecoverFromLossOfFrames(const nsIntSize& aSize, uint32_t aFlags);
+
 private: // data
   nsIntSize                  mSize;
   Orientation                mOrientation;
 
   nsCOMPtr<nsIProperties>   mProperties;
 
   /// If this image is animated, a FrameAnimator which manages its animation.
   UniquePtr<FrameAnimator> mAnim;