Bug 780718 - Return false from DOMRequestService is preventDefault was called on events. r=sicking
☠☠ backed out by f4495eb1c973 ☠ ☠
authorWes Johnston <wjohnston@mozilla.com>
Wed, 08 Aug 2012 12:35:15 -0700
changeset 104996 c030a8af8abd549cc765a4ac11de7ae47a659e03
parent 104995 0f7d2d447ed501408c8d86707f921c0ae038515d
child 104997 6dd4e5c2fe0a0911a7d9289802889fefa42bfc5e
push idunknown
push userunknown
push dateunknown
reviewerssicking
bugs780718
milestone17.0a1
Bug 780718 - Return false from DOMRequestService is preventDefault was called on events. r=sicking
dom/base/DOMRequest.cpp
dom/base/DOMRequest.h
dom/base/nsIDOMDOMRequest.idl
dom/base/test/test_domrequest.html
dom/bluetooth/BluetoothReplyRunnable.cpp
dom/devicestorage/DeviceStorageRequestChild.cpp
dom/devicestorage/nsDeviceStorage.cpp
dom/file/ArchiveRequest.cpp
dom/file/FileRequest.cpp
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -107,77 +107,77 @@ DOMRequest::GetError(nsIDOMDOMError** aE
                "Error should be null when pending");
 
   NS_IF_ADDREF(*aError = mError);
 
   return NS_OK;
 }
 
 void
-DOMRequest::FireSuccess(jsval aResult)
+DOMRequest::FireSuccess(jsval aResult, bool* aDefaultActionEnabled)
 {
   NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
   NS_ASSERTION(!mError, "mError shouldn't have been set!");
   NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
   mDone = true;
   if (JSVAL_IS_GCTHING(aResult)) {
     RootResultVal();
   }
   mResult = aResult;
 
-  FireEvent(NS_LITERAL_STRING("success"), false, false);
+  FireEvent(NS_LITERAL_STRING("success"), false, false, aDefaultActionEnabled);
 }
 
 void
-DOMRequest::FireError(const nsAString& aError)
+DOMRequest::FireError(const nsAString& aError, bool* aDefaultActionEnabled)
 {
   NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
   NS_ASSERTION(!mError, "mError shouldn't have been set!");
   NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
   mDone = true;
   mError = DOMError::CreateWithName(aError);
 
-  FireEvent(NS_LITERAL_STRING("error"), true, true);
+  FireEvent(NS_LITERAL_STRING("error"), true, true, aDefaultActionEnabled);
 }
 
 void
-DOMRequest::FireError(nsresult aError)
+DOMRequest::FireError(nsresult aError, bool* aDefaultActionEnabled)
 {
   NS_ASSERTION(!mDone, "mDone shouldn't have been set to true already!");
   NS_ASSERTION(!mError, "mError shouldn't have been set!");
   NS_ASSERTION(mResult == JSVAL_VOID, "mResult shouldn't have been set!");
 
   mDone = true;
   mError = DOMError::CreateForNSResult(aError);
 
-  FireEvent(NS_LITERAL_STRING("error"), true, true);
+  FireEvent(NS_LITERAL_STRING("error"), true, true, aDefaultActionEnabled);
 }
 
 void
-DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable)
+DOMRequest::FireEvent(const nsAString& aType, bool aBubble, bool aCancelable,
+                      bool* aDefaultActionEnabled)
 {
   if (NS_FAILED(CheckInnerWindowCorrectness())) {
     return;
   }
 
   nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
   nsresult rv = event->InitEvent(aType, aBubble, aCancelable);
   if (NS_FAILED(rv)) {
     return;
   }
 
   rv = event->SetTrusted(true);
   if (NS_FAILED(rv)) {
     return;
   }
 
-  bool dummy;
-  DispatchEvent(event, &dummy);
+  DispatchEvent(event, aDefaultActionEnabled);
 }
 
 void
 DOMRequest::RootResultVal()
 {
   NS_ASSERTION(!mRooted, "Don't call me if already rooted!");
   NS_HOLD_JS_OBJECTS(this, DOMRequest);
   mRooted = true;
@@ -200,25 +200,29 @@ DOMRequestService::CreateRequest(nsIDOMW
   NS_ENSURE_STATE(aWindow);
   NS_ADDREF(*aRequest = new DOMRequest(aWindow));
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMRequestService::FireSuccess(nsIDOMDOMRequest* aRequest,
-                               const jsval& aResult)
+                               const jsval& aResult,
+                               bool* aDefaultActionEnabled)
 {
+  NS_ENSURE_ARG_POINTER(aDefaultActionEnabled);
   NS_ENSURE_STATE(aRequest);
-  static_cast<DOMRequest*>(aRequest)->FireSuccess(aResult);
+  static_cast<DOMRequest*>(aRequest)->FireSuccess(aResult, aDefaultActionEnabled);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 DOMRequestService::FireError(nsIDOMDOMRequest* aRequest,
-                             const nsAString& aError)
+                             const nsAString& aError,
+                             bool* aDefaultActionEnabled)
 {
+  NS_ENSURE_ARG_POINTER(aDefaultActionEnabled);
   NS_ENSURE_STATE(aRequest);
-  static_cast<DOMRequest*>(aRequest)->FireError(aError);
+  static_cast<DOMRequest*>(aRequest)->FireError(aError, aDefaultActionEnabled);
 
   return NS_OK;
 }
--- a/dom/base/DOMRequest.h
+++ b/dom/base/DOMRequest.h
@@ -32,32 +32,33 @@ protected:
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMDOMREQUEST
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMRequest,
                                                          nsDOMEventTargetHelper)
 
-  void FireSuccess(jsval aResult);
-  void FireError(const nsAString& aError);
-  void FireError(nsresult aError);
+  void FireSuccess(jsval aResult, bool* aDefaultActionEnabled);
+  void FireError(const nsAString& aError, bool* aDefaultActionEnabled);
+  void FireError(nsresult aError, bool* aDefaultActionEnabled);
 
   DOMRequest(nsIDOMWindow* aWindow);
   DOMRequest();
 
   virtual ~DOMRequest()
   {
     if (mRooted) {
       UnrootResultVal();
     }
   }
 
 protected:
-  void FireEvent(const nsAString& aType, bool aBubble, bool aCancelable);
+  void FireEvent(const nsAString& aType, bool aBubble, bool aCancelable,
+                 bool* aDefaultActionEnabled);
 
   virtual void RootResultVal();
   virtual void UnrootResultVal();
 
   void Init(nsIDOMWindow* aWindow);
 };
 
 class DOMRequestService MOZ_FINAL : public nsIDOMRequestService
--- a/dom/base/nsIDOMDOMRequest.idl
+++ b/dom/base/nsIDOMDOMRequest.idl
@@ -16,16 +16,16 @@ interface nsIDOMDOMRequest : nsIDOMEvent
 
   readonly attribute jsval result;
   readonly attribute nsIDOMDOMError error;
 
   attribute nsIDOMEventListener onsuccess;
   attribute nsIDOMEventListener onerror;
 };
 
-[scriptable, builtinclass, uuid(eebcdf29-f8fa-4c36-bbc7-2146b1cbaf7b)]
+[scriptable, builtinclass, uuid(46afe27a-d407-4eb8-95c4-aefbd2b63540)]
 interface nsIDOMRequestService : nsISupports
 {
   nsIDOMDOMRequest createRequest(in nsIDOMWindow window);
 
-  void fireSuccess(in nsIDOMDOMRequest request, in jsval result);
-  void fireError(in nsIDOMDOMRequest request, in DOMString error);
+  bool fireSuccess(in nsIDOMDOMRequest request, in jsval result);
+  bool fireError(in nsIDOMDOMRequest request, in DOMString error);
 };
