Bug 776539 - Move FormData to Paris bindings; r=bz
authorMs2ger <ms2ger@gmail.com>
Tue, 11 Dec 2012 19:09:56 +0100
changeset 125527 2fb469965c13a453c11463f014293778f677c6f8
parent 125526 3bb5a5a91af65134ca51fceeba6511045ae4fb66
child 125528 7bdbb938754177d3b8343251d684d7577475122e
push id297
push userlsblakk@mozilla.com
push dateTue, 26 Mar 2013 17:28:00 +0000
treeherdermozilla-release@64d7b45c34e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs776539
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 776539 - Move FormData to Paris bindings; r=bz
content/base/src/nsFormData.cpp
content/base/src/nsFormData.h
content/base/src/nsXMLHttpRequest.cpp
content/base/src/nsXMLHttpRequest.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/bindings/Bindings.conf
dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
dom/webidl/FormData.webidl
dom/webidl/WebIDL.mk
dom/webidl/XMLHttpRequest.webidl
dom/workers/XMLHttpRequest.h
js/xpconnect/src/nsDOMQS.h
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -1,71 +1,68 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
 #include "nsIDOMFile.h"
-#include "nsContentUtils.h"
 #include "nsHTMLFormElement.h"
+#include "mozilla/dom/FormDataBinding.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
 
-nsFormData::nsFormData()
+nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
+  , mOwner(aOwner)
 {
+  SetIsDOMBinding();
 }
 
 // -------------------------------------------------------------------------
 // nsISupports
 
-DOMCI_DATA(FormData, nsFormData)
-
-NS_IMPL_ADDREF(nsFormData)
-NS_IMPL_RELEASE(nsFormData)
-NS_INTERFACE_MAP_BEGIN(nsFormData)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsFormData, mOwner)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormData)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormData)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMFormData)
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
-  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FormData)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFormData)
 NS_INTERFACE_MAP_END
 
 // -------------------------------------------------------------------------
 // nsFormSubmission
 nsresult
 nsFormData::GetEncodedSubmission(nsIURI* aURI,
                                  nsIInputStream** aPostDataStream)
 {
   NS_NOTREACHED("Shouldn't call nsFormData::GetEncodedSubmission");
   return NS_OK;
 }
 
-nsresult
-nsFormData::AddNameValuePair(const nsAString& aName,
-                             const nsAString& aValue)
+void
+nsFormData::Append(const nsAString& aName, const nsAString& aValue)
 {
   FormDataTuple* data = mFormData.AppendElement();
   data->name = aName;
   data->stringValue = aValue;
   data->valueIsFile = false;
-
-  return NS_OK;
 }
 
-nsresult
-nsFormData::AddNameFilePair(const nsAString& aName,
-                            nsIDOMBlob* aBlob)
+void
+nsFormData::Append(const nsAString& aName, nsIDOMBlob* aBlob)
 {
   FormDataTuple* data = mFormData.AppendElement();
   data->name = aName;
   data->fileValue = aBlob;
   data->valueIsFile = true;
-
-  return NS_OK;
 }
 
 // -------------------------------------------------------------------------
 // nsIDOMFormData
 
 NS_IMETHODIMP
 nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
 {
@@ -79,29 +76,50 @@ nsFormData::Append(const nsAString& aNam
     nsID *iid;
     rv = aValue->GetAsInterface(&iid, getter_AddRefs(supports));
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsMemory::Free(iid);
 
     nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(supports);
     if (domBlob) {
-      return AddNameFilePair(aName, domBlob);
+      Append(aName, domBlob);
+      return NS_OK;
     }
   }
 
   PRUnichar* stringData = nullptr;
   uint32_t stringLen = 0;
   rv = aValue->GetAsWStringWithSize(&stringLen, &stringData);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString valAsString;
   valAsString.Adopt(stringData, stringLen);
 
-  return AddNameValuePair(aName, valAsString);
+  Append(aName, valAsString);
+  return NS_OK;
+}
+
+/* virtual */ JSObject*
+nsFormData::WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap)
+{
+  return FormDataBinding::Wrap(aCx, aScope, this, aTriedToWrap);
+}
+
+/* static */ already_AddRefed<nsFormData>
+nsFormData::Constructor(nsISupports* aGlobal,
+                        const Optional<nsHTMLFormElement*>& aFormElement,
+                        ErrorResult& aRv)
+{
+  nsRefPtr<nsFormData> formData = new nsFormData(aGlobal);
+  if (aFormElement.WasPassed()) {
+    MOZ_ASSERT(aFormElement.Value());
+    aRv = aFormElement.Value()->WalkFormElements(formData);
+  }
+  return formData.forget();
 }
 
 // -------------------------------------------------------------------------
 // nsIXHRSendable
 
 NS_IMETHODIMP
 nsFormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
                         nsACString& aContentType, nsACString& aCharset)
