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/. */
9 #include "ClientDOMUtil.h"
10 #include "mozilla/dom/ClientHandle.h"
11 #include "mozilla/dom/ClientIPCTypes.h"
12 #include "mozilla/dom/ClientManager.h"
13 #include "mozilla/dom/ClientState.h"
14 #include "mozilla/dom/DOMMozPromiseRequestHolder.h"
15 #include "mozilla/dom/MessagePortBinding.h"
16 #include "mozilla/dom/Promise.h"
17 #include "mozilla/dom/WorkerScope.h"
18 #include "nsIDUtils.h"
19 #include "nsIGlobalObject.h"
21 namespace mozilla::dom
{
23 using mozilla::dom::ipc::StructuredCloneData
;
25 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::Client
);
26 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::Client
);
27 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::Client
, mGlobal
);
29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(mozilla::dom::Client
)
30 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
31 NS_INTERFACE_MAP_ENTRY(nsISupports
)
34 void Client::EnsureHandle() {
35 NS_ASSERT_OWNINGTHREAD(mozilla::dom::Client
);
37 mHandle
= ClientManager::CreateHandle(ClientInfo(mData
->info()),
38 mGlobal
->SerialEventTarget());
42 Client::Client(nsIGlobalObject
* aGlobal
, const ClientInfoAndState
& aData
)
43 : mGlobal(aGlobal
), mData(MakeUnique
<ClientInfoAndState
>(aData
)) {
44 MOZ_DIAGNOSTIC_ASSERT(mGlobal
);
47 TimeStamp
Client::CreationTime() const { return mData
->info().creationTime(); }
49 TimeStamp
Client::LastFocusTime() const {
50 if (mData
->info().type() != ClientType::Window
) {
53 return mData
->state().get_IPCClientWindowState().lastFocusTime();
56 StorageAccess
Client::GetStorageAccess() const {
57 ClientState
state(ClientState::FromIPC(mData
->state()));
58 return state
.GetStorageAccess();
61 JSObject
* Client::WrapObject(JSContext
* aCx
,
62 JS::Handle
<JSObject
*> aGivenProto
) {
63 if (mData
->info().type() == ClientType::Window
) {
64 return WindowClient_Binding::Wrap(aCx
, this, aGivenProto
);
66 return Client_Binding::Wrap(aCx
, this, aGivenProto
);
69 nsIGlobalObject
* Client::GetParentObject() const { return mGlobal
; }
71 void Client::GetUrl(nsAString
& aUrlOut
) const {
72 CopyUTF8toUTF16(mData
->info().url(), aUrlOut
);
75 void Client::GetId(nsAString
& aIdOut
) const {
76 aIdOut
= NSID_TrimBracketsUTF16(mData
->info().id());
79 ClientType
Client::Type() const { return mData
->info().type(); }
81 FrameType
Client::GetFrameType() const { return mData
->info().frameType(); }
83 void Client::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
84 const Sequence
<JSObject
*>& aTransferable
,
86 MOZ_ASSERT(!NS_IsMainThread());
87 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
88 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
);
89 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
->IsServiceWorker());
90 workerPrivate
->AssertIsOnWorkerThread();
92 JS::Rooted
<JS::Value
> transferable(aCx
, JS::UndefinedValue());
93 aRv
= nsContentUtils::CreateJSValueFromSequenceOfObject(aCx
, aTransferable
,
99 StructuredCloneData data
;
100 data
.Write(aCx
, aMessage
, transferable
, JS::CloneDataPolicy(), aRv
);
106 mHandle
->PostMessage(data
, workerPrivate
->GetServiceWorkerDescriptor());
109 void Client::PostMessage(JSContext
* aCx
, JS::Handle
<JS::Value
> aMessage
,
110 const StructuredSerializeOptions
& aOptions
,
112 PostMessage(aCx
, aMessage
, aOptions
.mTransfer
, aRv
);
115 VisibilityState
Client::GetVisibilityState() const {
116 return mData
->state().get_IPCClientWindowState().visibilityState();
119 bool Client::Focused() const {
120 return mData
->state().get_IPCClientWindowState().focused();
123 already_AddRefed
<Promise
> Client::Focus(CallerType aCallerType
,
125 MOZ_ASSERT(!NS_IsMainThread());
126 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
127 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
);
128 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
->IsServiceWorker());
129 workerPrivate
->AssertIsOnWorkerThread();
131 RefPtr
<Promise
> outerPromise
= Promise::Create(mGlobal
, aRv
);
133 return outerPromise
.forget();
136 if (!workerPrivate
->GlobalScope()->WindowInteractionAllowed()) {
137 outerPromise
->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
138 return outerPromise
.forget();
143 IPCClientInfo
ipcClientInfo(mData
->info());
145 MakeRefPtr
<DOMMozPromiseRequestHolder
<ClientStatePromise
>>(mGlobal
);
147 mHandle
->Focus(aCallerType
)
149 mGlobal
->SerialEventTarget(), __func__
,
150 [ipcClientInfo
, holder
, outerPromise
](const ClientState
& aResult
) {
152 NS_ENSURE_TRUE_VOID(holder
->GetParentObject());
153 RefPtr
<Client
> newClient
=
154 new Client(holder
->GetParentObject(),
155 ClientInfoAndState(ipcClientInfo
, aResult
.ToIPC()));
156 outerPromise
->MaybeResolve(newClient
);
158 [holder
, outerPromise
](const CopyableErrorResult
& aResult
) {
160 // MaybeReject needs a non-const-ref result, so make a copy.
161 outerPromise
->MaybeReject(CopyableErrorResult(aResult
));
165 return outerPromise
.forget();
168 already_AddRefed
<Promise
> Client::Navigate(const nsAString
& aURL
,
170 MOZ_ASSERT(!NS_IsMainThread());
171 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
172 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
);
173 MOZ_DIAGNOSTIC_ASSERT(workerPrivate
->IsServiceWorker());
174 workerPrivate
->AssertIsOnWorkerThread();
176 RefPtr
<Promise
> outerPromise
= Promise::Create(mGlobal
, aRv
);
178 return outerPromise
.forget();
181 ClientNavigateArgs
args(mData
->info(), NS_ConvertUTF16toUTF8(aURL
),
182 workerPrivate
->GetLocationInfo().mHref
,
183 workerPrivate
->GetServiceWorkerDescriptor().ToIPC());
184 RefPtr
<Client
> self
= this;
186 StartClientManagerOp(
187 &ClientManager::Navigate
, args
, mGlobal
,
188 [self
, outerPromise
](const ClientOpResult
& aResult
) {
189 if (aResult
.type() != ClientOpResult::TClientInfoAndState
) {
190 outerPromise
->MaybeResolve(JS::NullHandleValue
);
193 RefPtr
<Client
> newClient
=
194 new Client(self
->mGlobal
, aResult
.get_ClientInfoAndState());
195 outerPromise
->MaybeResolve(newClient
);
197 [self
, outerPromise
](const CopyableErrorResult
& aResult
) {
198 // MaybeReject needs a non-const-ref result, so make a copy.
199 outerPromise
->MaybeReject(CopyableErrorResult(aResult
));
202 return outerPromise
.forget();
205 } // namespace mozilla::dom