1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/DOMRequest.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,329 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "DOMRequest.h" 1.11 + 1.12 +#include "DOMError.h" 1.13 +#include "nsCxPusher.h" 1.14 +#include "nsThreadUtils.h" 1.15 +#include "DOMCursor.h" 1.16 +#include "nsIDOMEvent.h" 1.17 + 1.18 +using mozilla::dom::DOMRequest; 1.19 +using mozilla::dom::DOMRequestService; 1.20 +using mozilla::dom::DOMCursor; 1.21 +using mozilla::AutoSafeJSContext; 1.22 + 1.23 +DOMRequest::DOMRequest(nsPIDOMWindow* aWindow) 1.24 + : DOMEventTargetHelper(aWindow->IsInnerWindow() ? 1.25 + aWindow : aWindow->GetCurrentInnerWindow()) 1.26 + , mResult(JSVAL_VOID) 1.27 + , mDone(false) 1.28 +{ 1.29 +} 1.30 + 1.31 +NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest) 1.32 + 1.33 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest, 1.34 + DOMEventTargetHelper) 1.35 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError) 1.36 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.37 + 1.38 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest, 1.39 + DOMEventTargetHelper) 1.40 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mError) 1.41 + tmp->mResult = JSVAL_VOID; 1.42 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.43 + 1.44 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest, 1.45 + DOMEventTargetHelper) 1.46 + // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because 1.47 + // DOMEventTargetHelper does it for us. 1.48 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mResult) 1.49 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.50 + 1.51 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMRequest) 1.52 + NS_INTERFACE_MAP_ENTRY(nsIDOMDOMRequest) 1.53 +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 1.54 + 1.55 +NS_IMPL_ADDREF_INHERITED(DOMRequest, DOMEventTargetHelper) 1.56 +NS_IMPL_RELEASE_INHERITED(DOMRequest, DOMEventTargetHelper) 1.57 + 1.58 +/* virtual */ JSObject* 1.59 +DOMRequest::WrapObject(JSContext* aCx) 1.60 +{ 1.61 + return DOMRequestBinding::Wrap(aCx, this); 1.62 +} 1.63 + 1.64 +NS_IMPL_EVENT_HANDLER(DOMRequest, success) 1.65 +NS_IMPL_EVENT_HANDLER(DOMRequest, error) 1.66 + 1.67 +NS_IMETHODIMP 1.68 +DOMRequest::GetReadyState(nsAString& aReadyState) 1.69 +{ 1.70 + DOMRequestReadyState readyState = ReadyState(); 1.71 + switch (readyState) { 1.72 + case DOMRequestReadyState::Pending: 1.73 + aReadyState.AssignLiteral("pending"); 1.74 + break; 1.75 + case DOMRequestReadyState::Done: 1.76 + aReadyState.AssignLiteral("done"); 1.77 + break; 1.78 + default: 1.79 + MOZ_CRASH("Unrecognized readyState."); 1.80 + } 1.81 + 1.82 + return NS_OK; 1.83 +} 1.84 + 1.85 +NS_IMETHODIMP 1.86 +DOMRequest::GetResult(JS::MutableHandle<JS::Value> aResult) 1.87 +{ 1.88 + GetResult(nullptr, aResult); 1.89 + return NS_OK; 1.90 +} 1.91 + 1.92 +NS_IMETHODIMP 1.93 +DOMRequest::GetError(nsISupports** aError) 1.94 +{ 1.95 + NS_IF_ADDREF(*aError = GetError()); 1.96 + return NS_OK; 1.97 +} 1.98 + 1.99 +void 1.100 +DOMRequest::FireSuccess(JS::Handle<JS::Value> aResult) 1.101 +{ 1.102 + NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); 1.103 + NS_ASSERTION(!mError, "mError shouldn't have been set!"); 1.104 + NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!"); 1.105 + 1.106 + mDone = true; 1.107 + if (JSVAL_IS_GCTHING(aResult)) { 1.108 + RootResultVal(); 1.109 + } 1.110 + mResult = aResult; 1.111 + 1.112 + FireEvent(NS_LITERAL_STRING("success"), false, false); 1.113 +} 1.114 + 1.115 +void 1.116 +DOMRequest::FireError(const nsAString& aError) 1.117 +{ 1.118 + NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); 1.119 + NS_ASSERTION(!mError, "mError shouldn't have been set!"); 1.120 + NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!"); 1.121 + 1.122 + mDone = true; 1.123 + mError = new DOMError(GetOwner(), aError); 1.124 + 1.125 + FireEvent(NS_LITERAL_STRING("error"), true, true); 1.126 +} 1.127 + 1.128 +void 1.129 +DOMRequest::FireError(nsresult aError) 1.130 +{ 1.131 + NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); 1.132 + NS_ASSERTION(!mError, "mError shouldn't have been set!"); 1.133 + NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!"); 1.134 + 1.135 + mDone = true; 1.136 + mError = new DOMError(GetOwner(), aError); 1.137 + 1.138 + FireEvent(NS_LITERAL_STRING("error"), true, true); 1.139 +} 1.140 + 1.141 +void 1.142 +DOMRequest::FireDetailedError(nsISupports* aError) 1.143 +{ 1.144 + NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!"); 1.145 + NS_ASSERTION(!mError, "mError shouldn't have been set!"); 1.146 + NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!"); 1.147 + NS_ASSERTION(aError, "No detailed error provided"); 1.148 + 1.149 + mDone = true; 1.150 + mError = aError; 1.151 + 1.152 + FireEvent(NS_LITERAL_STRING("error"), true, true); 1.153 +} 1.154 + 1.155 +void 1.156 +DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable) 1.157 +{ 1.158 + if (NS_FAILED(CheckInnerWindowCorrectness())) { 1.159 + return; 1.160 + } 1.161 + 1.162 + nsCOMPtr<nsIDOMEvent> event; 1.163 + NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); 1.164 + nsresult rv = event->InitEvent(aType, aBubble, aCancelable); 1.165 + if (NS_FAILED(rv)) { 1.166 + return; 1.167 + } 1.168 + 1.169 + event->SetTrusted(true); 1.170 + 1.171 + bool dummy; 1.172 + DispatchEvent(event, &dummy); 1.173 +} 1.174 + 1.175 +void 1.176 +DOMRequest::RootResultVal() 1.177 +{ 1.178 + mozilla::HoldJSObjects(this); 1.179 +} 1.180 + 1.181 +NS_IMPL_ISUPPORTS(DOMRequestService, nsIDOMRequestService) 1.182 + 1.183 +NS_IMETHODIMP 1.184 +DOMRequestService::CreateRequest(nsIDOMWindow* aWindow, 1.185 + nsIDOMDOMRequest** aRequest) 1.186 +{ 1.187 + nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow)); 1.188 + NS_ENSURE_STATE(win); 1.189 + NS_ADDREF(*aRequest = new DOMRequest(win)); 1.190 + 1.191 + return NS_OK; 1.192 +} 1.193 + 1.194 +NS_IMETHODIMP 1.195 +DOMRequestService::CreateCursor(nsIDOMWindow* aWindow, 1.196 + nsICursorContinueCallback* aCallback, 1.197 + nsIDOMDOMCursor** aCursor) 1.198 +{ 1.199 + nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow)); 1.200 + NS_ENSURE_STATE(win); 1.201 + NS_ADDREF(*aCursor = new DOMCursor(win, aCallback)); 1.202 + 1.203 + return NS_OK; 1.204 +} 1.205 + 1.206 +NS_IMETHODIMP 1.207 +DOMRequestService::FireSuccess(nsIDOMDOMRequest* aRequest, 1.208 + JS::Handle<JS::Value> aResult) 1.209 +{ 1.210 + NS_ENSURE_STATE(aRequest); 1.211 + static_cast<DOMRequest*>(aRequest)->FireSuccess(aResult); 1.212 + 1.213 + return NS_OK; 1.214 +} 1.215 + 1.216 +NS_IMETHODIMP 1.217 +DOMRequestService::FireError(nsIDOMDOMRequest* aRequest, 1.218 + const nsAString& aError) 1.219 +{ 1.220 + NS_ENSURE_STATE(aRequest); 1.221 + static_cast<DOMRequest*>(aRequest)->FireError(aError); 1.222 + 1.223 + return NS_OK; 1.224 +} 1.225 + 1.226 +NS_IMETHODIMP 1.227 +DOMRequestService::FireDetailedError(nsIDOMDOMRequest* aRequest, 1.228 + nsISupports* aError) 1.229 +{ 1.230 + NS_ENSURE_STATE(aRequest); 1.231 + static_cast<DOMRequest*>(aRequest)->FireDetailedError(aError); 1.232 + 1.233 + return NS_OK; 1.234 +} 1.235 + 1.236 +class FireSuccessAsyncTask : public nsRunnable 1.237 +{ 1.238 + 1.239 + FireSuccessAsyncTask(JSContext* aCx, 1.240 + DOMRequest* aRequest, 1.241 + const JS::Value& aResult) : 1.242 + mReq(aRequest), 1.243 + mResult(aCx, aResult) 1.244 + { 1.245 + } 1.246 + 1.247 +public: 1.248 + 1.249 + // Due to the fact that initialization can fail during shutdown (since we 1.250 + // can't fetch a js context), set up an initiatization function to make sure 1.251 + // we can return the failure appropriately 1.252 + static nsresult 1.253 + Dispatch(DOMRequest* aRequest, 1.254 + const JS::Value& aResult) 1.255 + { 1.256 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.257 + AutoSafeJSContext cx; 1.258 + nsRefPtr<FireSuccessAsyncTask> asyncTask = new FireSuccessAsyncTask(cx, aRequest, aResult); 1.259 + if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) { 1.260 + NS_WARNING("Failed to dispatch to main thread!"); 1.261 + return NS_ERROR_FAILURE; 1.262 + } 1.263 + return NS_OK; 1.264 + } 1.265 + 1.266 + NS_IMETHODIMP 1.267 + Run() 1.268 + { 1.269 + mReq->FireSuccess(JS::Handle<JS::Value>::fromMarkedLocation(mResult.address())); 1.270 + return NS_OK; 1.271 + } 1.272 + 1.273 + ~FireSuccessAsyncTask() 1.274 + { 1.275 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.276 + } 1.277 + 1.278 +private: 1.279 + nsRefPtr<DOMRequest> mReq; 1.280 + JS::PersistentRooted<JS::Value> mResult; 1.281 +}; 1.282 + 1.283 +class FireErrorAsyncTask : public nsRunnable 1.284 +{ 1.285 +public: 1.286 + FireErrorAsyncTask(DOMRequest* aRequest, 1.287 + const nsAString& aError) : 1.288 + mReq(aRequest), 1.289 + mError(aError) 1.290 + { 1.291 + } 1.292 + 1.293 + NS_IMETHODIMP 1.294 + Run() 1.295 + { 1.296 + mReq->FireError(mError); 1.297 + return NS_OK; 1.298 + } 1.299 +private: 1.300 + nsRefPtr<DOMRequest> mReq; 1.301 + nsString mError; 1.302 +}; 1.303 + 1.304 +NS_IMETHODIMP 1.305 +DOMRequestService::FireSuccessAsync(nsIDOMDOMRequest* aRequest, 1.306 + JS::Handle<JS::Value> aResult) 1.307 +{ 1.308 + NS_ENSURE_STATE(aRequest); 1.309 + return FireSuccessAsyncTask::Dispatch(static_cast<DOMRequest*>(aRequest), aResult); 1.310 +} 1.311 + 1.312 +NS_IMETHODIMP 1.313 +DOMRequestService::FireErrorAsync(nsIDOMDOMRequest* aRequest, 1.314 + const nsAString& aError) 1.315 +{ 1.316 + NS_ENSURE_STATE(aRequest); 1.317 + nsCOMPtr<nsIRunnable> asyncTask = 1.318 + new FireErrorAsyncTask(static_cast<DOMRequest*>(aRequest), aError); 1.319 + if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) { 1.320 + NS_WARNING("Failed to dispatch to main thread!"); 1.321 + return NS_ERROR_FAILURE; 1.322 + } 1.323 + return NS_OK; 1.324 +} 1.325 + 1.326 +NS_IMETHODIMP 1.327 +DOMRequestService::FireDone(nsIDOMDOMCursor* aCursor) { 1.328 + NS_ENSURE_STATE(aCursor); 1.329 + static_cast<DOMCursor*>(aCursor)->FireDone(); 1.330 + 1.331 + return NS_OK; 1.332 +}