Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / dom / base / DOMRequest.cpp
blob6226cb5cbb6ac31745be429a6498c3991cfbbaa4
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DOMRequest.h"
9 #include "DOMException.h"
10 #include "nsThreadUtils.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/dom/Event.h"
13 #include "mozilla/dom/Promise.h"
14 #include "mozilla/dom/ScriptSettings.h"
15 #include "jsfriendapi.h"
16 #include "nsContentUtils.h"
18 using mozilla::dom::AnyCallback;
19 using mozilla::dom::AutoJSAPI;
20 using mozilla::dom::DOMException;
21 using mozilla::dom::DOMRequest;
22 using mozilla::dom::DOMRequestService;
23 using mozilla::dom::Promise;
24 using mozilla::dom::RootingCx;
26 DOMRequest::DOMRequest(nsPIDOMWindowInner* aWindow)
27 : DOMEventTargetHelper(aWindow),
28 mResult(JS::UndefinedValue()),
29 mDone(false) {}
31 DOMRequest::DOMRequest(nsIGlobalObject* aGlobal)
32 : DOMEventTargetHelper(aGlobal),
33 mResult(JS::UndefinedValue()),
34 mDone(false) {}
36 DOMRequest::~DOMRequest() {
37 mResult.setUndefined();
38 mozilla::DropJSObjects(this);
41 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
44 DOMEventTargetHelper)
45 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
46 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
49 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
50 DOMEventTargetHelper)
51 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
52 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
53 tmp->mResult.setUndefined();
54 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
56 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest, DOMEventTargetHelper)
57 // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
58 // DOMEventTargetHelper does it for us.
59 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResult)
60 NS_IMPL_CYCLE_COLLECTION_TRACE_END
62 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMRequest)
63 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
65 NS_IMPL_ADDREF_INHERITED(DOMRequest, DOMEventTargetHelper)
66 NS_IMPL_RELEASE_INHERITED(DOMRequest, DOMEventTargetHelper)
68 /* virtual */
69 JSObject* DOMRequest::WrapObject(JSContext* aCx,
70 JS::Handle<JSObject*> aGivenProto) {
71 return DOMRequest_Binding::Wrap(aCx, this, aGivenProto);
74 void DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult) {
75 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
76 NS_ASSERTION(!mError, "mError shouldn't have been set!");
77 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
79 mDone = true;
80 if (aResult.isGCThing()) {
81 RootResultVal();
83 mResult = aResult;
85 FireEvent(NS_LITERAL_STRING("success"), false, false);
87 if (mPromise) {
88 mPromise->MaybeResolve(mResult);
92 void DOMRequest::FireError(const nsAString& aError) {
93 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
94 NS_ASSERTION(!mError, "mError shouldn't have been set!");
95 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
97 mDone = true;
98 // XXX Error code chosen arbitrarily
99 mError = DOMException::Create(NS_ERROR_DOM_UNKNOWN_ERR,
100 NS_ConvertUTF16toUTF8(aError));
102 FireEvent(NS_LITERAL_STRING("error"), true, true);
104 if (mPromise) {
105 mPromise->MaybeRejectBrokenly(mError);
109 void DOMRequest::FireError(nsresult aError) {
110 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
111 NS_ASSERTION(!mError, "mError shouldn't have been set!");
112 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
114 mDone = true;
115 mError = DOMException::Create(aError);
117 FireEvent(NS_LITERAL_STRING("error"), true, true);
119 if (mPromise) {
120 mPromise->MaybeRejectBrokenly(mError);
124 void DOMRequest::FireDetailedError(DOMException& aError) {
125 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
126 NS_ASSERTION(!mError, "mError shouldn't have been set!");
127 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
129 mDone = true;
130 mError = &aError;
132 FireEvent(NS_LITERAL_STRING("error"), true, true);
134 if (mPromise) {
135 mPromise->MaybeRejectBrokenly(mError);
139 void DOMRequest::FireEvent(const nsAString& aType, bool aBubble,
140 bool aCancelable) {
141 if (NS_FAILED(CheckCurrentGlobalCorrectness())) {
142 return;
145 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
146 event->InitEvent(aType, aBubble, aCancelable);
147 event->SetTrusted(true);
149 DispatchEvent(*event);
152 void DOMRequest::RootResultVal() { mozilla::HoldJSObjects(this); }
154 void DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback,
155 AnyCallback* aRejectCallback,
156 JS::MutableHandle<JS::Value> aRetval,
157 mozilla::ErrorResult& aRv) {
158 if (!mPromise) {
159 mPromise = Promise::Create(DOMEventTargetHelper::GetParentObject(), aRv);
160 if (aRv.Failed()) {
161 return;
163 if (mDone) {
164 // Since we create mPromise lazily, it's possible that the DOMRequest
165 // object has already fired its success/error event. In that case we
166 // should manually resolve/reject mPromise here. mPromise will take care
167 // of calling the callbacks on |promise| as needed.
168 if (mError) {
169 mPromise->MaybeRejectBrokenly(mError);
170 } else {
171 mPromise->MaybeResolve(mResult);
176 // Just use the global of the Promise itself as the callee global.
177 JS::Rooted<JSObject*> global(aCx, mPromise->PromiseObj());
178 global = JS::GetNonCCWObjectGlobal(global);
179 mPromise->Then(aCx, global, aResolveCallback, aRejectCallback, aRetval, aRv);
182 NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)
184 NS_IMETHODIMP
185 DOMRequestService::CreateRequest(mozIDOMWindow* aWindow,
186 DOMRequest** aRequest) {
187 MOZ_ASSERT(NS_IsMainThread());
188 NS_ENSURE_STATE(aWindow);
189 auto* win = nsPIDOMWindowInner::From(aWindow);
190 RefPtr<DOMRequest> req = new DOMRequest(win);
191 req.forget(aRequest);
193 return NS_OK;
196 NS_IMETHODIMP
197 DOMRequestService::FireSuccess(DOMRequest* aRequest,
198 JS::Handle<JS::Value> aResult) {
199 NS_ENSURE_STATE(aRequest);
200 aRequest->FireSuccess(aResult);
202 return NS_OK;
205 NS_IMETHODIMP
206 DOMRequestService::FireError(DOMRequest* aRequest, const nsAString& aError) {
207 NS_ENSURE_STATE(aRequest);
208 aRequest->FireError(aError);
210 return NS_OK;
213 class FireSuccessAsyncTask : public mozilla::Runnable {
214 FireSuccessAsyncTask(DOMRequest* aRequest, const JS::Value& aResult)
215 : mozilla::Runnable("FireSuccessAsyncTask"),
216 mReq(aRequest),
217 mResult(RootingCx(), aResult) {}
219 public:
220 // Due to the fact that initialization can fail during shutdown (since we
221 // can't fetch a js context), set up an initiatization function to make sure
222 // we can return the failure appropriately
223 static nsresult Dispatch(DOMRequest* aRequest, const JS::Value& aResult) {
224 RefPtr<FireSuccessAsyncTask> asyncTask =
225 new FireSuccessAsyncTask(aRequest, aResult);
226 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask));
227 return NS_OK;
230 NS_IMETHOD
231 Run() override {
232 mReq->FireSuccess(
233 JS::Handle<JS::Value>::fromMarkedLocation(mResult.address()));
234 return NS_OK;
237 private:
238 RefPtr<DOMRequest> mReq;
239 JS::PersistentRooted<JS::Value> mResult;
242 class FireErrorAsyncTask : public mozilla::Runnable {
243 public:
244 FireErrorAsyncTask(DOMRequest* aRequest, const nsAString& aError)
245 : mozilla::Runnable("FireErrorAsyncTask"),
246 mReq(aRequest),
247 mError(aError) {}
249 NS_IMETHOD
250 Run() override {
251 mReq->FireError(mError);
252 return NS_OK;
255 private:
256 RefPtr<DOMRequest> mReq;
257 nsString mError;
260 NS_IMETHODIMP
261 DOMRequestService::FireSuccessAsync(DOMRequest* aRequest,
262 JS::Handle<JS::Value> aResult) {
263 NS_ENSURE_STATE(aRequest);
264 return FireSuccessAsyncTask::Dispatch(aRequest, aResult);
267 NS_IMETHODIMP
268 DOMRequestService::FireErrorAsync(DOMRequest* aRequest,
269 const nsAString& aError) {
270 NS_ENSURE_STATE(aRequest);
271 nsCOMPtr<nsIRunnable> asyncTask = new FireErrorAsyncTask(aRequest, aError);
272 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask));
273 return NS_OK;