Skip to content

Commit de8b344

Browse files
committed
Bug 1800882 - Implement HTMLVideoElement.requestVideoFrameCallback. r=webidl,media-playback-reviewers,emilio,ErichDonGubler,padenot
See https://wicg.github.io/video-rvfc/ for standard details. Differential Revision: https://phabricator.services.mozilla.com/D216159
1 parent 8c78ed5 commit de8b344

33 files changed

+505
-194
lines changed

dom/base/AnimationFrameProvider.cpp

-53
This file was deleted.

dom/base/AnimationFrameProvider.h

+37-46
Original file line numberDiff line numberDiff line change
@@ -7,72 +7,63 @@
77
#ifndef mozilla_dom_AnimationFrameProvider_h
88
#define mozilla_dom_AnimationFrameProvider_h
99

10+
#include "MainThreadUtils.h"
11+
#include "mozilla/Assertions.h"
1012
#include "mozilla/dom/AnimationFrameProviderBinding.h"
11-
#include "mozilla/HashTable.h"
12-
#include "mozilla/RefPtr.h"
13-
#include "nsTArray.h"
13+
#include "mozilla/dom/HTMLVideoElement.h"
14+
#include "mozilla/dom/RequestCallbackManager.h"
1415

1516
namespace mozilla::dom {
1617

17-
struct FrameRequest {
18-
FrameRequest(FrameRequestCallback& aCallback, uint32_t aHandle);
19-
~FrameRequest();
18+
using FrameRequest = RequestCallbackEntry<FrameRequestCallback>;
19+
using FrameRequestManagerBase = RequestCallbackManager<FrameRequestCallback>;
2020

21-
// Comparator operators to allow RemoveElementSorted with an
22-
// integer argument on arrays of FrameRequest
23-
bool operator==(uint32_t aHandle) const { return mHandle == aHandle; }
24-
bool operator<(uint32_t aHandle) const { return mHandle < aHandle; }
25-
26-
RefPtr<FrameRequestCallback> mCallback;
27-
uint32_t mHandle;
28-
};
29-
30-
class FrameRequestManager {
21+
class FrameRequestManager final : public FrameRequestManagerBase {
3122
public:
3223
FrameRequestManager() = default;
3324
~FrameRequestManager() = default;
3425

35-
nsresult Schedule(FrameRequestCallback& aCallback, uint32_t* aHandle);
36-
bool Cancel(uint32_t aHandle);
26+
using FrameRequestManagerBase::Cancel;
27+
using FrameRequestManagerBase::Schedule;
28+
using FrameRequestManagerBase::Take;
3729

38-
bool IsEmpty() const { return mCallbacks.IsEmpty(); }
39-
40-
bool IsCanceled(uint32_t aHandle) const {
41-
return !mCanceledCallbacks.empty() && mCanceledCallbacks.has(aHandle);
30+
void Schedule(HTMLVideoElement* aElement) {
31+
if (!mVideoCallbacks.Contains(aElement)) {
32+
mVideoCallbacks.AppendElement(aElement);
33+
}
4234
}
4335

44-
void Take(nsTArray<FrameRequest>& aCallbacks) {
45-
aCallbacks = std::move(mCallbacks);
46-
mCanceledCallbacks.clear();
36+
bool Cancel(HTMLVideoElement* aElement) {
37+
return mVideoCallbacks.RemoveElement(aElement);
4738
}
4839

49-
void Unlink();
40+
bool IsEmpty() const {
41+
return FrameRequestManagerBase::IsEmpty() && mVideoCallbacks.IsEmpty();
42+
}
5043

51-
void Traverse(nsCycleCollectionTraversalCallback& aCB);
44+
void Take(nsTArray<RefPtr<HTMLVideoElement>>& aVideoCallbacks) {
45+
MOZ_ASSERT(NS_IsMainThread());
46+
aVideoCallbacks = std::move(mVideoCallbacks);
47+
}
5248

53-
private:
54-
nsTArray<FrameRequest> mCallbacks;
49+
void Unlink() {
50+
FrameRequestManagerBase::Unlink();
51+
mVideoCallbacks.Clear();
52+
}
5553

56-
// The set of frame request callbacks that were canceled but which we failed
57-
// to find in mFrameRequestCallbacks.
58-
HashSet<uint32_t> mCanceledCallbacks;
54+
void Traverse(nsCycleCollectionTraversalCallback& aCB) {
55+
FrameRequestManagerBase::Traverse(aCB);
56+
for (auto& i : mVideoCallbacks) {
57+
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
58+
aCB, "FrameRequestManager::mVideoCallbacks[i]");
59+
aCB.NoteXPCOMChild(ToSupports(i));
60+
}
61+
}
5962

60-
/**
61-
* The current frame request callback handle
62-
*/
63-
uint32_t mCallbackCounter = 0;
63+
private:
64+
nsTArray<RefPtr<HTMLVideoElement>> mVideoCallbacks;
6465
};
6566

66-
inline void ImplCycleCollectionUnlink(FrameRequestManager& aField) {
67-
aField.Unlink();
68-
}
69-
70-
inline void ImplCycleCollectionTraverse(
71-
nsCycleCollectionTraversalCallback& aCallback, FrameRequestManager& aField,
72-
const char* aName, uint32_t aFlags) {
73-
aField.Traverse(aCallback);
74-
}
75-
7667
} // namespace mozilla::dom
7768

7869
#endif

dom/base/Document.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -7159,6 +7159,12 @@ void Document::MaybeScheduleFrameRequestCallbacks() {
71597159
rd->EnsureFrameRequestCallbacksHappen();
71607160
}
71617161

7162+
void Document::TakeVideoFrameRequestCallbacks(
7163+
nsTArray<RefPtr<HTMLVideoElement>>& aVideoCallbacks) {
7164+
MOZ_ASSERT(aVideoCallbacks.IsEmpty());
7165+
mFrameRequestManager.Take(aVideoCallbacks);
7166+
}
7167+
71627168
void Document::TakeFrameRequestCallbacks(nsTArray<FrameRequest>& aCallbacks) {
71637169
MOZ_ASSERT(aCallbacks.IsEmpty());
71647170
mFrameRequestManager.Take(aCallbacks);
@@ -13692,6 +13698,18 @@ bool Document::IsCanceledFrameRequestCallback(uint32_t aHandle) const {
1369213698
return mFrameRequestManager.IsCanceled(aHandle);
1369313699
}
1369413700

13701+
void Document::ScheduleVideoFrameCallbacks(HTMLVideoElement* aElement) {
13702+
const bool wasEmpty = mFrameRequestManager.IsEmpty();
13703+
mFrameRequestManager.Schedule(aElement);
13704+
if (wasEmpty) {
13705+
MaybeScheduleFrameRequestCallbacks();
13706+
}
13707+
}
13708+
13709+
void Document::CancelVideoFrameCallbacks(HTMLVideoElement* aElement) {
13710+
mFrameRequestManager.Cancel(aElement);
13711+
}
13712+
1369513713
nsresult Document::GetStateObject(JS::MutableHandle<JS::Value> aState) {
1369613714
// Get the document's current state object. This is the object backing both
1369713715
// history.state and popStateEvent.state.

dom/base/Document.h

+11
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class HTMLInputElement;
254254
class HTMLMetaElement;
255255
class HTMLDialogElement;
256256
class HTMLSharedElement;
257+
class HTMLVideoElement;
257258
class HTMLImageElement;
258259
struct LifecycleCallbackArgs;
259260
class Link;
@@ -3047,13 +3048,23 @@ class Document : public nsINode,
30473048
uint32_t* aHandle);
30483049
void CancelFrameRequestCallback(uint32_t aHandle);
30493050

3051+
void ScheduleVideoFrameCallbacks(HTMLVideoElement* aElement);
3052+
void CancelVideoFrameCallbacks(HTMLVideoElement* aElement);
3053+
30503054
/**
30513055
* Returns true if the handle refers to a callback that was canceled that
30523056
* we did not find in our list of callbacks (e.g. because it is one of those
30533057
* in the set of callbacks currently queued to be run).
30543058
*/
30553059
bool IsCanceledFrameRequestCallback(uint32_t aHandle) const;
30563060

3061+
/**
3062+
* Put this document's video frame request callbacks into the provided
3063+
* list, and forget about them.
3064+
*/
3065+
void TakeVideoFrameRequestCallbacks(
3066+
nsTArray<RefPtr<HTMLVideoElement>>& aVideoCallbacks);
3067+
30573068
/**
30583069
* Put this document's frame request callbacks into the provided
30593070
* list, and forget about them.

dom/base/RequestCallbackManager.h

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef mozilla_dom_RequestCallbackManager_h
8+
#define mozilla_dom_RequestCallbackManager_h
9+
10+
#include <limits>
11+
#include "mozilla/HashTable.h"
12+
#include "mozilla/RefPtr.h"
13+
#include "nsTArray.h"
14+
#include "nsThreadUtils.h"
15+
16+
namespace mozilla::dom {
17+
18+
template <typename RequestCallback>
19+
struct RequestCallbackEntry {
20+
RequestCallbackEntry(RequestCallback& aCallback, uint32_t aHandle)
21+
: mCallback(&aCallback), mHandle(aHandle) {
22+
LogTaskBase<RequestCallback>::LogDispatch(mCallback);
23+
}
24+
25+
~RequestCallbackEntry() = default;
26+
27+
// Comparator operators to allow RemoveElementSorted with an
28+
// integer argument on arrays of RequestCallback
29+
bool operator==(uint32_t aHandle) const { return mHandle == aHandle; }
30+
bool operator<(uint32_t aHandle) const { return mHandle < aHandle; }
31+
32+
RefPtr<RequestCallback> mCallback;
33+
uint32_t mHandle;
34+
};
35+
36+
template <typename RequestCallback>
37+
class RequestCallbackManager {
38+
public:
39+
RequestCallbackManager() = default;
40+
~RequestCallbackManager() = default;
41+
42+
nsresult Schedule(RequestCallback& aCallback, uint32_t* aHandle) {
43+
if (mCallbackCounter == std::numeric_limits<uint32_t>::max()) {
44+
// Can't increment without overflowing; bail out
45+
return NS_ERROR_NOT_AVAILABLE;
46+
}
47+
uint32_t newHandle = ++mCallbackCounter;
48+
49+
mCallbacks.AppendElement(RequestCallbackEntry(aCallback, newHandle));
50+
51+
*aHandle = newHandle;
52+
return NS_OK;
53+
}
54+
55+
bool Cancel(uint32_t aHandle) {
56+
// mCallbacks is stored sorted by handle
57+
if (mCallbacks.RemoveElementSorted(aHandle)) {
58+
return true;
59+
}
60+
61+
Unused << mCanceledCallbacks.put(aHandle);
62+
return false;
63+
}
64+
65+
bool IsEmpty() const { return mCallbacks.IsEmpty(); }
66+
67+
bool IsCanceled(uint32_t aHandle) const {
68+
return !mCanceledCallbacks.empty() && mCanceledCallbacks.has(aHandle);
69+
}
70+
71+
void Take(nsTArray<RequestCallbackEntry<RequestCallback>>& aCallbacks) {
72+
aCallbacks = std::move(mCallbacks);
73+
mCanceledCallbacks.clear();
74+
}
75+
76+
void Unlink() { mCallbacks.Clear(); }
77+
78+
void Traverse(nsCycleCollectionTraversalCallback& aCB) {
79+
for (auto& i : mCallbacks) {
80+
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
81+
aCB, "RequestCallbackManager::mCallbacks[i]");
82+
aCB.NoteXPCOMChild(i.mCallback);
83+
}
84+
}
85+
86+
private:
87+
nsTArray<RequestCallbackEntry<RequestCallback>> mCallbacks;
88+
89+
// The set of frame request callbacks that were canceled but which we failed
90+
// to find in mRequestCallbacks.
91+
HashSet<uint32_t> mCanceledCallbacks;
92+
93+
/**
94+
* The current frame request callback handle
95+
*/
96+
uint32_t mCallbackCounter = 0;
97+
};
98+
99+
template <class RequestCallback>
100+
inline void ImplCycleCollectionUnlink(
101+
RequestCallbackManager<RequestCallback>& aField) {
102+
aField.Unlink();
103+
}
104+
105+
template <class RequestCallback>
106+
inline void ImplCycleCollectionTraverse(
107+
nsCycleCollectionTraversalCallback& aCallback,
108+
RequestCallbackManager<RequestCallback>& aField, const char* aName,
109+
uint32_t aFlags) {
110+
aField.Traverse(aCallback);
111+
}
112+
113+
} // namespace mozilla::dom
114+
115+
#endif

dom/base/VideoFrameProvider.h

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef mozilla_dom_VideoFrameProvider_h
8+
#define mozilla_dom_VideoFrameProvider_h
9+
10+
#include "mozilla/dom/VideoFrameBinding.h"
11+
#include "mozilla/dom/HTMLVideoElementBinding.h"
12+
#include "mozilla/dom/RequestCallbackManager.h"
13+
14+
namespace mozilla::dom {
15+
16+
using VideoFrameRequest = RequestCallbackEntry<VideoFrameRequestCallback>;
17+
18+
using VideoFrameRequestManager =
19+
RequestCallbackManager<VideoFrameRequestCallback>;
20+
21+
// Force instantiation.
22+
template void ImplCycleCollectionUnlink(VideoFrameRequestManager& aField);
23+
template void ImplCycleCollectionTraverse(
24+
nsCycleCollectionTraversalCallback& aCallback,
25+
VideoFrameRequestManager& aField, const char* aName, uint32_t aFlags);
26+
27+
} // namespace mozilla::dom
28+
#endif // mozilla_dom_VideoFrameProvider_h

dom/base/moz.build

+2-1
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ EXPORTS.mozilla.dom += [
258258
"PostMessageEvent.h",
259259
"ProcessMessageManager.h",
260260
"RadioGroupContainer.h",
261+
"RequestCallbackManager.h",
261262
"ResizeObserver.h",
262263
"ResponsiveImageSelector.h",
263264
"SameProcessMessageQueue.h",
@@ -289,6 +290,7 @@ EXPORTS.mozilla.dom += [
289290
"UnbindContext.h",
290291
"UseCounterMetrics.h",
291292
"UserActivation.h",
293+
"VideoFrameProvider.h",
292294
"ViewportMetaData.h",
293295
"VisualViewport.h",
294296
"WindowFeatures.h",
@@ -320,7 +322,6 @@ if CONFIG["COMPILE_ENVIRONMENT"]:
320322
UNIFIED_SOURCES += [
321323
"!UseCounterMetrics.cpp",
322324
"AbstractRange.cpp",
323-
"AnimationFrameProvider.cpp",
324325
"AnonymousContent.cpp",
325326
"Attr.cpp",
326327
"AttrArray.cpp",

0 commit comments

Comments
 (0)