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/. */
7 #include "WorkerDocumentListener.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/WorkerPrivate.h"
10 #include "mozilla/dom/WorkerRef.h"
11 #include "mozilla/dom/WorkerRunnable.h"
12 #include "mozilla/dom/WorkerScope.h"
13 #include "nsGlobalWindowInner.h"
15 namespace mozilla::dom
{
17 WorkerDocumentListener::WorkerDocumentListener()
18 : mMutex("mozilla::dom::WorkerDocumentListener::mMutex") {}
20 WorkerDocumentListener::~WorkerDocumentListener() = default;
22 RefPtr
<WorkerDocumentListener
> WorkerDocumentListener::Create(
23 WorkerPrivate
* aWorkerPrivate
) {
24 MOZ_ASSERT(aWorkerPrivate
);
25 aWorkerPrivate
->AssertIsOnWorkerThread();
27 auto listener
= MakeRefPtr
<WorkerDocumentListener
>();
29 RefPtr
<StrongWorkerRef
> strongWorkerRef
=
30 StrongWorkerRef::Create(aWorkerPrivate
, "WorkerDocumentListener",
31 [listener
]() { listener
->Destroy(); });
32 if (NS_WARN_IF(!strongWorkerRef
)) {
36 listener
->mWorkerRef
= new ThreadSafeWorkerRef(strongWorkerRef
);
37 uint64_t windowID
= aWorkerPrivate
->WindowID();
39 aWorkerPrivate
->DispatchToMainThread(NS_NewRunnableFunction(
40 "WorkerDocumentListener::Create",
41 [listener
, windowID
] { listener
->SetListening(windowID
, true); }));
46 void WorkerDocumentListener::OnVisible(bool aVisible
) {
47 MOZ_ASSERT(NS_IsMainThread());
49 MutexAutoLock
lock(mMutex
);
51 // We haven't handled the runnable to release this yet.
55 class VisibleRunnable final
: public WorkerThreadRunnable
{
57 VisibleRunnable(WorkerPrivate
* aWorkerPrivate
, bool aVisible
)
58 : WorkerThreadRunnable("VisibleRunnable"), mVisible(aVisible
) {}
60 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) {
61 WorkerGlobalScope
* scope
= aWorkerPrivate
->GlobalScope();
63 scope
->OnDocumentVisible(mVisible
);
71 auto runnable
= MakeRefPtr
<VisibleRunnable
>(mWorkerRef
->Private(), aVisible
);
72 runnable
->Dispatch(mWorkerRef
->Private());
75 void WorkerDocumentListener::SetListening(uint64_t aWindowID
, bool aListen
) {
76 MOZ_ASSERT(NS_IsMainThread());
78 auto* window
= nsGlobalWindowInner::GetInnerWindowWithId(aWindowID
);
79 Document
* doc
= window
->GetExtantDoc();
80 if (NS_WARN_IF(!doc
)) {
81 // This would typically happen during shutdown if there is an active worker
82 // listening for document events. The Document may already be freed when we
83 // try to deregister for notifications.
88 doc
->AddWorkerDocumentListener(this);
90 doc
->RemoveWorkerDocumentListener(this);
94 void WorkerDocumentListener::Destroy() {
95 MutexAutoLock
lock(mMutex
);
97 MOZ_ASSERT(mWorkerRef
);
98 WorkerPrivate
* workerPrivate
= mWorkerRef
->Private();
99 MOZ_ASSERT(workerPrivate
);
100 workerPrivate
->AssertIsOnWorkerThread();
102 uint64_t windowID
= workerPrivate
->WindowID();
103 workerPrivate
->DispatchToMainThread(NS_NewRunnableFunction(
104 "WorkerDocumentListener::Destroy", [self
= RefPtr
{this}, windowID
] {
105 self
->SetListening(windowID
, false);
107 mWorkerRef
= nullptr;
110 } // namespace mozilla::dom