Bug 1700051: part 35) Reduce accessibility of `mSoftText.mDOMMapping` to `private...
[gecko.git] / dom / base / DOMRequest.cpp
blobbebcb6fdcfac6338a2a0375e471d61d04977d484
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/HoldDropJSObjects.h"
12 #include "mozilla/ErrorResult.h"
13 #include "mozilla/dom/Event.h"
14 #include "mozilla/dom/Promise.h"
15 #include "mozilla/dom/ScriptSettings.h"
16 #include "jsfriendapi.h"
17 #include "nsContentUtils.h"
19 using mozilla::dom::AnyCallback;
20 using mozilla::dom::AutoJSAPI;
21 using mozilla::dom::DOMException;
22 using mozilla::dom::DOMRequest;
23 using mozilla::dom::DOMRequestService;
24 using mozilla::dom::Promise;
25 using mozilla::dom::RootingCx;
27 DOMRequest::DOMRequest(nsPIDOMWindowInner* aWindow)
28 : DOMEventTargetHelper(aWindow),
29 mResult(JS::UndefinedValue()),
30 mDone(false) {}
32 DOMRequest::DOMRequest(nsIGlobalObject* aGlobal)
33 : DOMEventTargetHelper(aGlobal),
34 mResult(JS::UndefinedValue()),
35 mDone(false) {}
37 DOMRequest::~DOMRequest() {
38 mResult.setUndefined();
39 mozilla::DropJSObjects(this);
42 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
45 DOMEventTargetHelper)
46 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
48 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
50 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
51 DOMEventTargetHelper)
52 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
53 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
54 tmp->mResult.setUndefined();
55 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
57 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest, DOMEventTargetHelper)
58 // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
59 // DOMEventTargetHelper does it for us.
60 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResult)
61 NS_IMPL_CYCLE_COLLECTION_TRACE_END
63 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMRequest)
64 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
66 NS_IMPL_ADDREF_INHERITED(DOMRequest, DOMEventTargetHelper)
67 NS_IMPL_RELEASE_INHERITED(DOMRequest, DOMEventTargetHelper)
69 /* virtual */
70 JSObject* DOMRequest::WrapObject(JSContext* aCx,
71 JS::Handle<JSObject*> aGivenProto) {
72 return DOMRequest_Binding::Wrap(aCx, this, aGivenProto);
75 void DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult) {
76 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
77 NS_ASSERTION(!mError, "mError shouldn't have been set!");
78 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
80 mDone = true;
81 if (aResult.isGCThing()) {
82 RootResultVal();
84 mResult = aResult;
86 FireEvent(u"success"_ns, false, false);
88 if (mPromise) {
89 mPromise->MaybeResolve(mResult);
93 void DOMRequest::FireError(const nsAString& aError) {
94 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
95 NS_ASSERTION(!mError, "mError shouldn't have been set!");
96 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
98 mDone = true;
99 // XXX Error code chosen arbitrarily
100 mError = DOMException::Create(NS_ERROR_DOM_UNKNOWN_ERR,
101 NS_ConvertUTF16toUTF8(aError));
103 FireEvent(u"error"_ns, true, true);
105 if (mPromise) {
106 mPromise->MaybeRejectBrokenly(mError);
110 void DOMRequest::FireError(nsresult aError) {
111 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
112 NS_ASSERTION(!mError, "mError shouldn't have been set!");
113 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
115 mDone = true;
116 mError = DOMException::Create(aError);
118 FireEvent(u"error"_ns, true, true);
120 if (mPromise) {
121 mPromise->MaybeRejectBrokenly(mError);
125 void DOMRequest::FireDetailedError(DOMException& aError) {
126 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
127 NS_ASSERTION(!mError, "mError shouldn't have been set!");
128 NS_ASSERTION(mResult.isUndefined(), "mResult shouldn't have been set!");
130 mDone = true;
131 mError = &aError;
133 FireEvent(u"error"_ns, true, true);
135 if (mPromise) {
136 mPromise->MaybeRejectBrokenly(mError);
140 void DOMRequest::FireEvent(const nsAString& aType, bool aBubble,
141 bool aCancelable) {
142 if (NS_FAILED(CheckCurrentGlobalCorrectness())) {
143 return;
146 RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
147 event->InitEvent(aType, aBubble, aCancelable);
148 event->SetTrusted(true);
150 DispatchEvent(*event);
153 void DOMRequest::RootResultVal() { mozilla::HoldJSObjects(this); }
155 void DOMRequest::Then(JSContext* aCx, AnyCallback* aResolveCallback,
156 AnyCallback* aRejectCallback,
157 JS::MutableHandle<JS::Value> aRetval,
158 mozilla::ErrorResult& aRv) {
159 if (!mPromise) {
160 mPromise = Promise::Create(DOMEventTargetHelper::GetParentObject(), aRv);
161 if (aRv.Failed()) {
162 return;
164 if (mDone) {
165 // Since we create mPromise lazily, it's possible that the DOMRequest
166 // object has already fired its success/error event. In that case we
167 // should manually resolve/reject mPromise here. mPromise will take care
168 // of calling the callbacks on |promise| as needed.
169 if (mError) {
170 mPromise->MaybeRejectBrokenly(mError);
171 } else {
172 mPromise->MaybeResolve(mResult);
177 // Just use the global of the Promise itself as the callee global.
178 JS::Rooted<JSObject*> global(aCx, mPromise->PromiseObj());
179 global = JS::GetNonCCWObjectGlobal(global);
180 mPromise->Then(aCx, global, aResolveCallback, aRejectCallback, aRetval, aRv);
183 NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)
185 NS_IMETHODIMP
186 DOMRequestService::CreateRequest(mozIDOMWindow* aWindow,
187 DOMRequest** aRequest) {
188 MOZ_ASSERT(NS_IsMainThread());
189 NS_ENSURE_STATE(aWindow);
190 auto* win = nsPIDOMWindowInner::From(aWindow);
191 RefPtr<DOMRequest> req = new DOMRequest(win);
192 req.forget(aRequest);
194 return NS_OK;
197 NS_IMETHODIMP
198 DOMRequestService::FireSuccess(DOMRequest* aRequest,
199 JS::Handle<JS::Value> aResult) {
200 NS_ENSURE_STATE(aRequest);
201 aRequest->FireSuccess(aResult);
203 return NS_OK;
206 NS_IMETHODIMP
207 DOMRequestService::FireError(DOMRequest* aRequest, const nsAString& aError) {
208 NS_ENSURE_STATE(aRequest);
209 aRequest->FireError(aError);
211 return NS_OK;
214 class FireSuccessAsyncTask : public mozilla::Runnable {
215 FireSuccessAsyncTask(DOMRequest* aRequest, const JS::Value& aResult)
216 : mozilla::Runnable("FireSuccessAsyncTask"),
217 mReq(aRequest),
218 mResult(RootingCx(), aResult) {}
220 public:
221 // Due to the fact that initialization can fail during shutdown (since we
222 // can't fetch a js context), set up an initiatization function to make sure
223 // we can return the failure appropriately
224 static nsresult Dispatch(DOMRequest* aRequest, const JS::Value& aResult) {
225 RefPtr<FireSuccessAsyncTask> asyncTask =
226 new FireSuccessAsyncTask(aRequest, aResult);
227 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask));
228 return NS_OK;
231 NS_IMETHOD
232 Run() override {
233 mReq->FireSuccess(
234 JS::Handle<JS::Value>::fromMarkedLocation(mResult.address()));
235 return NS_OK;
238 private:
239 RefPtr<DOMRequest> mReq;
240 JS::PersistentRooted<JS::Value> mResult;
243 class FireErrorAsyncTask : public mozilla::Runnable {
244 public:
245 FireErrorAsyncTask(DOMRequest* aRequest, const nsAString& aError)
246 : mozilla::Runnable("FireErrorAsyncTask"),
247 mReq(aRequest),
248 mError(aError) {}
250 NS_IMETHOD
251 Run() override {
252 mReq->FireError(mError);
253 return NS_OK;
256 private:
257 RefPtr<DOMRequest> mReq;
258 nsString mError;
261 NS_IMETHODIMP
262 DOMRequestService::FireSuccessAsync(DOMRequest* aRequest,
263 JS::Handle<JS::Value> aResult) {
264 NS_ENSURE_STATE(aRequest);
265 return FireSuccessAsyncTask::Dispatch(aRequest, aResult);
268 NS_IMETHODIMP
269 DOMRequestService::FireErrorAsync(DOMRequest* aRequest,
270 const nsAString& aError) {
271 NS_ENSURE_STATE(aRequest);
272 nsCOMPtr<nsIRunnable> asyncTask = new FireErrorAsyncTask(aRequest, aError);
273 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(asyncTask));
274 return NS_OK;