Bug 666446, Part 7/10 - Change nsImageLoader to utilize new refresh driver animations to overcome performance issues with animated background images. [r=roc]
authorScott Johnson <sjohnson@mozilla.com>
Wed, 09 Nov 2011 13:39:16 -0800
changeset 80126 9b8cba26cdb30f14037e5d2cc87c397ee2076fef
parent 80125 3ebba3819ae63d0cff3e49fbd5d31ffd0c040b04
child 80127 6c7ff923785f5e14f2a74dcf0aa42033e80654ee
push id323
push userrcampbell@mozilla.com
push dateTue, 15 Nov 2011 21:58:36 +0000
treeherderfx-team@3ea216303184 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs666446
milestone11.0a1
Bug 666446, Part 7/10 - Change nsImageLoader to utilize new refresh driver animations to overcome performance issues with animated background images. [r=roc]
layout/base/nsImageLoader.cpp
layout/base/nsImageLoader.h
--- a/layout/base/nsImageLoader.cpp
+++ b/layout/base/nsImageLoader.cpp
@@ -52,37 +52,35 @@
 #include "nsIFrame.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 
 #include "imgIContainer.h"
 
 #include "nsStyleContext.h"
 #include "nsGkAtoms.h"
+#include "nsLayoutUtils.h"
 
 // Paint forcing
 #include "prenv.h"
 
 NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
 
 nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRUint32 aActions,
                              nsImageLoader *aNextLoader)
   : mFrame(aFrame),
     mActions(aActions),
-    mNextLoader(aNextLoader)
+    mNextLoader(aNextLoader),
+    mRequestRegistered(false)
 {
 }
 
 nsImageLoader::~nsImageLoader()
 {
-  mFrame = nsnull;
-
-  if (mRequest) {
-    mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
-  }
+  Destroy();
 }
 
 /* static */ already_AddRefed<nsImageLoader>
 nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest, 
                       PRUint32 aActions, nsImageLoader *aNextLoader)
 {
   nsRefPtr<nsImageLoader> loader =
     new nsImageLoader(aFrame, aActions, aNextLoader);
@@ -100,49 +98,61 @@ nsImageLoader::Destroy()
   mNextLoader = nsnull;
   while (list) {
     nsRefPtr<nsImageLoader> todestroy = list;
     list = todestroy->mNextLoader;
     todestroy->mNextLoader = nsnull;
     todestroy->Destroy();
   }
 
-  mFrame = nsnull;
-
-  if (mRequest) {
+  if (mRequest && mFrame) {
+    nsLayoutUtils::DeregisterImageRequest(mFrame->PresContext(), mRequest,
+                                          &mRequestRegistered);
     mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
   }
 
+  mFrame = nsnull;
   mRequest = nsnull;
 }
 
 nsresult
 nsImageLoader::Load(imgIRequest *aImage)
 {
   NS_ASSERTION(!mRequest, "can't reuse image loaders");
   NS_ASSERTION(mFrame, "not initialized");
   NS_ASSERTION(aImage, "must have non-null image");
 
   if (!mFrame)
     return NS_ERROR_NOT_INITIALIZED;
 
   if (!aImage)
     return NS_ERROR_FAILURE;
 
+  // Deregister mRequest from the refresh driver, since it is no longer
+  // going to be managed by this nsImageLoader.
+  nsPresContext* presContext = mFrame->PresContext();
+
+  nsLayoutUtils::DeregisterImageRequest(presContext, mRequest,
+                                        &mRequestRegistered);
+
   // Make sure to clone into a temporary, then set mRequest, since
   // cloning may notify and we don't want to trigger paints from this
   // code.
   nsCOMPtr<imgIRequest> newRequest;
   nsresult rv = aImage->Clone(this, getter_AddRefs(newRequest));
   mRequest.swap(newRequest);
+
+  if (mRequest) {
+    nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mRequest,
+                                                  &mRequestRegistered);
+  }
+
   return rv;
 }
 
-                    
-
 NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
                                               imgIContainer *aImage)
 {
   NS_ABORT_IF_FALSE(aImage, "Who's calling us then?");
 
   /* Get requested animation policy from the pres context:
    *   normal = 0
    *   one frame = 1
@@ -169,16 +179,25 @@ NS_IMETHODIMP nsImageLoader::OnStopFrame
     DoReflow();
   }
   if (mActions & ACTION_REDRAW_ON_DECODE) {
     DoRedraw(nsnull);
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP nsImageLoader::OnImageIsAnimated(imgIRequest *aRequest)
+{
+  // Register with the refresh driver now that we are aware that
+  // we are animated.
+  nsLayoutUtils::RegisterImageRequest(mFrame->PresContext(),
+                                      aRequest, &mRequestRegistered);
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsImageLoader::OnStopRequest(imgIRequest *aRequest,
                                            bool aLastPart)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
   if (!mRequest) {
     // We're in the middle of a paint anyway
--- a/layout/base/nsImageLoader.h
+++ b/layout/base/nsImageLoader.h
@@ -79,16 +79,17 @@ public:
            PRUint32 aActions, nsImageLoader *aNextLoader);
 
   NS_DECL_ISUPPORTS
 
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
   NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
   NS_IMETHOD OnStopRequest(imgIRequest *aRequest, bool aLastPart);
+  NS_IMETHOD OnImageIsAnimated(imgIRequest *aRequest);
   // Do not override OnDataAvailable since background images are not
   // displayed incrementally; they are displayed after the entire image
   // has been loaded.
   // Note: Images referenced by the <img> element are displayed
   // incrementally in nsImageFrame.cpp.
 
   // imgIContainerObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD FrameChanged(imgIContainer *aContainer,
@@ -104,9 +105,13 @@ private:
   void DoReflow();
   /* if aDamageRect is nsnull, the whole frame is redrawn. */
   void DoRedraw(const nsRect* aDamageRect);
 
   nsIFrame *mFrame;
   nsCOMPtr<imgIRequest> mRequest;
   PRUint32 mActions;
   nsRefPtr<nsImageLoader> mNextLoader;
+
+  // This is a boolean flag indicating whether or not the current image request
+  // has been registered with the refresh driver.
+  bool mRequestRegistered;
 };