--- a/dom/base/test/test_domrequest.html
+++ b/dom/base/test/test_domrequest.html
@@ -30,34 +30,44 @@ is(req.result, undefined, "result is und
 is(req.onsuccess, null, "onsuccess is null");
 is(req.onerror, null, "onerror is null");
 
 // fire success
 var ev = null;
 req.onsuccess = function(e) {
   ev = e;
 }
-reqserv.fireSuccess(req, "my result");
+is(reqserv.fireSuccess(req, "my result"), true, "prevent default not detected");
 ok(ev, "got success event");
 is(ev.type, "success", "correct type during success");
 is(ev.target, req, "correct target during success");
 is(req.readyState, "done", "correct readyState after success");
 is(req.error, null, "correct error after success");
 is(req.result, "my result", "correct result after success");
 
 // fire error
 req = reqserv.createRequest(window);
 ev = null;
 req.onerror = function(e) {
   ev = e;
 }
-reqserv.fireError(req, "OhMyError");
+is(reqserv.fireError(req, "OhMyError"), true, "prevent default not detected");
 ok(ev, "got success event");
 is(ev.type, "error", "correct type during error");
 is(ev.target, req, "correct target during error");
 is(req.readyState, "done", "correct readyState after error");
 is(req.error.name, "OhMyError", "correct error after error");
 is(req.result, undefined, "correct result after error");
 
+// Test calling preventDefault on events
+req.onsuccess = function(e) e.preventDefault();
+reqserv.fireSuccess(req, "my result");
+is(reqserv.fireSuccess(req, "my result"), false, "prevent default detected");
+
+// fire error
+req.onerror = function(e) e.preventDefault();
+reqserv.fireError(req, "OhMyError");
+is(reqserv.fireError(req, "OhMyError"), false, "prevent default detected");
+
 </script>
 </pre>
 </body>
 </html>
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -16,34 +16,34 @@ BluetoothReplyRunnable::FireReply(const 
   nsCOMPtr<nsIDOMRequestService> rs =
     do_GetService("@mozilla.org/dom/dom-request-service;1");
   
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
   
-  
+  bool allowDefault;
   return mReply->type() == BluetoothReply::TBluetoothReplySuccess ?
-    rs->FireSuccess(mDOMRequest, aVal) :
-    rs->FireError(mDOMRequest, mReply->get_BluetoothReplyError().error());
+    rs->FireSuccess(mDOMRequest, aVal, &allowDefault) :
+    rs->FireError(mDOMRequest, mReply->get_BluetoothReplyError().error(), &allowDefault);
 }
 
 nsresult
 BluetoothReplyRunnable::FireErrorString()
 {
   nsCOMPtr<nsIDOMRequestService> rs =
     do_GetService("@mozilla.org/dom/dom-request-service;1");
   
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
-  
-  return rs->FireError(mDOMRequest, mErrorString);
+  bool allowDefault;
+  return rs->FireError(mDOMRequest, mErrorString, &allowDefault);
 }
 
 NS_IMETHODIMP
 BluetoothReplyRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv;
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -31,24 +31,26 @@ DeviceStorageRequestChild::~DeviceStorag
 bool
 DeviceStorageRequestChild::Recv__delete__(const DeviceStorageResponseValue& aValue)
 {
   switch (aValue.type()) {
 
     case DeviceStorageResponseValue::TErrorResponse:
     {
       ErrorResponse r = aValue;
-      mRequest->FireError(r.error());
+      bool allowDefault;
+      mRequest->FireError(r.error(), &allowDefault);
       break;
     }
 
     case DeviceStorageResponseValue::TSuccessResponse:
     {
       jsval result = StringToJsval(mRequest->GetOwner(), mFile->mPath);
-      mRequest->FireSuccess(result);
+      bool allowDefault;
+      mRequest->FireSuccess(result, &allowDefault);
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
 
       // I am going to hell for this.  bent says he'll save me.
@@ -60,17 +62,18 @@ DeviceStorageRequestChild::Recv__delete_
       mimeType.AssignWithConversion(r.contentType());
 
       nsCOMPtr<nsIDOMBlob> blob = new nsDOMMemoryFile(buffer,
                                                       bits.Length(),
                                                       mFile->mPath,
                                                       mimeType);
 
       jsval result = BlobToJsval(mRequest->GetOwner(), blob);
-      mRequest->FireSuccess(result);
+      bool allowDefault;
+      mRequest->FireSuccess(result, &allowDefault);
       break;
     }
 
     case DeviceStorageResponseValue::TEnumerationResponse:
     {
       EnumerationResponse r = aValue;
       nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
 
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -533,17 +533,18 @@ public:
       mError.Append(NS_LITERAL_STRING("null path"));
     }
   }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-    mRequest->FireError(mError);
+    bool allowDefault;
+    mRequest->FireError(mError, &allowDefault);
     mRequest = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<DOMRequest> mRequest;
   nsString mError;
 };
@@ -574,17 +575,18 @@ ContinueCursorEvent::Run() {
     nsRefPtr<DeviceStorageFile> file = cursor->mFiles[0];
     cursor->mFiles.RemoveElementAt(0);
 
     // todo, this blob needs to be opened in the parent.  This will be signifincally easier when bent lands
     val = nsIFileToJsval(cursor->GetOwner(), file);
     cursor->mOkToCallContinue = true;
   }
 
-  mRequest->FireSuccess(val);
+  bool allowDefault;
+  mRequest->FireSuccess(val, &allowDefault);
   mRequest = nullptr;
   return NS_OK;
 }
 
 class InitCursorEvent : public nsRunnable
 {
 public:
     InitCursorEvent(DOMRequest* aRequest, DeviceStorageFile* aFile)
@@ -789,17 +791,18 @@ public:
 
     jsval result = JSVAL_NULL;
     if (mFile) {
       result = nsIFileToJsval(mRequest->GetOwner(), mFile);
     } else {
       result = StringToJsval(mRequest->GetOwner(), mPath);
     }
 
-    mRequest->FireSuccess(result);
+    bool allowDefault;
+    mRequest->FireSuccess(result, &allowDefault);
     mRequest = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<DeviceStorageFile> mFile;
   nsString mPath;
   nsRefPtr<DOMRequest> mRequest;
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -85,18 +85,20 @@ ArchiveRequest::GetReader(nsIDOMArchiveR
 
 // Here the request is processed:
 void
 ArchiveRequest::Run()
 {
   // Register this request to the reader.
   // When the reader is ready to return data, a 'Ready()' will be called
   nsresult rv = mArchiveReader->RegisterRequest(this);
-  if (NS_FAILED(rv))
-    FireError(rv);
+  if (NS_FAILED(rv)) {
+    bool allowDefault;
+    FireError(rv, &allowDefault);
+  }
 }
 
 void
 ArchiveRequest::OpGetFilenames()
 {
   mOperation = GetFilenames;
 }
 
@@ -106,18 +108,19 @@ ArchiveRequest::OpGetFile(const nsAStrin
   mOperation = GetFile;
   mFilename = aFilename;
 }
 
 nsresult
 ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
                             nsresult aStatus)
 {
+  bool allowDefault;
   if (aStatus != NS_OK) {
-    FireError(aStatus);
+    FireError(aStatus, &allowDefault);
     return NS_OK;
   }
 
   jsval result;
   nsresult rv;
 
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   NS_ENSURE_STATE(sc);
@@ -145,20 +148,20 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
       NS_WARNING("Get*Result failed!");
     }
   } else {
     NS_WARNING("Failed to enter correct compartment!");
     rv = NS_ERROR_FAILURE;
   }
 
   if (NS_SUCCEEDED(rv)) {
-    FireSuccess(result);
+    FireSuccess(result, &allowDefault);
   }
   else {
-    FireError(rv);
+    FireError(rv, &allowDefault);
   }
 
   return NS_OK;
 }
 
 nsresult
 ArchiveRequest::GetFilenamesResult(JSContext* aCx,
                                    jsval* aValue,
--- a/dom/file/FileRequest.cpp
+++ b/dom/file/FileRequest.cpp
@@ -57,18 +57,19 @@ FileRequest::PreHandleEvent(nsEventChain
 nsresult
 FileRequest::NotifyHelperCompleted(FileHelper* aFileHelper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsresult rv = aFileHelper->mResultCode;
 
   // If the request failed then fire error event and return.
+  bool allowDefault;
   if (NS_FAILED(rv)) {
-    FireError(rv);
+    FireError(rv, &allowDefault);
     return NS_OK;
   }
 
   // Otherwise we need to get the result from the helper.
   jsval result;
 
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   NS_ENSURE_STATE(sc);
@@ -88,20 +89,20 @@ FileRequest::NotifyHelperCompleted(FileH
     }
   }
   else {
     NS_WARNING("Failed to enter correct compartment!");
     rv = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
   }
 
   if (NS_SUCCEEDED(rv)) {
-    FireSuccess(result);
+    FireSuccess(result, &allowDefault);
   }
   else {
-    FireError(rv);
+    FireError(rv, &allowDefault);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FileRequest::GetLockedFile(nsIDOMLockedFile** aLockedFile)
 {