@@ -119,40 +137,8 @@ nsFormData::GetSendInfo(nsIInputStream**
 
   fs.GetContentType(aContentType);
   aCharset.Truncate();
   *aContentLength = 0;
   NS_ADDREF(*aBody = fs.GetSubmissionBody(aContentLength));
 
   return NS_OK;
 }
-
-
-// -------------------------------------------------------------------------
-// nsIJSNativeInitializer
-
-NS_IMETHODIMP
-nsFormData::Initialize(nsISupports* aOwner,
-                       JSContext* aCx,
-                       JSObject* aObj,
-                       uint32_t aArgc,
-                       jsval* aArgv)
-{
-  if (aArgc > 0) {
-    if (JSVAL_IS_PRIMITIVE(aArgv[0])) {
-      return NS_ERROR_UNEXPECTED;
-    }
-    nsCOMPtr<nsIContent> formCont = do_QueryInterface(
-      nsContentUtils::XPConnect()->
-        GetNativeOfWrapper(aCx, JSVAL_TO_OBJECT(aArgv[0])));
-    
-    if (!formCont || !formCont->IsHTML(nsGkAtoms::form)) {
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    nsresult rv = static_cast<nsHTMLFormElement*>(formCont.get())->
-      WalkFormElements(this);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-
-  return NS_OK;
-}
--- a/content/base/src/nsFormData.h
+++ b/content/base/src/nsFormData.h
@@ -3,48 +3,86 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFormData_h__
 #define nsFormData_h__
 
 #include "nsIDOMFormData.h"
 #include "nsIXMLHttpRequest.h"
 #include "nsFormSubmission.h"
-#include "nsIJSNativeInitializer.h"
+#include "nsWrapperCache.h"
 #include "nsTArray.h"
+#include "mozilla/ErrorResult.h"
 
+class nsHTMLFormElement;
 class nsIDOMFile;
 
+namespace mozilla {
+class ErrorResult;
+
+namespace dom {
+template<class> class Optional;
+} // namespace dom
+} // namespace mozilla
+
 class nsFormData : public nsIDOMFormData,
                    public nsIXHRSendable,
-                   public nsIJSNativeInitializer,
-                   public nsFormSubmission
+                   public nsFormSubmission,
+                   public nsWrapperCache
 {
 public:
-  nsFormData();
+  nsFormData(nsISupports* aOwner = nullptr);
 
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsFormData,
+                                                         nsIDOMFormData)
+
   NS_DECL_NSIDOMFORMDATA
   NS_DECL_NSIXHRSENDABLE
 
+  // nsWrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JSObject* aScope, bool* aTriedToWrap) MOZ_OVERRIDE;
+
+  // WebIDL
+  nsISupports*
+  GetParentObject() const
+  {
+    return mOwner;
+  }
+  static already_AddRefed<nsFormData>
+  Constructor(nsISupports* aGlobal,
+              const mozilla::dom::Optional<nsHTMLFormElement*>& aFormElement,
+              mozilla::ErrorResult& aRv);
+  void Append(const nsAString& aName, const nsAString& aValue);
+  void Append(const nsAString& aName, nsIDOMBlob* aBlob);
+
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream);
   virtual nsresult AddNameValuePair(const nsAString& aName,
-                                    const nsAString& aValue);
+                                    const nsAString& aValue)
+  {
+    Append(aName, aValue);
+    return NS_OK;
+  }
   virtual nsresult AddNameFilePair(const nsAString& aName,
-                                   nsIDOMBlob* aBlob);
+                                   nsIDOMBlob* aBlob)
+  {
+    Append(aName, aBlob);
+    return NS_OK;
+  }
 
-  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-                        uint32_t aArgc, jsval* aArgv);
 private:
+  nsCOMPtr<nsISupports> mOwner;
+
   struct FormDataTuple
   {
     nsString name;
     nsString stringValue;
     nsCOMPtr<nsIDOMBlob> fileValue;
     bool valueIsFile;
   };
-  
+
   nsTArray<FormDataTuple> mFormData;
 };
 
 #endif // nsFormData_h__
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -74,19 +74,20 @@
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 #include "nsIDOMFormData.h"
 #include "DictionaryHelpers.h"
 #include "mozilla/Attributes.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsIHttpChannelInternal.h"
+#include "nsFormData.h"
+#include "nsStreamListenerWrapper.h"
 
 #include "nsWrapperCacheInlines.h"
