diff options
Diffstat (limited to '')
-rw-r--r-- | dom/workers/WorkerDocumentListener.cpp | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/dom/workers/WorkerDocumentListener.cpp b/dom/workers/WorkerDocumentListener.cpp new file mode 100644 index 0000000000..dfc8544daf --- /dev/null +++ b/dom/workers/WorkerDocumentListener.cpp @@ -0,0 +1,110 @@ +/* -*- 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 "WorkerDocumentListener.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "mozilla/dom/WorkerScope.h" +#include "nsGlobalWindowInner.h" + +namespace mozilla::dom { + +WorkerDocumentListener::WorkerDocumentListener() + : mMutex("mozilla::dom::WorkerDocumentListener::mMutex") {} + +WorkerDocumentListener::~WorkerDocumentListener() = default; + +RefPtr<WorkerDocumentListener> WorkerDocumentListener::Create( + WorkerPrivate* aWorkerPrivate) { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + auto listener = MakeRefPtr<WorkerDocumentListener>(); + + RefPtr<StrongWorkerRef> strongWorkerRef = + StrongWorkerRef::Create(aWorkerPrivate, "WorkerDocumentListener", + [listener]() { listener->Destroy(); }); + if (NS_WARN_IF(!strongWorkerRef)) { + return nullptr; + } + + listener->mWorkerRef = new ThreadSafeWorkerRef(strongWorkerRef); + uint64_t windowID = aWorkerPrivate->WindowID(); + + aWorkerPrivate->DispatchToMainThread(NS_NewRunnableFunction( + "WorkerDocumentListener::Create", + [listener, windowID] { listener->SetListening(windowID, true); })); + + return listener; +} + +void WorkerDocumentListener::OnVisible(bool aVisible) { + MOZ_ASSERT(NS_IsMainThread()); + + MutexAutoLock lock(mMutex); + if (!mWorkerRef) { + // We haven't handled the runnable to release this yet. + return; + } + + class VisibleRunnable final : public WorkerRunnable { + public: + VisibleRunnable(WorkerPrivate* aWorkerPrivate, bool aVisible) + : WorkerRunnable(aWorkerPrivate), mVisible(aVisible) {} + + bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { + WorkerGlobalScope* scope = aWorkerPrivate->GlobalScope(); + MOZ_ASSERT(scope); + scope->OnDocumentVisible(mVisible); + return true; + } + + private: + const bool mVisible; + }; + + auto runnable = MakeRefPtr<VisibleRunnable>(mWorkerRef->Private(), aVisible); + runnable->Dispatch(); +} + +void WorkerDocumentListener::SetListening(uint64_t aWindowID, bool aListen) { + MOZ_ASSERT(NS_IsMainThread()); + + auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID); + Document* doc = window->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + // This would typically happen during shutdown if there is an active worker + // listening for document events. The Document may already be freed when we + // try to deregister for notifications. + return; + } + + if (aListen) { + doc->AddWorkerDocumentListener(this); + } else { + doc->RemoveWorkerDocumentListener(this); + } +} + +void WorkerDocumentListener::Destroy() { + MutexAutoLock lock(mMutex); + + MOZ_ASSERT(mWorkerRef); + WorkerPrivate* workerPrivate = mWorkerRef->Private(); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + uint64_t windowID = workerPrivate->WindowID(); + workerPrivate->DispatchToMainThread(NS_NewRunnableFunction( + "WorkerDocumentListener::Destroy", [self = RefPtr{this}, windowID] { + self->SetListening(windowID, false); + })); + mWorkerRef = nullptr; +} + +} // namespace mozilla::dom |