Bug 1343341. When the animated images discarding pref is enabled Remove the lifetime lock on animated images and adjust code in RasterImage to allow animated images to be discarded. r=aosmond
authorTimothy Nikkel <tnikkel@gmail.com>
Mon, 27 Mar 2017 00:17:52 -0500
changeset 551724 189dbcbf21e2a9af235fd2413f253e2fb3287ef8
parent 551723 b94b13d756c19e06fcdb833b3736d3aa920fbaa6
child 551725 e91d83339d9772de459669e8b448427e260be365
push id51151
push usergijskruitbosch@gmail.com
push dateMon, 27 Mar 2017 12:23:52 +0000
reviewersaosmond
bugs1343341
milestone55.0a1
Bug 1343341. When the animated images discarding pref is enabled Remove the lifetime lock on animated images and adjust code in RasterImage to allow animated images to be discarded. r=aosmond Mostly asserts and simple book keeping. The complicated things were in FrameAnimator.
image/RasterImage.cpp
image/RasterImage.h
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -342,16 +342,17 @@ RasterImage::LookupFrame(const IntSize& 
 
   if (result.Type() == MatchType::NOT_FOUND ||
       result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND ||
       ((aFlags & FLAG_SYNC_DECODE) && !result)) {
     // We don't have a copy of this frame, and there's no decoder working on
     // one. (Or we're sync decoding and the existing decoder hasn't even started
     // yet.) Trigger decoding so it'll be available next time.
     MOZ_ASSERT(aPlaybackType != PlaybackType::eAnimated ||
+               gfxPrefs::ImageMemAnimatedDiscardable() ||
                !mAnimationState || mAnimationState->KnownFrameCount() < 1,
                "Animated frames should be locked");
 
     bool ranSync = Decode(requestedSize, aFlags, aPlaybackType);
 
     // If we can or did sync decode, we should already have the frame.
     if (ranSync || (aFlags & FLAG_SYNC_DECODE)) {
       result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType);
@@ -409,17 +410,17 @@ RasterImage::IsOpaque()
 
 NS_IMETHODIMP_(bool)
 RasterImage::WillDrawOpaqueNow()
 {
   if (!IsOpaque()) {
     return false;
   }
 
-  if (mAnimationState) {
+  if (mAnimationState && !gfxPrefs::ImageMemAnimatedDiscardable()) {
     // We never discard frames of animated images.
     return true;
   }
 
   // If we are not locked our decoded data could get discard at any time (ie
   // between the call to this function and when we are asked to draw), so we
   // have to return false if we are unlocked.
   if (IsUnlocked()) {
@@ -753,19 +754,21 @@ RasterImage::SetMetadata(const ImageMeta
     mHasSize = true;
   }
 
   if (mHasSize && aMetadata.HasAnimation() && !mAnimationState) {
     // We're becoming animated, so initialize animation stuff.
     mAnimationState.emplace(mAnimationMode);
     mFrameAnimator = MakeUnique<FrameAnimator>(this, mSize);
 
-    // We don't support discarding animated images (See bug 414259).
-    // Lock the image and throw away the key.
-    LockImage();
+    if (!gfxPrefs::ImageMemAnimatedDiscardable()) {
+      // We don't support discarding animated images (See bug 414259).
+      // Lock the image and throw away the key.
+      LockImage();
+    }
 
     if (!aFromMetadataDecode) {
       // The metadata decode reported that this image isn't animated, but we
       // discovered that it actually was during the full decode. This is a
       // rare failure that only occurs for corrupt images. To recover, we need
       // to discard all existing surfaces and redecode.
       return false;
     }
@@ -1070,35 +1073,37 @@ RasterImage::GetKeys(uint32_t* count, ch
   return mProperties->GetKeys(count, keys);
 }
 
 void
 RasterImage::Discard()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CanDiscard(), "Asked to discard but can't");
-  MOZ_ASSERT(!mAnimationState, "Asked to discard for animated image");
+  MOZ_ASSERT(!mAnimationState || gfxPrefs::ImageMemAnimatedDiscardable(),
+    "Asked to discard for animated image");
 
   // Delete all the decoded frames.
   SurfaceCache::RemoveImage(ImageKey(this));
 
   if (mAnimationState) {
     mAnimationState->UpdateState(mAnimationFinished, this, mSize);
   }
 
   // Notify that we discarded.
   if (mProgressTracker) {
     mProgressTracker->OnDiscard();
   }
 }
 
 bool
 RasterImage::CanDiscard() {
-  return mAllSourceData &&       // ...have the source data...
-         !mAnimationState;       // Can never discard animated images
+  return mAllSourceData &&
+         // Can discard animated images if the pref is set
+         (!mAnimationState || gfxPrefs::ImageMemAnimatedDiscardable());
 }
 
 NS_IMETHODIMP
 RasterImage::StartDecoding(uint32_t aFlags)
 {
   if (mError) {
     return NS_ERROR_FAILURE;
   }
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -316,17 +316,19 @@ private:
 
   void UpdateImageContainer();
 
   // We would like to just check if we have a zero lock count, but we can't do
   // that for animated images because in EnsureAnimExists we lock the image and
   // never unlock so that animated images always have their lock count >= 1. In
   // that case we use our animation consumers count as a proxy for lock count.
   bool IsUnlocked() {
-    return (mLockCount == 0 || (mAnimationState && mAnimationConsumers == 0));
+    return (mLockCount == 0 ||
+            (!gfxPrefs::ImageMemAnimatedDiscardable() &&
+             (mAnimationState && mAnimationConsumers == 0)));
   }
 
   //////////////////////////////////////////////////////////////////////////////
   // Decoding.
   //////////////////////////////////////////////////////////////////////////////
 
   /**
    * Creates and runs a decoder, either synchronously or asynchronously