Bug 594771 - Reset animations when .src changes. r=joe,bz a=blocking-final
authorAlon Zakai <azakai@mozilla.com>
Wed, 26 Jan 2011 10:52:48 -0800
changeset 61327 13651d82b77fd0f4c6c8954dc0cfcee3fbfe6104
parent 61326 256fe61e0caa23f4868cc911b1ca49c21e71c4b5
child 61328 1044b021f34c8980e8a82ab1cd04a8a580819a4e
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersjoe, bz, blocking-final
bugs594771
milestone2.0b11pre
Bug 594771 - Reset animations when .src changes. r=joe,bz a=blocking-final
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsImageLoadingContent.h
content/html/content/src/nsHTMLImageElement.cpp
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -109,16 +109,19 @@ nsImageLoadingContent::nsImageLoadingCon
     mLoadingEnabled(PR_TRUE),
     mIsImageStateForced(PR_FALSE),
     mLoading(PR_FALSE),
     // mBroken starts out true, since an image without a URI is broken....
     mBroken(PR_TRUE),
     mUserDisabled(PR_FALSE),
     mSuppressed(PR_FALSE),
     mBlockingOnload(PR_FALSE),
+    mNewRequestsWillNeedAnimationReset(PR_FALSE),
+    mPendingRequestNeedsResetAnimation(PR_FALSE),
+    mCurrentRequestNeedsResetAnimation(PR_FALSE),
     mStateChangerDepth(0)
 {
   if (!nsContentUtils::GetImgLoader()) {
     mLoadingEnabled = PR_FALSE;
   }
 }
 
 void
@@ -276,20 +279,30 @@ nsImageLoadingContent::OnStopDecode(imgI
 
   // Our state may change. Watch it.
   AutoStateChanger changer(this, PR_TRUE);
 
   // If the pending request is loaded, switch to it.
   if (aRequest == mPendingRequest) {
     PrepareCurrentRequest() = mPendingRequest;
     mPendingRequest = nsnull;
+    mCurrentRequestNeedsResetAnimation = mPendingRequestNeedsResetAnimation;
+    mPendingRequestNeedsResetAnimation = PR_FALSE;
   }
   NS_ABORT_IF_FALSE(aRequest == mCurrentRequest,
                     "One way or another, we should be current by now");
 
+  if (mCurrentRequestNeedsResetAnimation) {
+    nsCOMPtr<imgIContainer> container;
+    mCurrentRequest->GetImage(getter_AddRefs(container));
+    if (container)
+      container->ResetAnimation();
+    mCurrentRequestNeedsResetAnimation = PR_FALSE;
+  }
+
   // We just loaded all the data we're going to get. If we haven't done an
   // initial paint, we want to make sure the image starts decoding for 2
   // reasons:
   //
   // 1) This image is sitting idle but might need to be decoded as soon as we
   // start painting, in which case we've wasted time.
   //
   // 2) We want to block onload until all visible images are decoded. We do this
@@ -909,26 +922,30 @@ nsImageLoadingContent::PrepareCurrentReq
 {
   // Blocked images go through SetBlockedRequest, which is a separate path. For
   // everything else, we're unblocked.
   mImageBlockingStatus = nsIContentPolicy::ACCEPT;
 
   // Get rid of anything that was there previously.
   ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED);
 
+  mCurrentRequestNeedsResetAnimation = mNewRequestsWillNeedAnimationReset;
+
   // Return a reference.
   return mCurrentRequest;
 }
 
 nsCOMPtr<imgIRequest>&
 nsImageLoadingContent::PreparePendingRequest()
 {
   // Get rid of anything that was there previously.
   ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED);
 
