dom/base/DOMRequest.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "DOMRequest.h"
michael@0 8
michael@0 9 #include "DOMError.h"
michael@0 10 #include "nsCxPusher.h"
michael@0 11 #include "nsThreadUtils.h"
michael@0 12 #include "DOMCursor.h"
michael@0 13 #include "nsIDOMEvent.h"
michael@0 14
michael@0 15 using mozilla::dom::DOMRequest;
michael@0 16 using mozilla::dom::DOMRequestService;
michael@0 17 using mozilla::dom::DOMCursor;
michael@0 18 using mozilla::AutoSafeJSContext;
michael@0 19
michael@0 20 DOMRequest::DOMRequest(nsPIDOMWindow* aWindow)
michael@0 21 : DOMEventTargetHelper(aWindow->IsInnerWindow() ?
michael@0 22 aWindow : aWindow->GetCurrentInnerWindow())
michael@0 23 , mResult(JSVAL_VOID)
michael@0 24 , mDone(false)
michael@0 25 {
michael@0 26 }
michael@0 27
michael@0 28 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
michael@0 29
michael@0 30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
michael@0 31 DOMEventTargetHelper)
michael@0 32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
michael@0 33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 34
michael@0 35 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
michael@0 36 DOMEventTargetHelper)
michael@0 37 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
michael@0 38 tmp->mResult = JSVAL_VOID;
michael@0 39 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 40
michael@0 41 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest,
michael@0 42 DOMEventTargetHelper)
michael@0 43 // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
michael@0 44 // DOMEventTargetHelper does it for us.
michael@0 45 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResult)
michael@0 46 NS_IMPL_CYCLE_COLLECTION_TRACE_END
michael@0 47
michael@0 48 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMRequest)
michael@0 49 NS_INTERFACE_MAP_ENTRY(nsIDOMDOMRequest)
michael@0 50 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
michael@0 51
michael@0 52 NS_IMPL_ADDREF_INHERITED(DOMRequest, DOMEventTargetHelper)
michael@0 53 NS_IMPL_RELEASE_INHERITED(DOMRequest, DOMEventTargetHelper)
michael@0 54
michael@0 55 /* virtual */ JSObject*
michael@0 56 DOMRequest::WrapObject(JSContext* aCx)
michael@0 57 {
michael@0 58 return DOMRequestBinding::Wrap(aCx, this);
michael@0 59 }
michael@0 60
michael@0 61 NS_IMPL_EVENT_HANDLER(DOMRequest, success)
michael@0 62 NS_IMPL_EVENT_HANDLER(DOMRequest, error)
michael@0 63
michael@0 64 NS_IMETHODIMP
michael@0 65 DOMRequest::GetReadyState(nsAString& aReadyState)
michael@0 66 {
michael@0 67 DOMRequestReadyState readyState = ReadyState();
michael@0 68 switch (readyState) {
michael@0 69 case DOMRequestReadyState::Pending:
michael@0 70 aReadyState.AssignLiteral("pending");
michael@0 71 break;
michael@0 72 case DOMRequestReadyState::Done:
michael@0 73 aReadyState.AssignLiteral("done");
michael@0 74 break;
michael@0 75 default:
michael@0 76 MOZ_CRASH("Unrecognized readyState.");
michael@0 77 }
michael@0 78
michael@0 79 return NS_OK;
michael@0 80 }
michael@0 81
michael@0 82 NS_IMETHODIMP
michael@0 83 DOMRequest::GetResult(JS::MutableHandle<JS::Value> aResult)
michael@0 84 {
michael@0 85 GetResult(nullptr, aResult);
michael@0 86 return NS_OK;
michael@0 87 }
michael@0 88
michael@0 89 NS_IMETHODIMP
michael@0 90 DOMRequest::GetError(nsISupports** aError)
michael@0 91 {
michael@0 92 NS_IF_ADDREF(*aError = GetError());
michael@0 93 return NS_OK;
michael@0 94 }
michael@0 95
michael@0 96 void
michael@0 97 DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult)
michael@0 98 {
michael@0 99 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
michael@0 100 NS_ASSERTION(!mError, "mError shouldn't have been set!");
michael@0 101 NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
michael@0 102
michael@0 103 mDone = true;
michael@0 104 if (JSVAL_IS_GCTHING(aResult)) {
michael@0 105 RootResultVal();
michael@0 106 }
michael@0 107 mResult = aResult;
michael@0 108
michael@0 109 FireEvent(NS_LITERAL_STRING("success"), false, false);
michael@0 110 }
michael@0 111
michael@0 112 void
michael@0 113 DOMRequest::FireError(const nsAString& aError)
michael@0 114 {
michael@0 115 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
michael@0 116 NS_ASSERTION(!mError, "mError shouldn't have been set!");
michael@0 117 NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
michael@0 118
michael@0 119 mDone = true;
michael@0 120 mError = new DOMError(GetOwner(), aError);
michael@0 121
michael@0 122 FireEvent(NS_LITERAL_STRING("error"), true, true);
michael@0 123 }
michael@0 124
michael@0 125 void
michael@0 126 DOMRequest::FireError(nsresult aError)
michael@0 127 {
michael@0 128 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
michael@0 129 NS_ASSERTION(!mError, "mError shouldn't have been set!");
michael@0 130 NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
michael@0 131
michael@0 132 mDone = true;
michael@0 133 mError = new DOMError(GetOwner(), aError);
michael@0 134
michael@0 135 FireEvent(NS_LITERAL_STRING("error"), true, true);
michael@0 136 }
michael@0 137
michael@0 138 void
michael@0 139 DOMRequest::FireDetailedError(nsISupports* aError)
michael@0 140 {
michael@0 141 NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
michael@0 142 NS_ASSERTION(!mError, "mError shouldn't have been set!");
michael@0 143 NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
michael@0 144 NS_ASSERTION(aError, "No detailed error provided");
michael@0 145
michael@0 146 mDone = true;
michael@0 147 mError = aError;
michael@0 148
michael@0 149 FireEvent(NS_LITERAL_STRING("error"), true, true);
michael@0 150 }
michael@0 151
michael@0 152 void
michael@0 153 DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable)
michael@0 154 {
michael@0 155 if (NS_FAILED(CheckInnerWindowCorrectness())) {
michael@0 156 return;
michael@0 157 }
michael@0 158
michael@0 159 nsCOMPtr<nsIDOMEvent> event;
michael@0 160 NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
michael@0 161 nsresult rv = event->InitEvent(aType, aBubble, aCancelable);
michael@0 162 if (NS_FAILED(rv)) {
michael@0 163 return;
michael@0 164 }
michael@0 165
michael@0 166 event->SetTrusted(true);
michael@0 167
michael@0 168 bool dummy;
michael@0 169 DispatchEvent(event, &dummy);
michael@0 170 }
michael@0 171
michael@0 172 void
michael@0 173 DOMRequest::RootResultVal()
michael@0 174 {
michael@0 175 mozilla::HoldJSObjects(this);
michael@0 176 }
michael@0 177
michael@0 178 NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService)
michael@0 179
michael@0 180 NS_IMETHODIMP
michael@0 181 DOMRequestService::CreateRequest(nsIDOMWindow* aWindow,
michael@0 182 nsIDOMDOMRequest** aRequest)
michael@0 183 {
michael@0 184 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
michael@0 185 NS_ENSURE_STATE(win);
michael@0 186 NS_ADDREF(*aRequest = new DOMRequest(win));
michael@0 187
michael@0 188 return NS_OK;
michael@0 189 }
michael@0 190
michael@0 191 NS_IMETHODIMP
michael@0 192 DOMRequestService::CreateCursor(nsIDOMWindow* aWindow,
michael@0 193 nsICursorContinueCallback* aCallback,
michael@0 194 nsIDOMDOMCursor** aCursor)
michael@0 195 {
michael@0 196 nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
michael@0 197 NS_ENSURE_STATE(win);
michael@0 198 NS_ADDREF(*aCursor = new DOMCursor(win, aCallback));
michael@0 199
michael@0 200 return NS_OK;
michael@0 201 }
michael@0 202
michael@0 203 NS_IMETHODIMP
michael@0 204 DOMRequestService::FireSuccess(nsIDOMDOMRequest* aRequest,
michael@0 205 JS::Handle<JS::Value> aResult)
michael@0 206 {
michael@0 207 NS_ENSURE_STATE(aRequest);
michael@0 208 static_cast<DOMRequest*>(aRequest)->FireSuccess(aResult);
michael@0 209
michael@0 210 return NS_OK;
michael@0 211 }
michael@0 212
michael@0 213 NS_IMETHODIMP
michael@0 214 DOMRequestService::FireError(nsIDOMDOMRequest* aRequest,
michael@0 215 const nsAString& aError)
michael@0 216 {
michael@0 217 NS_ENSURE_STATE(aRequest);
michael@0 218 static_cast<DOMRequest*>(aRequest)->FireError(aError);
michael@0 219
michael@0 220 return NS_OK;
michael@0 221 }
michael@0 222
michael@0 223 NS_IMETHODIMP
michael@0 224 DOMRequestService::FireDetailedError(nsIDOMDOMRequest* aRequest,
michael@0 225 nsISupports* aError)
michael@0 226 {
michael@0 227 NS_ENSURE_STATE(aRequest);
michael@0 228 static_cast<DOMRequest*>(aRequest)->FireDetailedError(aError);
michael@0 229
michael@0 230 return NS_OK;
michael@0 231 }
michael@0 232
michael@0 233 class FireSuccessAsyncTask : public nsRunnable
michael@0 234 {
michael@0 235
michael@0 236 FireSuccessAsyncTask(JSContext* aCx,
michael@0 237 DOMRequest* aRequest,
michael@0 238 const JS::Value& aResult) :
michael@0 239 mReq(aRequest),
michael@0 240 mResult(aCx, aResult)
michael@0 241 {
michael@0 242 }
michael@0 243
michael@0 244 public:
michael@0 245
michael@0 246 // Due to the fact that initialization can fail during shutdown (since we
michael@0 247 // can't fetch a js context), set up an initiatization function to make sure
michael@0 248 // we can return the failure appropriately
michael@0 249 static nsresult
michael@0 250 Dispatch(DOMRequest* aRequest,
michael@0 251 const JS::Value& aResult)
michael@0 252 {
michael@0 253 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
michael@0 254 AutoSafeJSContext cx;
michael@0 255 nsRefPtr<FireSuccessAsyncTask> asyncTask = new FireSuccessAsyncTask(cx, aRequest, aResult);
michael@0 256 if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
michael@0 257 NS_WARNING("Failed to dispatch to main thread!");
michael@0 258 return NS_ERROR_FAILURE;
michael@0 259 }
michael@0 260 return NS_OK;
michael@0 261 }
michael@0 262
michael@0 263 NS_IMETHODIMP
michael@0 264 Run()
michael@0 265 {
michael@0 266 mReq->FireSuccess(JS::Handle<JS::Value>::fromMarkedLocation(mResult.address()));
michael@0 267 return NS_OK;
michael@0 268 }
michael@0 269
michael@0 270 ~FireSuccessAsyncTask()
michael@0 271 {
michael@0 272 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
michael@0 273 }
michael@0 274
michael@0 275 private:
michael@0 276 nsRefPtr<DOMRequest> mReq;
michael@0 277 JS::PersistentRooted<JS::Value> mResult;
michael@0 278 };
michael@0 279
michael@0 280 class FireErrorAsyncTask : public nsRunnable
michael@0 281 {
michael@0 282 public:
michael@0 283 FireErrorAsyncTask(DOMRequest* aRequest,
michael@0 284 const nsAString& aError) :
michael@0 285 mReq(aRequest),
michael@0 286 mError(aError)
michael@0 287 {
michael@0 288 }
michael@0 289
michael@0 290 NS_IMETHODIMP
michael@0 291 Run()
michael@0 292 {
michael@0 293 mReq->FireError(mError);
michael@0 294 return NS_OK;
michael@0 295 }
michael@0 296 private:
michael@0 297 nsRefPtr<DOMRequest> mReq;
michael@0 298 nsString mError;
michael@0 299 };
michael@0 300
michael@0 301 NS_IMETHODIMP
michael@0 302 DOMRequestService::FireSuccessAsync(nsIDOMDOMRequest* aRequest,
michael@0 303 JS::Handle<JS::Value> aResult)
michael@0 304 {
michael@0 305 NS_ENSURE_STATE(aRequest);
michael@0 306 return FireSuccessAsyncTask::Dispatch(static_cast<DOMRequest*>(aRequest), aResult);
michael@0 307 }
michael@0 308
michael@0 309 NS_IMETHODIMP
michael@0 310 DOMRequestService::FireErrorAsync(nsIDOMDOMRequest* aRequest,
michael@0 311 const nsAString& aError)
michael@0 312 {
michael@0 313 NS_ENSURE_STATE(aRequest);
michael@0 314 nsCOMPtr<nsIRunnable> asyncTask =
michael@0 315 new FireErrorAsyncTask(static_cast<DOMRequest*>(aRequest), aError);
michael@0 316 if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
michael@0 317 NS_WARNING("Failed to dispatch to main thread!");
michael@0 318 return NS_ERROR_FAILURE;
michael@0 319 }
michael@0 320 return NS_OK;
michael@0 321 }
michael@0 322
michael@0 323 NS_IMETHODIMP
michael@0 324 DOMRequestService::FireDone(nsIDOMDOMCursor* aCursor) {
michael@0 325 NS_ENSURE_STATE(aCursor);
michael@0 326 static_cast<DOMCursor*>(aCursor)->FireDone();
michael@0 327
michael@0 328 return NS_OK;
michael@0 329 }

mercurial