Client.cpp (7208B)
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 #include "Client.h" 8 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" 20 21 namespace mozilla::dom { 22 23 using mozilla::dom::ipc::StructuredCloneData; 24 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); 28 29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(mozilla::dom::Client) 30 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 31 NS_INTERFACE_MAP_ENTRY(nsISupports) 32 NS_INTERFACE_MAP_END 33 34 void Client::EnsureHandle() { 35 NS_ASSERT_OWNINGTHREAD(mozilla::dom::Client); 36 if (!mHandle) { 37 mHandle = ClientManager::CreateHandle(ClientInfo(mData->info()), 38 mGlobal->SerialEventTarget()); 39 } 40 } 41 42 Client::Client(nsIGlobalObject* aGlobal, const ClientInfoAndState& aData) 43 : mGlobal(aGlobal), mData(MakeUnique<ClientInfoAndState>(aData)) { 44 MOZ_DIAGNOSTIC_ASSERT(mGlobal); 45 } 46 47 TimeStamp Client::CreationTime() const { return mData->info().creationTime(); } 48 49 TimeStamp Client::LastFocusTime() const { 50 if (mData->info().type() != ClientType::Window) { 51 return TimeStamp(); 52 } 53 return mData->state().get_IPCClientWindowState().lastFocusTime(); 54 } 55 56 StorageAccess Client::GetStorageAccess() const { 57 ClientState state(ClientState::FromIPC(mData->state())); 58 return state.GetStorageAccess(); 59 } 60 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); 65 } 66 return Client_Binding::Wrap(aCx, this, aGivenProto); 67 } 68 69 nsIGlobalObject* Client::GetParentObject() const { return mGlobal; } 70 71 void Client::GetUrl(nsAString& aUrlOut) const { 72 CopyUTF8toUTF16(mData->info().url(), aUrlOut); 73 } 74 75 void Client::GetId(nsAString& aIdOut) const { 76 aIdOut = NSID_TrimBracketsUTF16(mData->info().id()); 77 } 78 79 ClientType Client::Type() const { return mData->info().type(); } 80 81 FrameType Client::GetFrameType() const { return mData->info().frameType(); } 82 83 void Client::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, 84 const Sequence<JSObject*>& aTransferable, 85 ErrorResult& aRv) { 86 MOZ_ASSERT(!NS_IsMainThread()); 87 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 88 MOZ_DIAGNOSTIC_ASSERT(workerPrivate); 89 MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker()); 90 workerPrivate->AssertIsOnWorkerThread(); 91 92 JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue()); 93 aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable, 94 &transferable); 95 if (aRv.Failed()) { 96 return; 97 } 98 99 StructuredCloneData data; 100 data.Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), aRv); 101 if (aRv.Failed()) { 102 return; 103 } 104 105 EnsureHandle(); 106 mHandle->PostMessage(data, workerPrivate->GetServiceWorkerDescriptor()); 107 } 108 109 void Client::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, 110 const StructuredSerializeOptions& aOptions, 111 ErrorResult& aRv) { 112 PostMessage(aCx, aMessage, aOptions.mTransfer, aRv); 113 } 114 115 VisibilityState Client::GetVisibilityState() const { 116 return mData->state().get_IPCClientWindowState().visibilityState(); 117 } 118 119 bool Client::Focused() const { 120 return mData->state().get_IPCClientWindowState().focused(); 121 } 122 123 already_AddRefed<Promise> Client::Focus(CallerType aCallerType, 124 ErrorResult& aRv) { 125 MOZ_ASSERT(!NS_IsMainThread()); 126 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 127 MOZ_DIAGNOSTIC_ASSERT(workerPrivate); 128 MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker()); 129 workerPrivate->AssertIsOnWorkerThread(); 130 131 RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv); 132 if (aRv.Failed()) { 133 return outerPromise.forget(); 134 } 135 136 if (!workerPrivate->GlobalScope()->WindowInteractionAllowed()) { 137 outerPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR); 138 return outerPromise.forget(); 139 } 140 141 EnsureHandle(); 142 143 IPCClientInfo ipcClientInfo(mData->info()); 144 auto holder = 145 MakeRefPtr<DOMMozPromiseRequestHolder<ClientStatePromise>>(mGlobal); 146 147 mHandle->Focus(aCallerType) 148 ->Then( 149 mGlobal->SerialEventTarget(), __func__, 150 [ipcClientInfo, holder, outerPromise](const ClientState& aResult) { 151 holder->Complete(); 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); 157 }, 158 [holder, outerPromise](const CopyableErrorResult& aResult) { 159 holder->Complete(); 160 // MaybeReject needs a non-const-ref result, so make a copy. 161 outerPromise->MaybeReject(CopyableErrorResult(aResult)); 162 }) 163 ->Track(*holder); 164 165 return outerPromise.forget(); 166 } 167 168 already_AddRefed<Promise> Client::Navigate(const nsAString& aURL, 169 ErrorResult& aRv) { 170 MOZ_ASSERT(!NS_IsMainThread()); 171 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); 172 MOZ_DIAGNOSTIC_ASSERT(workerPrivate); 173 MOZ_DIAGNOSTIC_ASSERT(workerPrivate->IsServiceWorker()); 174 workerPrivate->AssertIsOnWorkerThread(); 175 176 RefPtr<Promise> outerPromise = Promise::Create(mGlobal, aRv); 177 if (aRv.Failed()) { 178 return outerPromise.forget(); 179 } 180 181 ClientNavigateArgs args(mData->info(), NS_ConvertUTF16toUTF8(aURL), 182 workerPrivate->GetLocationInfo().mHref, 183 workerPrivate->GetServiceWorkerDescriptor().ToIPC()); 184 RefPtr<Client> self = this; 185 186 StartClientManagerOp( 187 &ClientManager::Navigate, args, mGlobal, 188 [self, outerPromise](const ClientOpResult& aResult) { 189 if (aResult.type() != ClientOpResult::TClientInfoAndState) { 190 outerPromise->MaybeResolve(JS::NullHandleValue); 191 return; 192 } 193 RefPtr<Client> newClient = 194 new Client(self->mGlobal, aResult.get_ClientInfoAndState()); 195 outerPromise->MaybeResolve(newClient); 196 }, 197 [self, outerPromise](const CopyableErrorResult& aResult) { 198 // MaybeReject needs a non-const-ref result, so make a copy. 199 outerPromise->MaybeReject(CopyableErrorResult(aResult)); 200 }); 201 202 return outerPromise.forget(); 203 } 204 205 } // namespace mozilla::dom