Bug 1509466 - Make cancelAnimationFrame cancel a pending request frame callback scheduled in the same frame; r=farre
☠☠ backed out by 9311a433ea1b ☠ ☠
authorBrian Birtles <birtles@gmail.com>
Mon, 25 Feb 2019 15:15:56 +0900
changeset 461686 da0f977287bdc5fc72623f644953d9da00fbd38c
parent 461685 de1481b9b6faab60a32f630fa50ec2a16db11773
child 461687 9311a433ea1beecdb14b2a25ba98d60fb83a4d8c
push id35626
push usercsabou@mozilla.com
push dateThu, 28 Feb 2019 11:31:08 +0000
treeherdermozilla-central@2ea0c1db7e60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfarre
bugs1509466
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1509466 - Make cancelAnimationFrame cancel a pending request frame callback scheduled in the same frame; r=farre As per the following change to the HTML spec: https://github.com/whatwg/html/commit/86b05f8a07db0627a80781cd8e92179671a28806 when running a requestAnimationFrame callback it should be possible to cancel another requestAnimationFrame callback scheduled to run in the same frame by using cancelAnimationFrame. See issue: https://github.com/whatwg/html/issues/4359 Differential Revision: https://phabricator.services.mozilla.com/D20974
dom/base/Document.cpp
dom/base/Document.h
layout/base/nsRefreshDriver.cpp
layout/style/ServoBindings.toml
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -3658,16 +3658,17 @@ void Document::UpdateFrameRequestCallbac
   }
 
   mFrameRequestCallbacksScheduled = shouldBeScheduled;
 }
 
 void Document::TakeFrameRequestCallbacks(nsTArray<FrameRequest>& aCallbacks) {
   MOZ_ASSERT(aCallbacks.IsEmpty());
   aCallbacks.SwapElements(mFrameRequestCallbacks);
+  mCanceledFrameRequestCallbacks.clear();
   // No need to manually remove ourselves from the refresh driver; it will
   // handle that part.  But we do have to update our state.
   mFrameRequestCallbacksScheduled = false;
 }
 
 bool Document::ShouldThrottleFrameRequests() {
   if (mStaticCloneCount > 0) {
     // Even if we're not visible, a static clone may be, so run at full speed.
@@ -8969,17 +8970,24 @@ nsresult Document::ScheduleFrameRequestC
   *aHandle = newHandle;
   return NS_OK;
 }
 
 void Document::CancelFrameRequestCallback(int32_t aHandle) {
   // mFrameRequestCallbacks is stored sorted by handle
   if (mFrameRequestCallbacks.RemoveElementSorted(aHandle)) {
     UpdateFrameRequestCallbackSchedulingState();
-  }
+  } else {
+    Unused << mCanceledFrameRequestCallbacks.put(aHandle);
+  }
+}
+
+bool Document::IsCanceledFrameRequestCallback(int32_t aHandle) const {
+  return !mCanceledFrameRequestCallbacks.empty() &&
+         mCanceledFrameRequestCallbacks.has(aHandle);
 }
 
 nsresult Document::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/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -47,16 +47,17 @@
 #include "nsContentListDeclarations.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/dom/BrowsingContext.h"
 #include "mozilla/dom/ContentBlockingLog.h"
 #include "mozilla/dom/DispatcherTrait.h"
 #include "mozilla/dom/DocumentOrShadowRoot.h"
+#include "mozilla/HashTable.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/SegmentedVector.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 #include <bitset>  // for member
@@ -2934,16 +2935,23 @@ class Document : public nsINode,
     int32_t mHandle;
   };
 
   nsresult ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
                                         int32_t* aHandle);
   void CancelFrameRequestCallback(int32_t aHandle);
 
   /**
+   * Returns true if the handle refers to a callback that was canceled that
+   * we did not find in our list of callbacks (e.g. because it is one of those
+   * in the set of callbacks currently queued to be run).
+   */
+  bool IsCanceledFrameRequestCallback(int32_t aHandle) const;
+
+  /**
    * Put this document's frame request callbacks into the provided
    * list, and forget about them.
    */
   void TakeFrameRequestCallbacks(nsTArray<FrameRequest>& aCallbacks);
 
   /**
    * @return true if this document's frame request callbacks should be
    * throttled. We throttle requestAnimationFrame for documents which aren't
@@ -4388,16 +4396,20 @@ class Document : public nsINode,
   // Weak reference to mScriptGlobalObject QI:d to nsPIDOMWindow,
   // updated on every set of mScriptGlobalObject.
   nsPIDOMWindowInner* mWindow;
 
   nsCOMPtr<nsIDocumentEncoder> mCachedEncoder;
 
   nsTArray<FrameRequest> mFrameRequestCallbacks;
 
+  // The set of frame request callbacks that were canceled but which we failed
+  // to find in mFrameRequestCallbacks.
+  HashSet<int32_t> mCanceledFrameRequestCallbacks;
+
   // This object allows us to evict ourself from the back/forward cache.  The
   // pointer is non-null iff we're currently in the bfcache.
   nsIBFCacheEntry* mBFCacheEntry;
 
   // Our base target.
   nsString mBaseTarget;
 
   nsCOMPtr<nsIStructuredCloneContainer> mStateObjectContainer;
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1669,16 +1669,20 @@ void nsRefreshDriver::RunFrameRequestCal
       if (innerWindow) {
         mozilla::dom::Performance* perf = innerWindow->GetPerformance();
         if (perf) {
           timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aNowTime);
         }
         // else window is partially torn down already
       }
       for (auto& callback : docCallbacks.mCallbacks) {
+        if (docCallbacks.mDocument->IsCanceledFrameRequestCallback(
+                callback.mHandle)) {
+          continue;
+        }
         callback.mCallback->Call(timeStamp);
       }
     }
   }
 }
 
 struct RunnableWithDelay {
   nsCOMPtr<nsIRunnable> mRunnable;
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -344,17 +344,22 @@ opaque-types = [
     "mozilla::dom::Optional",
     "mozilla::dom::OwningNodeOrString_Value",
     "mozilla::dom::Nullable",
     "mozilla::external::AtomicRefCounted",
     "RefPtr_Proxy",
     "RefPtr_Proxy_member_function",
     "nsAutoPtr_Proxy",
     "nsAutoPtr_Proxy_member_function",
+    "mozilla::detail::HashTable", # <- We should be able to remove this and
+                                  # HashSet below once
+                                  # https://github.com/rust-lang/rust-bindgen/pull/1515
+                                  # is available
     "mozilla::detail::PointerType",
+    "mozilla::HashSet",
     "mozilla::Pair",
     "mozilla::Pair_Base",
     "mozilla::SeenPtrs",
     "mozilla::SupportsWeakPtr",
     "mozilla::Tuple",
     "SupportsWeakPtr",
     "mozilla::detail::WeakReference",
     "mozilla::WeakPtr",