зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1738971 - Part 5. Implement AnimationFrameProvider for dedicated workers. r=dom-worker-reviewers,gfx-reviewers,jgilbert,smaug
Differential Revision: https://phabricator.services.mozilla.com/D130266
This commit is contained in:
Родитель
ddca5b5abd
Коммит
0fa01671ab
|
@ -27,4 +27,13 @@ interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
|
|||
|
||||
attribute EventHandler onmessage;
|
||||
attribute EventHandler onmessageerror;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frames
|
||||
// Ideally we would just include AnimationFrameProvider to add the interface,
|
||||
// but we cannot make an include conditional.
|
||||
[Pref="gfx.offscreencanvas.enabled", Throws]
|
||||
long requestAnimationFrame(FrameRequestCallback callback);
|
||||
|
||||
[Pref="gfx.offscreencanvas.enabled", Throws]
|
||||
void cancelAnimationFrame(long handle);
|
||||
};
|
||||
|
|
|
@ -41,10 +41,12 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/AutoEntryScript.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/BlobURLProtocolHandler.h"
|
||||
#include "mozilla/dom/CSPEvalChecker.h"
|
||||
#include "mozilla/dom/CallbackDebuggerNotification.h"
|
||||
#include "mozilla/dom/ClientSource.h"
|
||||
#include "mozilla/dom/Clients.h"
|
||||
#include "mozilla/dom/Console.h"
|
||||
|
@ -59,6 +61,7 @@
|
|||
#include "mozilla/dom/ImageBitmap.h"
|
||||
#include "mozilla/dom/ImageBitmapSource.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
|
@ -80,6 +83,8 @@
|
|||
#include "mozilla/dom/WorkerNavigator.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerRunnable.h"
|
||||
#include "mozilla/dom/WorkerDocumentListener.h"
|
||||
#include "mozilla/dom/VsyncWorkerChild.h"
|
||||
#include "mozilla/dom/cache/CacheStorage.h"
|
||||
#include "mozilla/dom/cache/Types.h"
|
||||
#include "mozilla/extensions/ExtensionBrowser.h"
|
||||
|
@ -99,6 +104,7 @@
|
|||
#include "nsLiteralString.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsRFPService.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTLiteralString.h"
|
||||
|
@ -116,13 +122,15 @@
|
|||
# undef PostMessage
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using mozilla::dom::cache::CacheStorage;
|
||||
using mozilla::dom::workerinternals::NamedWorkerGlobalScopeMixin;
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
using mozilla::ipc::PBackgroundChild;
|
||||
using mozilla::ipc::PrincipalInfo;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class WorkerScriptTimeoutHandler final : public ScriptTimeoutHandler {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -761,6 +769,16 @@ void WorkerGlobalScope::ConsumeWindowInteraction() {
|
|||
mWindowInteractionsAllowed--;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(DedicatedWorkerGlobalScope,
|
||||
WorkerGlobalScope, mFrameRequestManager)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DedicatedWorkerGlobalScope,
|
||||
WorkerGlobalScope)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(DedicatedWorkerGlobalScope,
|
||||
WorkerGlobalScope)
|
||||
|
||||
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
|
||||
NotNull<WorkerPrivate*> aWorkerPrivate,
|
||||
UniquePtr<ClientSource> aClientSource, const nsString& aName)
|
||||
|
@ -813,6 +831,128 @@ void DedicatedWorkerGlobalScope::Close() {
|
|||
mWorkerPrivate->CloseInternal();
|
||||
}
|
||||
|
||||
int32_t DedicatedWorkerGlobalScope::RequestAnimationFrame(
|
||||
FrameRequestCallback& aCallback, ErrorResult& aError) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
DebuggerNotificationDispatch(this,
|
||||
DebuggerNotificationType::RequestAnimationFrame);
|
||||
|
||||
// Ensure the worker is associated with a window.
|
||||
if (mWorkerPrivate->WindowID() == UINT64_MAX) {
|
||||
aError.ThrowNotSupportedError("Worker has no associated owner Window");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!mVsyncChild) {
|
||||
PBackgroundChild* bgChild = BackgroundChild::GetOrCreateForCurrentThread();
|
||||
mVsyncChild = MakeRefPtr<VsyncWorkerChild>();
|
||||
|
||||
if (!bgChild || !mVsyncChild->Initialize(mWorkerPrivate) ||
|
||||
!bgChild->SendPVsyncConstructor(mVsyncChild)) {
|
||||
mVsyncChild->Destroy();
|
||||
mVsyncChild = nullptr;
|
||||
aError.ThrowNotSupportedError(
|
||||
"Worker failed to register for vsync to drive event loop");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDocListener) {
|
||||
mDocListener = WorkerDocumentListener::Create(mWorkerPrivate);
|
||||
if (!mDocListener) {
|
||||
aError.ThrowNotSupportedError(
|
||||
"Worker failed to register for document visibility events");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t handle = 0;
|
||||
aError = mFrameRequestManager.Schedule(aCallback, &handle);
|
||||
if (!aError.Failed() && mDocumentVisible) {
|
||||
mVsyncChild->TryObserve();
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void DedicatedWorkerGlobalScope::CancelAnimationFrame(int32_t aHandle,
|
||||
ErrorResult& aError) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
DebuggerNotificationDispatch(this,
|
||||
DebuggerNotificationType::CancelAnimationFrame);
|
||||
|
||||
// Ensure the worker is associated with a window.
|
||||
if (mWorkerPrivate->WindowID() == UINT64_MAX) {
|
||||
aError.ThrowNotSupportedError("Worker has no associated owner Window");
|
||||
return;
|
||||
}
|
||||
|
||||
mFrameRequestManager.Cancel(aHandle);
|
||||
if (mVsyncChild && mFrameRequestManager.IsEmpty()) {
|
||||
mVsyncChild->TryUnobserve();
|
||||
}
|
||||
}
|
||||
|
||||
void DedicatedWorkerGlobalScope::OnDocumentVisible(bool aVisible) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
mDocumentVisible = aVisible;
|
||||
|
||||
// We only change state immediately when we become visible. If we become
|
||||
// hidden, then we wait for the next vsync tick to apply that.
|
||||
if (aVisible && !mFrameRequestManager.IsEmpty()) {
|
||||
mVsyncChild->TryObserve();
|
||||
}
|
||||
}
|
||||
|
||||
void DedicatedWorkerGlobalScope::OnVsync(const VsyncEvent& aVsync) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mFrameRequestManager.IsEmpty() || !mDocumentVisible) {
|
||||
// If we ever receive a vsync event, and there are still no callbacks to
|
||||
// process, or we remain hidden, we should disable observing them. By
|
||||
// waiting an extra tick, we ensure we minimize extra IPC for content that
|
||||
// does not call requestFrameAnimation directly during the callback, or
|
||||
// that is rapidly toggling between hidden and visible.
|
||||
mVsyncChild->TryUnobserve();
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<FrameRequest> callbacks;
|
||||
mFrameRequestManager.Take(callbacks);
|
||||
|
||||
RefPtr<DedicatedWorkerGlobalScope> scope(this);
|
||||
CallbackDebuggerNotificationGuard guard(
|
||||
scope, DebuggerNotificationType::RequestAnimationFrameCallback);
|
||||
|
||||
// This is similar to what we do in nsRefreshDriver::RunFrameRequestCallbacks
|
||||
// and Performance::TimeStampToDOMHighResForRendering in order to have the
|
||||
// same behaviour for requestAnimationFrame on both the main and worker
|
||||
// threads.
|
||||
DOMHighResTimeStamp timeStamp = 0;
|
||||
if (!aVsync.mTime.IsNull()) {
|
||||
timeStamp = mWorkerPrivate->TimeStampToDOMHighRes(aVsync.mTime);
|
||||
// 0 is an inappropriate mixin for this this area; however CSS Animations
|
||||
// needs to have it's Time Reduction Logic refactored, so it's currently
|
||||
// only clamping for RFP mode. RFP mode gives a much lower time precision,
|
||||
// so we accept the security leak here for now.
|
||||
timeStamp = nsRFPService::ReduceTimePrecisionAsMSecsRFPOnly(timeStamp, 0);
|
||||
}
|
||||
|
||||
for (auto& callback : callbacks) {
|
||||
if (mFrameRequestManager.IsCanceled(callback.mHandle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// MOZ_KnownLive is OK, because the stack array `callbacks` keeps the
|
||||
// callback alive and the mCallback strong reference can't be mutated by
|
||||
// the call.
|
||||
LogFrameRequestCallback::Run run(callback.mCallback);
|
||||
MOZ_KnownLive(callback.mCallback)->Call(timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
SharedWorkerGlobalScope::SharedWorkerGlobalScope(
|
||||
NotNull<WorkerPrivate*> aWorkerPrivate,
|
||||
UniquePtr<ClientSource> aClientSource, const nsString& aName)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "mozilla/NotNull.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/AnimationFrameProvider.h"
|
||||
#include "mozilla/dom/ImageBitmapBinding.h"
|
||||
#include "mozilla/dom/ImageBitmapSource.h"
|
||||
#include "mozilla/dom/SafeRefPtr.h"
|
||||
|
@ -69,9 +71,11 @@ class ServiceWorkerDescriptor;
|
|||
class ServiceWorkerRegistration;
|
||||
class ServiceWorkerRegistrationDescriptor;
|
||||
struct StructuredSerializeOptions;
|
||||
class WorkerDocumentListener;
|
||||
class WorkerLocation;
|
||||
class WorkerNavigator;
|
||||
class WorkerPrivate;
|
||||
class VsyncWorkerChild;
|
||||
struct RequestInit;
|
||||
|
||||
namespace cache {
|
||||
|
@ -336,6 +340,10 @@ class DedicatedWorkerGlobalScope final
|
|||
: public WorkerGlobalScope,
|
||||
public workerinternals::NamedWorkerGlobalScopeMixin {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
|
||||
DedicatedWorkerGlobalScope, WorkerGlobalScope)
|
||||
|
||||
DedicatedWorkerGlobalScope(NotNull<WorkerPrivate*> aWorkerPrivate,
|
||||
UniquePtr<ClientSource> aClientSource,
|
||||
const nsString& aName);
|
||||
|
@ -352,11 +360,28 @@ class DedicatedWorkerGlobalScope final
|
|||
|
||||
void Close();
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
int32_t RequestAnimationFrame(FrameRequestCallback& aCallback,
|
||||
ErrorResult& aError);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void CancelAnimationFrame(int32_t aHandle, ErrorResult& aError);
|
||||
|
||||
void OnDocumentVisible(bool aVisible) override;
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
void OnVsync(const VsyncEvent& aVsync) override;
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
IMPL_EVENT_HANDLER(messageerror)
|
||||
|
||||
private:
|
||||
~DedicatedWorkerGlobalScope() = default;
|
||||
|
||||
FrameRequestManager mFrameRequestManager;
|
||||
RefPtr<VsyncWorkerChild> mVsyncChild;
|
||||
RefPtr<WorkerDocumentListener> mDocListener;
|
||||
bool mDocumentVisible = false;
|
||||
};
|
||||
|
||||
class SharedWorkerGlobalScope final
|
||||
|
|
|
@ -55,9 +55,6 @@
|
|||
[TextMetrics interface: attribute emHeightAscent]
|
||||
expected: FAIL
|
||||
|
||||
[DedicatedWorkerGlobalScope interface: calling requestAnimationFrame(FrameRequestCallback) on self with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[TextMetrics interface: attribute ideographicBaseline]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -109,9 +106,6 @@
|
|||
[OffscreenCanvasRenderingContext2D interface: operation quadraticCurveTo(unrestricted double, unrestricted double, unrestricted double, unrestricted double)]
|
||||
expected: FAIL
|
||||
|
||||
[DedicatedWorkerGlobalScope interface: self must inherit property "cancelAnimationFrame(unsigned long)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvasRenderingContext2D interface: operation resetTransform()]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -229,9 +223,6 @@
|
|||
[OffscreenCanvasRenderingContext2D interface: operation putImageData(ImageData, long, long, long, long, long, long)]
|
||||
expected: FAIL
|
||||
|
||||
[DedicatedWorkerGlobalScope interface: calling cancelAnimationFrame(unsigned long) on self with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvasRenderingContext2D interface: operation moveTo(unrestricted double, unrestricted double)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -304,9 +295,6 @@
|
|||
[TextMetrics interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[DedicatedWorkerGlobalScope interface: self must inherit property "requestAnimationFrame(FrameRequestCallback)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Path2D interface: operation bezierCurveTo(unrestricted double, unrestricted double, unrestricted double, unrestricted double, unrestricted double, unrestricted double)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -322,15 +310,9 @@
|
|||
[CanvasGradient interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[DedicatedWorkerGlobalScope interface: operation cancelAnimationFrame(unsigned long)]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvasRenderingContext2D interface: operation save()]
|
||||
expected: FAIL
|
||||
|
||||
[DedicatedWorkerGlobalScope interface: operation requestAnimationFrame(FrameRequestCallback)]
|
||||
expected: FAIL
|
||||
|
||||
[CanvasPattern interface object length]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
[WorkerGlobalScope_requestAnimationFrame.tentative.worker.html]
|
||||
[WorkerGlobalScope_requestAnimationFrame]
|
||||
expected: FAIL
|
||||
|
||||
prefs: [gfx.offscreencanvas.enabled:true]
|
||||
|
|
Загрузка…
Ссылка в новой задаче