-#include "nsStreamListenerWrapper.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define LOAD_STR "load"
 #define ERROR_STR "error"
 #define ABORT_STR "abort"
 #define TIMEOUT_STR "timeout"
@@ -2661,21 +2662,19 @@ nsXMLHttpRequest::GetRequestBody(nsIVari
     }
     case nsXMLHttpRequest::RequestBody::DOMString:
     {
       return ::GetRequestBody(*value.mString, aResult, aContentLength,
                               aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::FormData:
     {
-      nsresult rv;
-      nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(value.mFormData, &rv);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      return ::GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
+      MOZ_ASSERT(value.mFormData);
+      return ::GetRequestBody(value.mFormData, aResult, aContentLength,
+                              aContentType, aCharset);
     }
     case nsXMLHttpRequest::RequestBody::InputStream:
     {
       return ::GetRequestBody(value.mStream, aResult, aContentLength,
                               aContentType, aCharset);
     }
     default:
     {
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -47,17 +47,17 @@
 /* Xlib headers insist on this for some reason... Nuke it because
    it'll override our member name */
 #undef Status
 #endif
 
 class nsILoadGroup;
 class AsyncVerifyRedirectCallbackForwarder;
 class nsIUnicodeDecoder;
-class nsIDOMFormData;
+class nsFormData;
 
 class nsXHREventTarget : public nsDOMEventTargetHelper,
                          public nsIXMLHttpRequestEventTarget
 {
 public:
   typedef mozilla::dom::XMLHttpRequestResponseType
           XMLHttpRequestResponseType;
   typedef mozilla::ErrorResult
@@ -283,19 +283,19 @@ private:
     RequestBody(nsIDocument* aDocument) : mType(Document)
     {
       mValue.mDocument = aDocument;
     }
     RequestBody(const nsAString& aString) : mType(DOMString)
     {
       mValue.mString = &aString;
     }
-    RequestBody(nsIDOMFormData* aFormData) : mType(FormData)
+    RequestBody(nsFormData& aFormData) : mType(FormData)
     {
-      mValue.mFormData = aFormData;
+      mValue.mFormData = &aFormData;
     }
     RequestBody(nsIInputStream* aStream) : mType(InputStream)
     {
       mValue.mStream = aStream;
     }
 
     enum Type {
       Uninitialized,
@@ -306,17 +306,17 @@ private:
       FormData,
       InputStream
     };
     union Value {
       mozilla::dom::ArrayBuffer* mArrayBuffer;
       nsIDOMBlob* mBlob;
       nsIDocument* mDocument;
       const nsAString* mString;
-      nsIDOMFormData* mFormData;
+      nsFormData* mFormData;
       nsIInputStream* mStream;
     };
 
     Type GetType() const
     {
       MOZ_ASSERT(mType != Uninitialized);
       return mType;
     }
@@ -371,19 +371,18 @@ public:
   {
     if (DOMStringIsNull(aString)) {
       Send(aRv);
     }
     else {
       aRv = Send(RequestBody(aString));
     }
   }
-  void Send(nsIDOMFormData* aFormData, ErrorResult& aRv)
+  void Send(nsFormData& aFormData, ErrorResult& aRv)
   {
-    NS_ASSERTION(aFormData, "Null should go to string version");
     aRv = Send(RequestBody(aFormData));
   }
   void Send(nsIInputStream* aStream, ErrorResult& aRv)
   {
     NS_ASSERTION(aStream, "Null should go to string version");
     aRv = Send(RequestBody(aStream));
   }
   void SendAsBinary(const nsAString& aBody, ErrorResult& aRv);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -422,17 +422,16 @@
 #include "nsIDOMNavigatorUserMedia.h"
 #endif
 
 // Workers
 #include "mozilla/dom/workers/Workers.h"
 
 #include "nsDOMFile.h"
 #include "nsDOMFileReader.h"
-#include "nsIDOMFormData.h"
 #include "ArchiveReader.h"
 #include "ArchiveRequest.h"
 
 #include "nsIDOMDesktopNotification.h"
 #include "nsIDOMNavigatorDesktopNotification.h"
 #include "nsIDOMNavigatorDeviceStorage.h"
 #include "nsIDOMNavigatorGeolocation.h"
 #include "Navigator.h"
@@ -1561,19 +1560,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(FormData, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(DesktopNotification, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DesktopNotificationCenter, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(IDBFactory, IDBFactorySH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA_WITH_NAME(IDBFileHandle, FileHandle, nsEventTargetSH,
@@ -1704,17 +1700,16 @@ static nsDOMClassInfoData sClassInfoData
     nsresult rv = NS_OK;                                                        \
     nsCOMPtr<nsISupports> native = do_CreateInstance(_contract_id, &rv);        \
     native.forget(aInstancePtrResult);                                          \
     return rv;                                                                  \
   }
 
 NS_DEFINE_CONTRACT_CTOR(FileReader, NS_FILEREADER_CONTRACTID)
 NS_DEFINE_CONTRACT_CTOR(ArchiveReader, NS_ARCHIVEREADER_CONTRACTID)
-NS_DEFINE_CONTRACT_CTOR(FormData, NS_FORMDATA_CONTRACTID)
 NS_DEFINE_CONTRACT_CTOR(XPathEvaluator, NS_XPATH_EVALUATOR_CONTRACTID)
 NS_DEFINE_CONTRACT_CTOR(XSLTProcessor,
                         "@mozilla.org/document-transformer;1?type=xslt")
 NS_DEFINE_CONTRACT_CTOR(EventSource, NS_EVENTSOURCE_CONTRACTID)
 NS_DEFINE_CONTRACT_CTOR(MutationObserver, NS_DOMMUTATIONOBSERVER_CONTRACTID)
 #ifdef MOZ_SYS_MSG
 NS_DEFINE_CONTRACT_CTOR(MozActivity, NS_DOMACTIVITY_CONTRACTID)
 #endif
@@ -1769,17 +1764,16 @@ static const nsConstructorFuncMapData kC
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_event_interface)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, sms::SmsFilter::NewSmsFilter)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(FileReader, FileReaderCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(ArchiveReader, ArchiveReaderCtor)
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(FormData, FormDataCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XPathEvaluator, XPathEvaluatorCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(EventSource, EventSourceCtor)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MutationObserver, MutationObserverCtor)
 #ifdef MOZ_SYS_MSG
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozActivity, MozActivityCtor)
 #endif
 };
@@ -4196,20 +4190,16 @@ nsDOMClassInfo::Init()
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIPermissionChecker)
     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(FormData, nsIDOMFormData)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMFormData)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(DesktopNotification, nsIDOMDesktopNotification)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDesktopNotification)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DesktopNotificationCenter, nsIDOMDesktopNotificationCenter)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDesktopNotificationCenter)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -443,18 +443,16 @@ DOMCI_CLASS(EventListenerInfo)
 
 DOMCI_CLASS(TransitionEvent)
 DOMCI_CLASS(AnimationEvent)
 
 DOMCI_CLASS(ContentFrameMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
-DOMCI_CLASS(FormData)
-
 DOMCI_CLASS(DesktopNotification)
 DOMCI_CLASS(DesktopNotificationCenter)
 
 DOMCI_CLASS(IDBFactory)
 DOMCI_CLASS(IDBFileHandle)
 DOMCI_CLASS(IDBRequest)
 DOMCI_CLASS(IDBDatabase)
 DOMCI_CLASS(IDBObjectStore)
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -241,17 +241,22 @@ DOMInterfaces = {
 },
 
 'FileReaderSync': {
     'workers': True,
 },
 
 'FormData': [
 {
+    'nativeType': 'nsFormData'
+},
+{
     'workers': True,
+    'skipGen': True,
+    'nativeType': 'JSObject'
 }],
 
 'GainNode': [
 {
     'resultNotAddRefed': [ 'gain' ],
 }],
 
 'HTMLCollection': {
@@ -738,16 +743,17 @@ def addExternalIface(iface, nativeType=N
 # If you add one of these, you need to make sure nsDOMQS.h has the relevant
 # macros added for it
 def addExternalHTMLElement(element):
    nativeElement = 'ns' + element
    addExternalIface(element, nativeType=nativeElement,
                     headerFile=nativeElement + '.h')
 
 addExternalHTMLElement('HTMLCanvasElement')
+addExternalHTMLElement('HTMLFormElement')
 addExternalHTMLElement('HTMLImageElement')
 addExternalHTMLElement('HTMLMenuElement')
 addExternalHTMLElement('HTMLOptionElement')
 addExternalHTMLElement('HTMLOptGroupElement')
 addExternalHTMLElement('HTMLVideoElement')
 addExternalIface('Attr')
 addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h')
 addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h')
--- a/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
+++ b/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
@@ -1,15 +1,6 @@
 {
   "XMLHttpRequest interface constructor": true,
   "XMLHttpRequest interface: operation open(DOMString,DOMString,boolean,DOMString,DOMString)": true,
   "XMLHttpRequest interface: operation send(union)": true,
-  "FormData interface: existence and properties of interface object": true,
-  "FormData interface constructor": true,
-  "FormData interface: existence and properties of interface prototype object": true,
-  "FormData interface: existence and properties of interface prototype object's \"constructor\" property": true,
-  "Stringification of new FormData()": "debug",
-  "FormData interface: calling append(DOMString,Blob,DOMString) on new FormData() with too few arguments must throw TypeError": true,
-  "FormData interface: calling append(DOMString,DOMString) on new FormData() with too few arguments must throw TypeError": true,
-  "Stringification of new FormData(form)": "debug",
-  "FormData interface: calling append(DOMString,Blob,DOMString) on new FormData(form) with too few arguments must throw TypeError": true,
-  "FormData interface: calling append(DOMString,DOMString) on new FormData(form) with too few arguments must throw TypeError": true
+  "FormData interface constructor": true
 }
new file mode 100644
--- /dev/null
+++ b/dom/webidl/FormData.webidl
@@ -0,0 +1,18 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://xhr.spec.whatwg.org
+ */
+
+interface HTMLFormElement;
+
+[Constructor(optional HTMLFormElement form)]
+interface FormData {
+  // Not supported (bug 739174)
+  // void append(DOMString name, Blob value, optional DOMString filename);
+  void append(DOMString name, Blob value);
+  void append(DOMString name, DOMString value);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -31,16 +31,17 @@ webidl_files = \
   DynamicsCompressorNode.webidl \
   Element.webidl \
   EventHandler.webidl \
   EventListener.webidl \
   EventTarget.webidl \
   FileHandle.webidl \
   FileList.webidl \
   FileReaderSync.webidl \
+  FormData.webidl \
   Function.webidl \
   GainNode.webidl \
   HTMLCollection.webidl \
   HTMLElement.webidl \
   HTMLOptionsCollection.webidl \
   HTMLPropertiesCollection.webidl \
   ImageData.webidl \
   Node.webidl \
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -7,17 +7,16 @@
  * www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface Document;
 interface Blob;
-interface FormData;
 interface InputStream;
 interface MozChannel;
 interface IID;
 
 enum XMLHttpRequestResponseType {
   "",
   "arraybuffer",
   "blob",
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -174,16 +174,22 @@ public:
 
   void
   Send(const nsAString& aBody, ErrorResult& aRv);
 
   void
   Send(JSObject* aBody, ErrorResult& aRv);
 
   void
+  Send(JSObject& aBody, ErrorResult& aRv)
+  {
+    Send(&aBody, aRv);
+  }
+
+  void
   Send(ArrayBuffer& aBody, ErrorResult& aRv) {
     return Send(aBody.Obj(), aRv);
   }
 
   void
   SendAsBinary(const nsAString& aBody, ErrorResult& aRv);
 
   void
--- a/js/xpconnect/src/nsDOMQS.h
+++ b/js/xpconnect/src/nsDOMQS.h
@@ -4,16 +4,17 @@
 
 #ifndef nsDOMQS_h__
 #define nsDOMQS_h__
 
 #include "nsDOMClassInfoID.h"
 #include "nsGenericHTMLElement.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsHTMLDivElement.h"
+#include "nsHTMLFormElement.h"
 #include "nsHTMLImageElement.h"
 #include "nsHTMLOptionElement.h"
 #include "nsHTMLOptGroupElement.h"
 #include "nsHTMLVideoElement.h"
 #include "nsHTMLDocument.h"
 #include "nsICSSDeclaration.h"
 #include "nsSVGStylableElement.h"
 
@@ -151,16 +152,17 @@ xpc_qsUnwrapArg<_clazz>(JSContext *cx, j
     nsISupports* argRef = static_cast<nsIContent*>(*ppArgRef);                \
     nsresult rv = xpc_qsUnwrapArg<_clazz>(cx, v, ppArg, &argRef, vp);         \
     *ppArgRef = static_cast<_clazz*>(static_cast<nsIContent*>(argRef));       \
     return rv;                                                                \
 }
 
 DEFINE_UNWRAP_CAST_HTML(canvas, nsHTMLCanvasElement)
 DEFINE_UNWRAP_CAST_HTML(div, nsHTMLDivElement)
+DEFINE_UNWRAP_CAST_HTML(form, nsHTMLFormElement)
 DEFINE_UNWRAP_CAST_HTML(img, nsHTMLImageElement)
 DEFINE_UNWRAP_CAST_HTML(optgroup, nsHTMLOptGroupElement)
 DEFINE_UNWRAP_CAST_HTML(option, nsHTMLOptionElement)
 DEFINE_UNWRAP_CAST_HTML(video, nsHTMLVideoElement)
 
 inline nsISupports*
 ToSupports(nsContentList *p)
 {