Skip to content

Commit

Permalink
Bug 1738971 - Part 1. Split out plumbing for AnimationFrameProvider f…
Browse files Browse the repository at this point in the history
…rom Document. r=dom-worker-reviewers,smaug

This patch splits out AnimationFrameProvider from the Document WebIDL to
allow the workers to implement it. It also splits out a helper class to
manage the requestAnimationFrame callbacks which may be reused on a
worker thread.

Differential Revision: https://phabricator.services.mozilla.com/D130262
  • Loading branch information
aosmond committed Dec 10, 2021
1 parent 36dee67 commit ce897c1
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 62 deletions.
53 changes: 53 additions & 0 deletions dom/base/AnimationFrameProvider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/AnimationFrameProvider.h"
#include "nsThreadUtils.h"

namespace mozilla::dom {

FrameRequest::FrameRequest(FrameRequestCallback& aCallback, int32_t aHandle)
: mCallback(&aCallback), mHandle(aHandle) {
LogFrameRequestCallback::LogDispatch(mCallback);
}

FrameRequest::~FrameRequest() = default;

nsresult FrameRequestManager::Schedule(FrameRequestCallback& aCallback,
int32_t* aHandle) {
if (mCallbackCounter == INT32_MAX) {
// Can't increment without overflowing; bail out
return NS_ERROR_NOT_AVAILABLE;
}
int32_t newHandle = ++mCallbackCounter;

mCallbacks.AppendElement(FrameRequest(aCallback, newHandle));

*aHandle = newHandle;
return NS_OK;
}

bool FrameRequestManager::Cancel(int32_t aHandle) {
// mCallbacks is stored sorted by handle
if (mCallbacks.RemoveElementSorted(aHandle)) {
return true;
}

Unused << mCanceledCallbacks.put(aHandle);
return false;
}

void FrameRequestManager::Unlink() { mCallbacks.Clear(); }

void FrameRequestManager::Traverse(nsCycleCollectionTraversalCallback& aCB) {
for (auto& i : mCallbacks) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCB,
"FrameRequestManager::mCallbacks[i]");
aCB.NoteXPCOMChild(i.mCallback);
}
}

} // namespace mozilla::dom
78 changes: 78 additions & 0 deletions dom/base/AnimationFrameProvider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_AnimationFrameProvider_h
#define mozilla_dom_AnimationFrameProvider_h

#include "mozilla/dom/AnimationFrameProviderBinding.h"
#include "mozilla/HashTable.h"
#include "mozilla/RefPtr.h"
#include "nsTArray.h"

namespace mozilla::dom {

struct FrameRequest {
FrameRequest(FrameRequestCallback& aCallback, int32_t aHandle);
~FrameRequest();

// Comparator operators to allow RemoveElementSorted with an
// integer argument on arrays of FrameRequest
bool operator==(int32_t aHandle) const { return mHandle == aHandle; }
bool operator<(int32_t aHandle) const { return mHandle < aHandle; }

RefPtr<FrameRequestCallback> mCallback;
int32_t mHandle;
};

class FrameRequestManager {
public:
FrameRequestManager() = default;
~FrameRequestManager() = default;

nsresult Schedule(FrameRequestCallback& aCallback, int32_t* aHandle);
bool Cancel(int32_t aHandle);

bool IsEmpty() const { return mCallbacks.IsEmpty(); }

bool IsCanceled(int32_t aHandle) const {
return !mCanceledCallbacks.empty() && mCanceledCallbacks.has(aHandle);
}

void Take(nsTArray<FrameRequest>& aCallbacks) {
aCallbacks = std::move(mCallbacks);
mCanceledCallbacks.clear();
}

void Unlink();

void Traverse(nsCycleCollectionTraversalCallback& aCB);

private:
nsTArray<FrameRequest> mCallbacks;

// The set of frame request callbacks that were canceled but which we failed
// to find in mFrameRequestCallbacks.
HashSet<int32_t> mCanceledCallbacks;

/**
* The current frame request callback handle
*/
int32_t mCallbackCounter = 0;
};

inline void ImplCycleCollectionUnlink(FrameRequestManager& aField) {
aField.Unlink();
}

inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback, FrameRequestManager& aField,
const char* aName, uint32_t aFlags) {
aField.Traverse(aCallback);
}

} // namespace mozilla::dom

