Bug 1738971 - Part 1. Split out plumbing for AnimationFrameProvider from 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
This commit is contained in:
Andrew Osmond 2021-12-10 02:57:49 +00:00
Родитель 36dee676de
Коммит ce897c182a
10 изменённых файлов: 164 добавлений и 62 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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;
// ==================================================================
@ -1412,7 +1404,6 @@ Document::Document(const char* aContentType)
mPreloadPictureDepth(0),
mEventsSuppressed(0),
mIgnoreDestructiveWritesCounter(0),
mFrameRequestCallbackCounter(0),
mStaticCloneCount(0),
mWindow(nullptr),
mBFCacheEntry(nullptr),
@ -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);
@ -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?");
@ -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;
@ -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;
@ -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) {

Просмотреть файл

@ -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"
@ -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);
@ -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;
@ -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.

Просмотреть файл

@ -148,6 +148,7 @@ EXPORTS.mozilla.dom += [
"!UseCounterWorkerList.h",
"AbstractRange.h",
"AncestorIterator.h",
"AnimationFrameProvider.h",
"AnonymousContent.h",
"Attr.h",
"AutoPrintEventDispatcher.h",
@ -295,6 +296,7 @@ if CONFIG["FUZZING"]:
UNIFIED_SOURCES += [
"AbstractRange.cpp",
"AnimationFrameProvider.cpp",
"AnonymousContent.cpp",
"Attr.cpp",
"AttrArray.cpp",

Просмотреть файл

@ -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);
};

Просмотреть файл

@ -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 {

Просмотреть файл

@ -403,6 +403,7 @@ WEBIDL_FILES = [
"Animatable.webidl",
"AnimationEffect.webidl",
"AnimationEvent.webidl",
"AnimationFrameProvider.webidl",
"AnimationTimeline.webidl",
"AnonymousContent.webidl",
"AppInfo.webidl",

Просмотреть файл

@ -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"

Просмотреть файл

@ -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) {