+  mPendingRequestNeedsResetAnimation = mNewRequestsWillNeedAnimationReset;
+
   // Return a reference.
   return mPendingRequest;
 }
 
 void
 nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
 {
   if (!mCurrentRequest) {
@@ -939,30 +956,32 @@ nsImageLoadingContent::ClearCurrentReque
   }
   NS_ABORT_IF_FALSE(!mCurrentURI,
                     "Shouldn't have both mCurrentRequest and mCurrentURI!");
 
   // Clean up the request.
   UntrackImage(mCurrentRequest);
   mCurrentRequest->CancelAndForgetObserver(aReason);
   mCurrentRequest = nsnull;
+  mCurrentRequestNeedsResetAnimation = PR_FALSE;
 
   // We only block onload during the decoding of "current" images. This one is
   // going away, so we should unblock unconditionally here.
   SetBlockingOnload(PR_FALSE);
 }
 
 void
 nsImageLoadingContent::ClearPendingRequest(nsresult aReason)
 {
   if (!mPendingRequest)
     return;
   UntrackImage(mPendingRequest);
   mPendingRequest->CancelAndForgetObserver(aReason);
   mPendingRequest = nsnull;
+  mPendingRequestNeedsResetAnimation = PR_FALSE;
 }
 
 bool
 nsImageLoadingContent::HaveSize(imgIRequest *aImage)
 {
   // Handle the null case
   if (!aImage)
     return false;
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -334,13 +334,28 @@ private:
   PRPackedBool mUserDisabled : 1;
   PRPackedBool mSuppressed : 1;
 
   /**
    * Whether we're currently blocking document load.
    */
   PRPackedBool mBlockingOnload : 1;
 
+protected:
+  /**
+   * A hack to get animations to reset, see bug 594771. On requests
+   * that originate from setting .src, we mark them for needing their animation
+   * reset when they are ready. mNewRequestsWillNeedAnimationReset is set to
+   * true while preparing such requests (as a hack around needing to change an
+   * interface), and the other two booleans store which of the current
+   * and pending requests are of the sort that need their animation restarted.
+   */
+  PRPackedBool mNewRequestsWillNeedAnimationReset : 1;
+
+private:
+  PRPackedBool mPendingRequestNeedsResetAnimation : 1;
+  PRPackedBool mCurrentRequestNeedsResetAnimation : 1;
+
   /* The number of nested AutoStateChangers currently tracking our state. */
   PRUint8 mStateChangerDepth;
 };
 
 #endif // nsImageLoadingContent_h__
--- a/content/html/content/src/nsHTMLImageElement.cpp
+++ b/content/html/content/src/nsHTMLImageElement.cpp
@@ -505,36 +505,27 @@ nsHTMLImageElement::SetAttr(PRInt32 aNam
 
     // If caller is not chrome and dom.disable_image_src_set is true,
     // prevent setting image.src by exiting early
     if (nsContentUtils::GetBoolPref("dom.disable_image_src_set") &&
         !nsContentUtils::IsCallerChrome()) {
       return NS_OK;
     }
 
-    nsCOMPtr<imgIRequest> oldCurrentRequest = mCurrentRequest;
+    // A hack to get animations to reset. See bug 594771.
+    mNewRequestsWillNeedAnimationReset = PR_TRUE;
 
     // Force image loading here, so that we'll try to load the image from
     // network if it's set to be not cacheable...  If we change things so that
     // the state gets in nsGenericElement's attr-setting happen around this
     // LoadImage call, we could start passing PR_FALSE instead of aNotify
     // here.
     LoadImage(aValue, PR_TRUE, aNotify);
 
-    if (mCurrentRequest && !mPendingRequest &&
-        oldCurrentRequest != mCurrentRequest) {
-      // We have a current request, and it's not the same one as we used
-      // to have, and we have no pending request.  So imglib already had
-      // that image.  Reset the animation on it -- see bug 210001
-      nsCOMPtr<imgIContainer> container;
-      mCurrentRequest->GetImage(getter_AddRefs(container));
-      if (container) {
-        container->ResetAnimation();
-      }
-    }
+    mNewRequestsWillNeedAnimationReset = PR_FALSE;
   }
     
   return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                        aNotify);
 }
 
 nsresult
 nsHTMLImageElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,