Bug 647518 part 2. Allow canceling requestAnimationFrame requests. r=roc
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 06 Dec 2011 23:43:18 -0500
changeset 82945 3e232dd3af61794ac5ba8333ff4e57a8521ae808
parent 82944 378505d09d172af1c95d105bce9af2315a680867
child 82946 0aba56de18242e4121aa5b49c4e2c21098b5e113
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs647518
milestone11.0a1
Bug 647518 part 2. Allow canceling requestAnimationFrame requests. r=roc
content/base/public/nsIDocument.h
content/base/src/nsDocument.cpp
content/base/test/test_bug647518.html
dom/base/nsGlobalWindow.cpp
dom/interfaces/base/nsIDOMWindow.idl
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1526,16 +1526,17 @@ public:
    * elements set using mozSetImageElement have higher priority.
    * @param aId the ID associated the element we want to lookup
    * @return the element associated with |aId|
    */
   virtual Element* LookupImageElement(const nsAString& aElementId) = 0;
 
   nsresult ScheduleFrameRequestCallback(nsIFrameRequestCallback* aCallback,
                                         PRInt32 *aHandle);
+  void CancelFrameRequestCallback(PRInt32 aHandle);
 
   typedef nsTArray< nsCOMPtr<nsIFrameRequestCallback> > FrameRequestCallbackList;
   /**
    * Put this document's frame request callbacks into the provided
    * list, and forget about them.
    */
   void TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks);
 
@@ -1827,16 +1828,25 @@ protected:
                  PRInt32 aHandle) :
       mCallback(aCallback),
       mHandle(aHandle)
     {}
 
     // Conversion operator so that we can append these to a
     // FrameRequestCallbackList
     operator nsIFrameRequestCallback* const () const { return mCallback; }
+
+    // Comparator operators to allow RemoveElementSorted with an
+    // integer argument on arrays of FrameRequest
+    bool operator==(PRInt32 aHandle) const {
+      return mHandle == aHandle;
+    }
+    bool operator<(PRInt32 aHandle) const {
+      return mHandle < aHandle;
+    }
     
     nsCOMPtr<nsIFrameRequestCallback> mCallback;
     PRInt32 mHandle;
   };
 
   nsTArray<FrameRequest> mFrameRequestCallbacks;
 
   // This object allows us to evict ourself from the back/forward cache.  The
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8059,16 +8059,27 @@ nsIDocument::ScheduleFrameRequestCallbac
     mPresShell->GetPresContext()->RefreshDriver()->
       ScheduleFrameRequestCallbacks(this);
   }
 
   *aHandle = newHandle;
   return NS_OK;
 }
 
+void
+nsIDocument::CancelFrameRequestCallback(PRInt32 aHandle)
+{
+  // mFrameRequestCallbacks is stored sorted by handle
+  mFrameRequestCallbacks.RemoveElementSorted(aHandle);
+
+  // Not going to worry about unscheduling our refresh driver
+  // callback.  It'll just be a no-op when it happens, if we have no
+  // more frame request callbacks.
+}
+
 nsresult
 nsDocument::GetStateObject(nsIVariant** aState)
 {
   // Get the document's current state object. This is the object backing both
   // history.state and popStateEvent.state.
   //
   // mStateObjectContainer may be null; this just means that there's no
   // current state object.
--- a/content/base/test/test_bug647518.html
+++ b/content/base/test/test_bug647518.html
@@ -13,15 +13,33 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 647518 **/
-var handle1 = window.mozRequestAnimationFrame(function() {});
+SimpleTest.waitForExplicitFinish();
+var counter = 3;
+
+var called = false;
+var handle1 = window.mozRequestAnimationFrame(function() {
+  called = true;
+});
 ok(handle1 > 0, "Should get back a nonzero handle");
 
+function checker() {
+  --counter;
+  if (counter == 0) {
+    is(called, false, "Canceled callback should not have been called");
+    SimpleTest.finish();
+  } else {
+    window.mozRequestAnimationFrame(checker);
+  }
+}
+window.mozRequestAnimationFrame(checker);
+window.mozCancelRequestAnimationFrame(handle1);
+
 </script>
 </pre>
 </body>
 </html>
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -3887,16 +3887,30 @@ nsGlobalWindow::MozRequestAnimationFrame
   if (!aCallback) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
   return mDoc->ScheduleFrameRequestCallback(aCallback, aHandle);
 }
 
 NS_IMETHODIMP
+nsGlobalWindow::MozCancelRequestAnimationFrame(PRInt32 aHandle)
+{
+  FORWARD_TO_INNER(MozCancelRequestAnimationFrame, (aHandle),
+                   NS_ERROR_NOT_INITIALIZED);
+
+  if (!mDoc) {
+    return NS_OK;
+  }
+
+  mDoc->CancelFrameRequestCallback(aHandle);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsGlobalWindow::GetMozAnimationStartTime(PRInt64 *aTime)
 {
   FORWARD_TO_INNER(GetMozAnimationStartTime, (aTime), NS_ERROR_NOT_INITIALIZED);
 
   if (mDoc) {
     nsIPresShell* presShell = mDoc->GetShell();
     if (presShell) {
       *aTime = presShell->GetPresContext()->RefreshDriver()->
--- a/dom/interfaces/base/nsIDOMWindow.idl
+++ b/dom/interfaces/base/nsIDOMWindow.idl
@@ -65,17 +65,17 @@ interface nsIDOMMozURLProperty : nsISupp
  * The nsIDOMWindow interface is the primary interface for a DOM
  * window object. It represents a single window object that may
  * contain child windows if the document in the window contains a
  * HTML frameset document or if the document contains iframe elements.
  *
  * @see <http://www.whatwg.org/html/#window>
  */
 
-[scriptable, uuid(57b7ed24-c340-4994-a023-56ba578b78ab)]
+[scriptable, uuid(973e7219-40d5-4f94-b78d-53c2a0b8a13c)]
 interface nsIDOMWindow : nsISupports
 {
   // the current browsing context
   readonly attribute nsIDOMWindow                       window;
 
   /* [replaceable] self */
   readonly attribute nsIDOMWindow                       self;
 
@@ -416,16 +416,21 @@ interface nsIDOMWindow : nsISupports
    * Request a refresh of this browser window.
    *
    * @see <http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/RequestAnimationFrame/Overview.html>
    */
   long
     mozRequestAnimationFrame(in nsIFrameRequestCallback aCallback);
 
   /**
+   * Cancel a refresh callback.
+   */
+  void mozCancelRequestAnimationFrame(in long aHandle);
+
+  /**
    * The current animation start time in milliseconds since the epoch.
    */
   readonly attribute long long mozAnimationStartTime;
 
   /**
    * @see <http://dev.w3.org/2006/webapi/FileAPI/#creating-revoking>
    */
   readonly attribute nsIDOMMozURLProperty URL;