Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 "mozilla/dom/Promise.h"
8 : #include "nsIDocShell.h"
9 : #include "nsIInterfaceRequestorUtils.h"
10 : #include "nsIPresentationService.h"
11 : #include "nsIWebProgress.h"
12 : #include "nsServiceManagerUtils.h"
13 : #include "nsThreadUtils.h"
14 : #include "PresentationCallbacks.h"
15 : #include "PresentationRequest.h"
16 : #include "PresentationConnection.h"
17 : #include "PresentationTransportBuilderConstructor.h"
18 :
19 : using namespace mozilla;
20 : using namespace mozilla::dom;
21 :
22 : /*
23 : * Implementation of PresentationRequesterCallback
24 : */
25 :
26 0 : NS_IMPL_ISUPPORTS(PresentationRequesterCallback, nsIPresentationServiceCallback)
27 :
28 0 : PresentationRequesterCallback::PresentationRequesterCallback(PresentationRequest* aRequest,
29 : const nsAString& aSessionId,
30 0 : Promise* aPromise)
31 : : mRequest(aRequest)
32 : , mSessionId(aSessionId)
33 0 : , mPromise(aPromise)
34 : {
35 0 : MOZ_ASSERT(mRequest);
36 0 : MOZ_ASSERT(mPromise);
37 0 : MOZ_ASSERT(!mSessionId.IsEmpty());
38 0 : }
39 :
40 0 : PresentationRequesterCallback::~PresentationRequesterCallback()
41 : {
42 0 : }
43 :
44 : // nsIPresentationServiceCallback
45 : NS_IMETHODIMP
46 0 : PresentationRequesterCallback::NotifySuccess(const nsAString& aUrl)
47 : {
48 0 : MOZ_ASSERT(NS_IsMainThread());
49 :
50 0 : if (aUrl.IsEmpty()) {
51 0 : return NotifyError(NS_ERROR_DOM_OPERATION_ERR);
52 : }
53 :
54 : RefPtr<PresentationConnection> connection =
55 0 : PresentationConnection::Create(mRequest->GetOwner(), mSessionId, aUrl,
56 0 : nsIPresentationService::ROLE_CONTROLLER);
57 0 : if (NS_WARN_IF(!connection)) {
58 0 : return NotifyError(NS_ERROR_DOM_OPERATION_ERR);
59 : }
60 :
61 0 : mRequest->NotifyPromiseSettled();
62 0 : mPromise->MaybeResolve(connection);
63 :
64 0 : return mRequest->DispatchConnectionAvailableEvent(connection);
65 : }
66 :
67 : NS_IMETHODIMP
68 0 : PresentationRequesterCallback::NotifyError(nsresult aError)
69 : {
70 0 : MOZ_ASSERT(NS_IsMainThread());
71 :
72 0 : mRequest->NotifyPromiseSettled();
73 0 : mPromise->MaybeReject(aError);
74 0 : return NS_OK;
75 : }
76 :
77 : /*
78 : * Implementation of PresentationRequesterCallback
79 : */
80 :
81 0 : NS_IMPL_ISUPPORTS_INHERITED0(PresentationReconnectCallback,
82 : PresentationRequesterCallback)
83 :
84 0 : PresentationReconnectCallback::PresentationReconnectCallback(
85 : PresentationRequest* aRequest,
86 : const nsAString& aSessionId,
87 : Promise* aPromise,
88 0 : PresentationConnection* aConnection)
89 : : PresentationRequesterCallback(aRequest, aSessionId, aPromise)
90 0 : , mConnection(aConnection)
91 : {
92 0 : }
93 :
94 0 : PresentationReconnectCallback::~PresentationReconnectCallback()
95 : {
96 0 : }
97 :
98 : NS_IMETHODIMP
99 0 : PresentationReconnectCallback::NotifySuccess(const nsAString& aUrl)
100 : {
101 0 : MOZ_ASSERT(NS_IsMainThread());
102 :
103 : nsCOMPtr<nsIPresentationService> service =
104 0 : do_GetService(PRESENTATION_SERVICE_CONTRACTID);
105 0 : if (NS_WARN_IF(!service)) {
106 0 : return NS_ERROR_NOT_AVAILABLE;
107 : }
108 :
109 0 : nsresult rv = NS_OK;
110 : // We found a matched connection with the same window ID, URL, and
111 : // the session ID. Resolve the promise with this connection and dispatch
112 : // the event.
113 0 : if (mConnection) {
114 0 : mConnection->NotifyStateChange(
115 : mSessionId,
116 : nsIPresentationSessionListener::STATE_CONNECTING,
117 0 : NS_OK);
118 0 : mPromise->MaybeResolve(mConnection);
119 0 : rv = mRequest->DispatchConnectionAvailableEvent(mConnection);
120 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
121 0 : return rv;
122 : }
123 : } else {
124 : // Use |PresentationRequesterCallback::NotifySuccess| to create a new
125 : // connection since we don't find one that can be reused.
126 0 : rv = PresentationRequesterCallback::NotifySuccess(aUrl);
127 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
128 0 : return rv;
129 : }
130 :
131 0 : rv = service->UpdateWindowIdBySessionId(mSessionId,
132 : nsIPresentationService::ROLE_CONTROLLER,
133 0 : mRequest->GetOwner()->WindowID());
134 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
135 0 : return rv;
136 : }
137 : }
138 :
139 0 : nsString sessionId = nsString(mSessionId);
140 0 : return NS_DispatchToMainThread(NS_NewRunnableFunction(
141 : "dom::PresentationReconnectCallback::NotifySuccess",
142 0 : [sessionId, service]() -> void {
143 0 : service->BuildTransport(sessionId,
144 0 : nsIPresentationService::ROLE_CONTROLLER);
145 0 : }));
146 : }
147 :
148 : NS_IMETHODIMP
149 0 : PresentationReconnectCallback::NotifyError(nsresult aError)
150 : {
151 0 : if (mConnection) {
152 0 : mConnection->NotifyStateChange(
153 : mSessionId,
154 : nsIPresentationSessionListener::STATE_CLOSED,
155 0 : aError);
156 : }
157 0 : return PresentationRequesterCallback::NotifyError(aError);
158 : }
159 :
160 0 : NS_IMPL_ISUPPORTS(PresentationResponderLoadingCallback,
161 : nsIWebProgressListener,
162 : nsISupportsWeakReference)
163 :
164 0 : PresentationResponderLoadingCallback::PresentationResponderLoadingCallback(const nsAString& aSessionId)
165 0 : : mSessionId(aSessionId)
166 : {
167 0 : }
168 :
169 0 : PresentationResponderLoadingCallback::~PresentationResponderLoadingCallback()
170 : {
171 0 : if (mProgress) {
172 0 : mProgress->RemoveProgressListener(this);
173 0 : mProgress = nullptr;
174 : }
175 0 : }
176 :
177 : nsresult
178 0 : PresentationResponderLoadingCallback::Init(nsIDocShell* aDocShell)
179 : {
180 0 : mProgress = do_GetInterface(aDocShell);
181 0 : if (NS_WARN_IF(!mProgress)) {
182 0 : return NS_ERROR_NOT_AVAILABLE;
183 : }
184 :
185 0 : uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
186 0 : nsresult rv = aDocShell->GetBusyFlags(&busyFlags);
187 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
188 0 : return rv;
189 : }
190 :
191 0 : if ((busyFlags == nsIDocShell::BUSY_FLAGS_NONE) ||
192 0 : (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING)) {
193 : // The docshell has finished loading or is receiving data (|STATE_TRANSFERRING|
194 : // has already been fired), so the page is ready for presentation use.
195 0 : return NotifyReceiverReady(/* isLoading = */ true);
196 : }
197 :
198 : // Start to listen to document state change event |STATE_TRANSFERRING|.
199 0 : return mProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
200 : }
201 :
202 : nsresult
203 0 : PresentationResponderLoadingCallback::NotifyReceiverReady(bool aIsLoading)
204 : {
205 0 : nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(mProgress);
206 0 : if (NS_WARN_IF(!window || !window->GetCurrentInnerWindow())) {
207 0 : return NS_ERROR_NOT_AVAILABLE;
208 : }
209 0 : uint64_t windowId = window->GetCurrentInnerWindow()->WindowID();
210 :
211 : nsCOMPtr<nsIPresentationService> service =
212 0 : do_GetService(PRESENTATION_SERVICE_CONTRACTID);
213 0 : if (NS_WARN_IF(!service)) {
214 0 : return NS_ERROR_NOT_AVAILABLE;
215 : }
216 :
217 : nsCOMPtr<nsIPresentationTransportBuilderConstructor> constructor =
218 0 : PresentationTransportBuilderConstructor::Create();
219 0 : return service->NotifyReceiverReady(mSessionId,
220 : windowId,aIsLoading,
221 0 : constructor);
222 : }
223 :
224 : // nsIWebProgressListener
225 : NS_IMETHODIMP
226 0 : PresentationResponderLoadingCallback::OnStateChange(nsIWebProgress* aWebProgress,
227 : nsIRequest* aRequest,
228 : uint32_t aStateFlags,
229 : nsresult aStatus)
230 : {
231 0 : MOZ_ASSERT(NS_IsMainThread());
232 :
233 0 : if (aStateFlags & (nsIWebProgressListener::STATE_TRANSFERRING |
234 : nsIWebProgressListener::STATE_STOP)) {
235 0 : mProgress->RemoveProgressListener(this);
236 :
237 0 : bool isLoading = aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING;
238 0 : return NotifyReceiverReady(isLoading);
239 : }
240 :
241 0 : return NS_OK;
242 : }
243 :
244 : NS_IMETHODIMP
245 0 : PresentationResponderLoadingCallback::OnProgressChange(nsIWebProgress* aWebProgress,
246 : nsIRequest* aRequest,
247 : int32_t aCurSelfProgress,
248 : int32_t aMaxSelfProgress,
249 : int32_t aCurTotalProgress,
250 : int32_t aMaxTotalProgress)
251 : {
252 : // Do nothing.
253 0 : return NS_OK;
254 : }
255 :
256 : NS_IMETHODIMP
257 0 : PresentationResponderLoadingCallback::OnLocationChange(nsIWebProgress* aWebProgress,
258 : nsIRequest* aRequest,
259 : nsIURI* aURI,
260 : uint32_t aFlags)
261 : {
262 : // Do nothing.
263 0 : return NS_OK;
264 : }
265 :
266 : NS_IMETHODIMP
267 0 : PresentationResponderLoadingCallback::OnStatusChange(nsIWebProgress* aWebProgress,
268 : nsIRequest* aRequest,
269 : nsresult aStatus,
270 : const char16_t* aMessage)
271 : {
272 : // Do nothing.
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : PresentationResponderLoadingCallback::OnSecurityChange(nsIWebProgress* aWebProgress,
278 : nsIRequest* aRequest,
279 : uint32_t state)
280 : {
281 : // Do nothing.
282 0 : return NS_OK;
283 : }
|