#endif
40 changes: 9 additions & 31 deletions dom/base/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1252,14 +1252,6 @@ void Document::SelectorCache::NotifyExpired(SelectorCacheKey* aSelector) {
delete aSelector;
}

Document::FrameRequest::FrameRequest(FrameRequestCallback& aCallback,
int32_t aHandle)
: mCallback(&aCallback), mHandle(aHandle) {
LogFrameRequestCallback::LogDispatch(mCallback);
}

Document::FrameRequest::~FrameRequest() = default;

Document::PendingFrameStaticClone::~PendingFrameStaticClone() = default;

// ==================================================================
Expand Down Expand Up @@ -1412,7 +1404,6 @@ Document::Document(const char* aContentType)
mPreloadPictureDepth(0),
mEventsSuppressed(0),
mIgnoreDestructiveWritesCounter(0),
mFrameRequestCallbackCounter(0),
mStaticCloneCount(0),
mWindow(nullptr),
mBFCacheEntry(nullptr),
Expand Down Expand Up @@ -2446,15 +2437,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMidasCommandManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAll)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocGroup)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameRequestManager)

// Traverse all our nsCOMArrays.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)

for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
}

// Traverse animation components
if (tmp->mAnimationController) {
tmp->mAnimationController->Traverse(&cb);
Expand Down Expand Up @@ -2600,7 +2587,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
delete tmp->mSubDocuments;
tmp->mSubDocuments = nullptr;

tmp->mFrameRequestCallbacks.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameRequestManager)
MOZ_RELEASE_ASSERT(!tmp->mFrameRequestCallbacksScheduled,
"How did we get here without our presshell going away "
"first?");
Expand Down Expand Up @@ -6889,7 +6876,7 @@ void Document::UpdateFrameRequestCallbackSchedulingState(
// WouldScheduleFrameRequestCallbacks() instead of adding more stuff to this
// condition.
bool shouldBeScheduled =
WouldScheduleFrameRequestCallbacks() && !mFrameRequestCallbacks.IsEmpty();
WouldScheduleFrameRequestCallbacks() && !mFrameRequestManager.IsEmpty();
if (shouldBeScheduled == mFrameRequestCallbacksScheduled) {
// nothing to do
return;
Expand All @@ -6910,8 +6897,7 @@ void Document::UpdateFrameRequestCallbackSchedulingState(

void Document::TakeFrameRequestCallbacks(nsTArray<FrameRequest>& aCallbacks) {
MOZ_ASSERT(aCallbacks.IsEmpty());
aCallbacks = std::move(mFrameRequestCallbacks);
mCanceledFrameRequestCallbacks.clear();
mFrameRequestManager.Take(aCallbacks);
// 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;
Expand Down Expand Up @@ -13210,31 +13196,23 @@ void Document::UnlinkOriginalDocumentIfStatic() {

nsresult Document::ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
int32_t* aHandle) {
if (mFrameRequestCallbackCounter == INT32_MAX) {
// Can't increment without overflowing; bail out
return NS_ERROR_NOT_AVAILABLE;
nsresult rv = mFrameRequestManager.Schedule(aCallback, aHandle);
if (NS_FAILED(rv)) {
return rv;
}
int32_t newHandle = ++mFrameRequestCallbackCounter;

mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
UpdateFrameRequestCallbackSchedulingState();

*aHandle = newHandle;
return NS_OK;
}

void Document::CancelFrameRequestCallback(int32_t aHandle) {
// mFrameRequestCallbacks is stored sorted by handle
if (mFrameRequestCallbacks.RemoveElementSorted(aHandle)) {
if (mFrameRequestManager.Cancel(aHandle)) {
UpdateFrameRequestCallbackSchedulingState();
} else {
Unused << mCanceledFrameRequestCallbacks.put(aHandle);
}
}

bool Document::IsCanceledFrameRequestCallback(int32_t aHandle) const {
return !mCanceledFrameRequestCallbacks.empty() &&
mCanceledFrameRequestCallbacks.has(aHandle);
return mFrameRequestManager.IsCanceled(aHandle);
}

nsresult Document::GetStateObject(nsIVariant** aState) {
Expand Down
25 changes: 2 additions & 23 deletions dom/base/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "mozilla/UseCounter.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/css/StylePreloadKind.h"
#include "mozilla/dom/AnimationFrameProvider.h"
#include "mozilla/dom/DispatcherTrait.h"
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "mozilla/dom/Element.h"
Expand Down Expand Up @@ -3103,19 +3104,6 @@ class Document : public nsINode,

SVGSVGElement* GetSVGRootElement() const;

struct FrameRequest {
FrameRequest(FrameRequestCallback& aCallback, int32_t aHandle);
~FrameRequest();

// Comparator operators to allow RemoveElementSorted with an
// integer argument on arrays of FrameRequest
bool operator==(int32_t aHandle) const { return mHandle == aHandle; }
bool operator<(int32_t aHandle) const { return mHandle < aHandle; }

RefPtr<FrameRequestCallback> mCallback;
int32_t mHandle;
};

nsresult ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
int32_t* aHandle);
void CancelFrameRequestCallback(int32_t aHandle);
Expand Down Expand Up @@ -4985,11 +4973,6 @@ class Document : public nsINode,
*/
uint32_t mIgnoreDestructiveWritesCounter;

/**
* The current frame request callback handle
*/
int32_t mFrameRequestCallbackCounter;

// Count of live static clones of this document.
uint32_t mStaticCloneCount;

Expand All @@ -5011,11 +4994,7 @@ class Document : public nsINode,

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;
FrameRequestManager mFrameRequestManager;

// This object allows us to evict ourself from the back/forward cache. The
// pointer is non-null iff we're currently in the bfcache.
Expand Down
2 changes: 2 additions & 0 deletions dom/base/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ EXPORTS.mozilla.dom += [
"!UseCounterWorkerList.h",
"AbstractRange.h",
"AncestorIterator.h",
"AnimationFrameProvider.h",
"AnonymousContent.h",
"Attr.h",
"AutoPrintEventDispatcher.h",
Expand Down Expand Up @@ -295,6 +296,7 @@ if CONFIG["FUZZING"]:

UNIFIED_SOURCES += [
"AbstractRange.cpp",
"AnimationFrameProvider.cpp",
"AnonymousContent.cpp",
"Attr.cpp",
"AttrArray.cpp",
Expand Down
15 changes: 15 additions & 0 deletions dom/webidl/AnimationFrameProvider.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frames
*/

callback FrameRequestCallback = void (DOMHighResTimeStamp time);

interface mixin AnimationFrameProvider {
[Throws] long requestAnimationFrame(FrameRequestCallback callback);
[Throws] void cancelAnimationFrame(long handle);
};
8 changes: 2 additions & 6 deletions dom/webidl/Window.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,8 @@ partial interface Window {
[Throws, NeedsCallerType] attribute any outerHeight;
};

// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/RequestAnimationFrame/Overview.html
partial interface Window {
[Throws] long requestAnimationFrame(FrameRequestCallback callback);
[Throws] void cancelAnimationFrame(long handle);
};
callback FrameRequestCallback = void (DOMHighResTimeStamp time);
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frames
Window includes AnimationFrameProvider;

// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html
partial interface Window {
Expand Down
1 change: 1 addition & 0 deletions dom/webidl/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ WEBIDL_FILES = [
"Animatable.webidl",
"AnimationEffect.webidl",
"AnimationEvent.webidl",
"AnimationFrameProvider.webidl",
"AnimationTimeline.webidl",
"AnonymousContent.webidl",
"AppInfo.webidl",
Expand Down
2 changes: 1 addition & 1 deletion gfx/vr/ipc/VRManagerChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include "nsISupportsImpl.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/WindowBinding.h" // For FrameRequestCallback
#include "mozilla/dom/AnimationFrameProviderBinding.h"
#include "mozilla/dom/WebXRBinding.h"
#include "mozilla/dom/XRFrame.h"
#include "mozilla/gfx/PVRManagerChild.h"
Expand Down
2 changes: 1 addition & 1 deletion layout/base/nsRefreshDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1890,7 +1890,7 @@ struct DocumentFrameCallbacks {
explicit DocumentFrameCallbacks(Document* aDocument) : mDocument(aDocument) {}

RefPtr<Document> mDocument;
nsTArray<Document::FrameRequest> mCallbacks;
nsTArray<FrameRequest> mCallbacks;
};

static bool HasPendingAnimations(PresShell* aPresShell) {
Expand Down

0 comments on commit ce897c1

Please sign in to comment.