Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 20 May 2013 08:02:31 -0400
changeset 143885 a914d2d6dfdce6a044f1a2abe6e67bc31a42aaf7
parent 143884 d48112a83fb29975e3620ef338dd1edfcd02306c (current diff)
parent 143861 ca7f8131a8d4ee0de01ee7d513a3543815846997 (diff)
child 143886 d6ee8d80627cb264fed411cc56ef3ba7e1d88a30
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.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
Merge m-c to inbound.
content/base/src/nsDOMDataChannel.h
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
--- a/content/base/public/nsIDOMDataChannel.idl
+++ b/content/base/public/nsIDOMDataChannel.idl
@@ -1,15 +1,26 @@
+/* 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 "domstubs.idl"
 
 #include "nsIDOMEventTarget.idl"
 
+%{C++
+#ifdef GetBinaryType
+// Windows apparently has a #define for GetBinaryType...
+#undef GetBinaryType
+#endif
+%}
+
 interface nsIVariant;
 
-[scriptable, builtinclass, uuid(1aed816d-1156-414e-8fe2-f01daa6021f0)]
+[scriptable, builtinclass, uuid(4410f28d-c9eb-481d-a47e-e7ef49f382c8)]
 interface nsIDOMDataChannel : nsIDOMEventTarget
 {
   readonly attribute DOMString label;
   readonly attribute DOMString protocol;
   readonly attribute boolean reliable;
   readonly attribute boolean ordered;
 
   readonly attribute DOMString readyState;
@@ -20,19 +31,9 @@ interface nsIDOMDataChannel : nsIDOMEven
   [implicit_jscontext] attribute jsval onopen;
   [implicit_jscontext] attribute jsval onerror;
   [implicit_jscontext] attribute jsval onclose;
   [implicit_jscontext] attribute jsval onmessage;
 
   attribute DOMString binaryType;
 
   void close();
-
-  /**
-   * Transmits data to other end of the connection.
-   * @param data The data to be transmitted.  Arraybuffers and Blobs are sent as
-   * binary data.  Strings are sent as UTF-8 text data.  Other types are
-   * converted to a String and sent as a String.
-   * @return if the connection is still established and the data was queued or
-   *         sent successfully.
-   */
-  void send(in nsIVariant data);
 };
--- a/content/base/src/moz.build
+++ b/content/base/src/moz.build
@@ -30,17 +30,20 @@ EXPORTS += [
     'nsScriptLoader.h',
     'nsStubDocumentObserver.h',
     'nsStubMutationObserver.h',
     'nsStyledElement.h',
     'nsTextFragment.h',
 ]
 
 if CONFIG['MOZ_WEBRTC']:
-    EXPORTS += ['nsDOMDataChannel.h']
+    EXPORTS += [
+        'nsDOMDataChannel.h',
+        'nsDOMDataChannelDeclarations.h',
+    ]
 
 EXPORTS.mozilla.dom += [
     'Attr.h',
     'Comment.h',
     'DOMImplementation.h',
     'DocumentFragment.h',
     'DocumentType.h',
     'EventSource.h',
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -1,138 +1,78 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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 "nsDOMDataChannel.h"
+
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #endif
 
 #include "base/basictypes.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetDataChannelLog();
 #endif
 #undef LOG
 #define LOG(args) PR_LOG(GetDataChannelLog(), PR_LOG_DEBUG, args)
 
 
-#include "nsDOMDataChannel.h"
+#include "nsDOMDataChannelDeclarations.h"
 #include "nsIDOMFile.h"
-#include "nsIJSNativeInitializer.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIDOMMessageEvent.h"
-#include "nsDOMClassInfo.h"
 #include "nsDOMEventTargetHelper.h"
 
-#include "js/Value.h"
-
 #include "nsError.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIScriptObjectPrincipal.h"
-#include "nsJSUtils.h"
 #include "nsNetUtil.h"
 #include "nsDOMFile.h"
 
 #include "DataChannel.h"
 
-#ifdef GetBinaryType
-// Windows apparently has a #define for GetBinaryType...
-#undef GetBinaryType
-#endif
-
 using namespace mozilla;
-
-class nsDOMDataChannel : public nsDOMEventTargetHelper,
-                         public nsIDOMDataChannel,
-                         public mozilla::DataChannelListener
-{
-public:
-  nsDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel)
-    : mDataChannel(aDataChannel)
-    , mBinaryType(DC_BINARY_TYPE_BLOB)
-  {}
-
-  ~nsDOMDataChannel()
-  {
-    // Don't call us anymore!  Likely isn't an issue (or maybe just less of
-    // one) once we block GC until all the (appropriate) onXxxx handlers
-    // are dropped. (See WebRTC spec)
-    LOG(("Close()ing %p", mDataChannel.get()));
-    mDataChannel->SetListener(nullptr, nullptr);
-    mDataChannel->Close();
-  }
-
-  nsresult Init(nsPIDOMWindow* aDOMWindow);
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMDATACHANNEL
-
-  NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDataChannel,
-                                           nsDOMEventTargetHelper)
+using namespace mozilla::dom;
 
-  nsresult
-  DoOnMessageAvailable(const nsACString& aMessage, bool aBinary);
-
-  virtual nsresult
-  OnMessageAvailable(nsISupports* aContext, const nsACString& aMessage);
-
-  virtual nsresult
-  OnBinaryMessageAvailable(nsISupports* aContext, const nsACString& aMessage);
-
-  virtual nsresult OnSimpleEvent(nsISupports* aContext, const nsAString& aName);
-
-  virtual nsresult
-  OnChannelConnected(nsISupports* aContext);
-
-  virtual nsresult
-  OnChannelClosed(nsISupports* aContext);
+nsDOMDataChannel::~nsDOMDataChannel()
+{
+  // Don't call us anymore!  Likely isn't an issue (or maybe just less of
+  // one) once we block GC until all the (appropriate) onXxxx handlers
+  // are dropped. (See WebRTC spec)
+  LOG(("Close()ing %p", mDataChannel.get()));
+  mDataChannel->SetListener(nullptr, nullptr);
+  mDataChannel->Close();
+}
 
-  virtual void
-  AppReady();
-
-private:
-  // Get msg info out of JS variable being sent (string, arraybuffer, blob)
-  nsresult GetSendParams(nsIVariant *aData, nsCString &aStringOut,
-                         nsCOMPtr<nsIInputStream> &aStreamOut,
-                         bool &aIsBinary, uint32_t &aOutgoingLength);
-
-  // Owning reference
-  nsRefPtr<mozilla::DataChannel> mDataChannel;
-  nsString  mOrigin;
-  enum
-  {
-    DC_BINARY_TYPE_ARRAYBUFFER,
-    DC_BINARY_TYPE_BLOB,
-  } mBinaryType;
-};
-
-DOMCI_DATA(DataChannel, nsDOMDataChannel)
+/* virtual */ JSObject*
+nsDOMDataChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return DataChannelBinding::Wrap(aCx, aScope, this);
+}
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMDataChannel,
                                                   nsDOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMDataChannel,
                                                 nsDOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(nsDOMDataChannel, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsDOMDataChannel, nsDOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDataChannel)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDataChannel)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DataChannel)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 nsresult
 nsDOMDataChannel::Init(nsPIDOMWindow* aDOMWindow)
 {
   nsresult rv;
   nsAutoString urlParam;
 
@@ -180,38 +120,63 @@ nsDOMDataChannel::GetLabel(nsAString& aL
 
 NS_IMETHODIMP
 nsDOMDataChannel::GetProtocol(nsAString& aProtocol)
 {
   mDataChannel->GetProtocol(aProtocol);
   return NS_OK;
 }
 
+uint16_t
+nsDOMDataChannel::Stream() const
+{
+  return mDataChannel->GetStream();
+}
+
 NS_IMETHODIMP
 nsDOMDataChannel::GetStream(uint16_t *aStream)
 {
-  mDataChannel->GetStream(aStream);
+  *aStream = Stream();
   return NS_OK;
 }
 
 // XXX should be GetType()?  Open question for the spec
+bool
+nsDOMDataChannel::Reliable() const
+{
+  return mDataChannel->GetType() == mozilla::DataChannelConnection::RELIABLE;
+}
+
 NS_IMETHODIMP
 nsDOMDataChannel::GetReliable(bool* aReliable)
 {
-  *aReliable = (mDataChannel->GetType() == mozilla::DataChannelConnection::RELIABLE);
+  *aReliable = Reliable();
   return NS_OK;
 }
 
+bool
+nsDOMDataChannel::Ordered() const
+{
+  return mDataChannel->GetOrdered();
+}
+
 NS_IMETHODIMP
 nsDOMDataChannel::GetOrdered(bool* aOrdered)
 {
-  *aOrdered = mDataChannel->GetOrdered();
+  *aOrdered = Ordered();
   return NS_OK;
 }
 
+RTCDataChannelState
+nsDOMDataChannel::ReadyState() const
+{
+  return static_cast<RTCDataChannelState>(mDataChannel->GetReadyState());
+}
+
+
 NS_IMETHODIMP
 nsDOMDataChannel::GetReadyState(nsAString& aReadyState)
 {
   uint16_t readyState = mDataChannel->GetReadyState();
   // From the WebRTC spec
   const char * stateName[] = {
     "connecting",
     "open",
@@ -220,20 +185,26 @@ nsDOMDataChannel::GetReadyState(nsAStrin
   };
   MOZ_ASSERT(/*readyState >= mozilla::DataChannel::CONNECTING && */ // Always true due to datatypes
              readyState <= mozilla::DataChannel::CLOSED);
   aReadyState.AssignASCII(stateName[readyState]);
 
   return NS_OK;
 }
 
+uint32_t
+nsDOMDataChannel::BufferedAmount() const
+{
+  return mDataChannel->GetBufferedAmount();
+}
+
 NS_IMETHODIMP
 nsDOMDataChannel::GetBufferedAmount(uint32_t* aBufferedAmount)
 {
-  *aBufferedAmount = mDataChannel->GetBufferedAmount();
+  *aBufferedAmount = BufferedAmount();
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDOMDataChannel::GetBinaryType(nsAString & aBinaryType)
 {
   switch (mBinaryType) {
   case DC_BINARY_TYPE_ARRAYBUFFER:
     aBinaryType.AssignLiteral("arraybuffer");
@@ -262,130 +233,115 @@ nsDOMDataChannel::SetBinaryType(const ns
 
 NS_IMETHODIMP
 nsDOMDataChannel::Close()
 {
   mDataChannel->Close();
   return NS_OK;
 }
 
-// Almost a clone of nsWebSocketChannel::Send()
-NS_IMETHODIMP
-nsDOMDataChannel::Send(nsIVariant* aData)
+// All of the following is copy/pasted from WebSocket.cpp.
+void
+nsDOMDataChannel::Send(const nsAString& aData, ErrorResult& aRv)
+{
+  NS_ConvertUTF16toUTF8 msgString(aData);
+  Send(nullptr, msgString, msgString.Length(), false, aRv);
+}
+
+void
+nsDOMDataChannel::Send(nsIDOMBlob* aData, ErrorResult& aRv)
+{
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+
+  nsCOMPtr<nsIInputStream> msgStream;
+  nsresult rv = aData->GetInternalStream(getter_AddRefs(msgStream));
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  uint64_t msgLength;
+  rv = aData->GetSize(&msgLength);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return;
+  }
+
+  if (msgLength > UINT32_MAX) {
+    aRv.Throw(NS_ERROR_FILE_TOO_BIG);
+    return;
+  }
+
+  Send(msgStream, EmptyCString(), msgLength, true, aRv);
+}
+
+void
+nsDOMDataChannel::Send(ArrayBuffer& aData, ErrorResult& aRv)
+{
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+
+  MOZ_ASSERT(sizeof(*aData.Data()) == 1);
+  uint32_t len = aData.Length();
+  char* data = reinterpret_cast<char*>(aData.Data());
+
+  nsDependentCSubstring msgString(data, len);
+  Send(nullptr, msgString, len, true, aRv);
+}
+
+void
+nsDOMDataChannel::Send(ArrayBufferView& aData, ErrorResult& aRv)
+{
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+
+  MOZ_ASSERT(sizeof(*aData.Data()) == 1);
+  uint32_t len = aData.Length();
+  char* data = reinterpret_cast<char*>(aData.Data());
+
+  nsDependentCSubstring msgString(data, len);
+  Send(nullptr, msgString, len, true, aRv);
+}
+
+void
+nsDOMDataChannel::Send(nsIInputStream* aMsgStream,
+                       const nsACString& aMsgString,
+                       uint32_t aMsgLength,
+                       bool aIsBinary,
+                       ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   uint16_t state = mDataChannel->GetReadyState();
 
   // In reality, the DataChannel protocol allows this, but we want it to
   // look like WebSockets
   if (state == mozilla::DataChannel::CONNECTING) {
-    return NS_ERROR_DOM_INVALID_STATE_ERR;
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
   }
 
-  nsCString msgString;
-  nsCOMPtr<nsIInputStream> msgStream;
-  bool isBinary;
-  uint32_t msgLen;
-  nsresult rv = GetSendParams(aData, msgString, msgStream, isBinary, msgLen);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   if (state == mozilla::DataChannel::CLOSING ||
       state == mozilla::DataChannel::CLOSED) {
-    return NS_OK;
+    return;
   }
 
   MOZ_ASSERT(state == mozilla::DataChannel::OPEN,
-             "Unknown state in nsWebSocket::Send");
+             "Unknown state in nsDOMDataChannel::Send");
 
   int32_t sent;
-  if (msgStream) {
-    sent = mDataChannel->SendBinaryStream(msgStream, msgLen);
+  if (aMsgStream) {
+    sent = mDataChannel->SendBinaryStream(aMsgStream, aMsgLength);
   } else {
-    if (isBinary) {
-      sent = mDataChannel->SendBinaryMsg(msgString);
+    if (aIsBinary) {
+      sent = mDataChannel->SendBinaryMsg(aMsgString);
     } else {
-      sent = mDataChannel->SendMsg(msgString);
+      sent = mDataChannel->SendMsg(aMsgString);
     }
   }
-  return sent >= 0 ? NS_OK : NS_ERROR_FAILURE;
-}
-
-// XXX Exact clone of nsWebSocketChannel::GetSendParams() - find a way to share!
-nsresult
-nsDOMDataChannel::GetSendParams(nsIVariant* aData, nsCString& aStringOut,
-                                nsCOMPtr<nsIInputStream>& aStreamOut,
-                                bool& aIsBinary, uint32_t& aOutgoingLength)
-{
-  // Get type of data (arraybuffer, blob, or string)
-  uint16_t dataType;
-  nsresult rv = aData->GetDataType(&dataType);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (dataType == nsIDataType::VTYPE_INTERFACE ||
-      dataType == nsIDataType::VTYPE_INTERFACE_IS) {
-    nsCOMPtr<nsISupports> supports;
-    nsID* iid;
-    rv = aData->GetAsInterface(&iid, getter_AddRefs(supports));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsMemory::Free(iid);
-
-    AutoSafeJSContext cx;
-    // ArrayBuffer?
-    JS::Rooted<JS::Value> realVal(cx);
-    JS::Rooted<JSObject*> obj(cx);
-    nsresult rv = aData->GetAsJSVal(realVal.address());
-    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
-        (obj = JSVAL_TO_OBJECT(realVal)) &&
-        (JS_IsArrayBufferObject(obj))) {
-      int32_t len = JS_GetArrayBufferByteLength(obj);
-      char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(obj));
-
-      aStringOut.Assign(data, len);
-      aIsBinary = true;
-      aOutgoingLength = len;
-      return NS_OK;
-    }
-
-    // Blob?
-    nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob) {
-      rv = blob->GetInternalStream(getter_AddRefs(aStreamOut));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      // GetSize() should not perform blocking I/O (unlike Available())
-      uint64_t blobLen;
-      rv = blob->GetSize(&blobLen);
-      NS_ENSURE_SUCCESS(rv, rv);
-      if (blobLen > UINT32_MAX) {
-        return NS_ERROR_FILE_TOO_BIG;
-      }
-      aOutgoingLength = static_cast<uint32_t>(blobLen);
-
-      aIsBinary = true;
-      return NS_OK;
-    }
+  if (sent < 0) {
+    aRv.Throw(NS_ERROR_FAILURE);
   }
-
-  // Text message: if not already a string, turn it into one.
-  // TODO: bug 704444: Correctly coerce any JS type to string
-  //
-  PRUnichar* data = nullptr;
-  uint32_t len = 0;
-  rv = aData->GetAsWStringWithSize(&len, &data);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsString text;
-  text.Adopt(data, len);
-
-  CopyUTF16toUTF8(text, aStringOut);
-
-  aIsBinary = false;
-  aOutgoingLength = aStringOut.Length();
-  return NS_OK;
 }
 
 nsresult
 nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
                                        bool aBinary)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/content/base/src/nsDOMDataChannel.h
+++ b/content/base/src/nsDOMDataChannel.h
@@ -1,30 +1,110 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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/. */
 
-#ifndef nsDOMDataChannel_h__
-#define nsDOMDataChannel_h__
+#ifndef nsDOMDataChannel_h
+#define nsDOMDataChannel_h
 
-// This defines only what's necessary to create nsDOMDataChannels, since this
-// gets used with MOZ_INTERNAL_API not set for media/webrtc/signaling/testing
-
-#include "nsCOMPtr.h"
+#include "mozilla/dom/DataChannelBinding.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/net/DataChannel.h"
+#include "nsDOMEventTargetHelper.h"
 #include "nsIDOMDataChannel.h"
 
-namespace mozilla {
-   class DataChannel;
-}
+class nsDOMDataChannel : public nsDOMEventTargetHelper,
+                         public nsIDOMDataChannel,
+                         public mozilla::DataChannelListener
+{
+public:
+  nsDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel)
+    : mDataChannel(aDataChannel)
+    , mBinaryType(DC_BINARY_TYPE_BLOB)
+  {
+    SetIsDOMBinding();
+  }
+
+  ~nsDOMDataChannel();
 
-class nsPIDOMWindow;
+  nsresult Init(nsPIDOMWindow* aDOMWindow);
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMDATACHANNEL
+
+  NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
+
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDataChannel,
+                                           nsDOMEventTargetHelper)
+
+  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+    MOZ_OVERRIDE;
+  nsPIDOMWindow* GetParentObject() const
+  {
+    return GetOwner();
+  }
 
-nsresult
-NS_NewDOMDataChannel(already_AddRefed<mozilla::DataChannel> dataChannel,
-                     nsPIDOMWindow* aWindow,
-                     nsIDOMDataChannel** domDataChannel);
+  // WebIDL
+  // Uses XPIDL GetLabel.
+  bool Reliable() const;
+  mozilla::dom::RTCDataChannelState ReadyState() const;
+  uint32_t BufferedAmount() const;
+  IMPL_EVENT_HANDLER(open)
+  IMPL_EVENT_HANDLER(error)
+  IMPL_EVENT_HANDLER(close)
+  // Uses XPIDL Close.
+  IMPL_EVENT_HANDLER(message)
+  mozilla::dom::RTCDataChannelType BinaryType() const
+  {
+    return static_cast<mozilla::dom::RTCDataChannelType>(
+      static_cast<int>(mBinaryType));
+  }
+  void SetBinaryType(mozilla::dom::RTCDataChannelType aType)
+  {
+    mBinaryType = static_cast<DataChannelBinaryType>(
+      static_cast<int>(aType));
+  }
+  void Send(const nsAString& aData, mozilla::ErrorResult& aRv);
+  void Send(nsIDOMBlob* aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::ArrayBuffer& aData, mozilla::ErrorResult& aRv);
+  void Send(mozilla::dom::ArrayBufferView& aData, mozilla::ErrorResult& aRv);
+
+  // Uses XPIDL GetProtocol.
+  bool Ordered() const;
+  uint16_t Stream() const;
+
+  nsresult
+  DoOnMessageAvailable(const nsACString& aMessage, bool aBinary);
 
-// Tell DataChannel it's ok to deliver open and message events
-void NS_DataChannelAppReady(nsIDOMDataChannel* domDataChannel);
+  virtual nsresult
+  OnMessageAvailable(nsISupports* aContext, const nsACString& aMessage);
+
+  virtual nsresult
+  OnBinaryMessageAvailable(nsISupports* aContext, const nsACString& aMessage);
+
+  virtual nsresult OnSimpleEvent(nsISupports* aContext, const nsAString& aName);
+
+  virtual nsresult
+  OnChannelConnected(nsISupports* aContext);
+
+  virtual nsresult
+  OnChannelClosed(nsISupports* aContext);
 
-#endif
+  virtual void
+  AppReady();
+
+private:
+  void Send(nsIInputStream* aMsgStream, const nsACString& aMsgString,
+            uint32_t aMsgLength, bool aIsBinary, mozilla::ErrorResult& aRv);
+
+  // Owning reference
+  nsRefPtr<mozilla::DataChannel> mDataChannel;
+  nsString  mOrigin;
+  enum DataChannelBinaryType {
+    DC_BINARY_TYPE_ARRAYBUFFER,
+    DC_BINARY_TYPE_BLOB,
+  };
+  DataChannelBinaryType mBinaryType;
+};
+
+#endif // nsDOMDataChannel_h
copy from content/base/src/nsDOMDataChannel.h
copy to content/base/src/nsDOMDataChannelDeclarations.h
--- a/content/base/src/nsDOMDataChannel.h
+++ b/content/base/src/nsDOMDataChannelDeclarations.h
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* 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/. */
 
-#ifndef nsDOMDataChannel_h__
-#define nsDOMDataChannel_h__
+#ifndef nsDOMDataChannelDeclarations_h
+#define nsDOMDataChannelDeclarations_h
 
 // This defines only what's necessary to create nsDOMDataChannels, since this
 // gets used with MOZ_INTERNAL_API not set for media/webrtc/signaling/testing
 
 #include "nsCOMPtr.h"
 #include "nsIDOMDataChannel.h"
 
 namespace mozilla {
@@ -22,9 +22,9 @@ class nsPIDOMWindow;
 nsresult
 NS_NewDOMDataChannel(already_AddRefed<mozilla::DataChannel> dataChannel,
                      nsPIDOMWindow* aWindow,
                      nsIDOMDataChannel** domDataChannel);
 
 // Tell DataChannel it's ok to deliver open and message events
 void NS_DataChannelAppReady(nsIDOMDataChannel* domDataChannel);
 
-#endif
+#endif // nsDOMDataChannelDeclarations_h
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -160,17 +160,17 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMEvent
 
 // WebIDL event handlers
 #define IMPL_EVENT_HANDLER(_event)                                        \
   inline mozilla::dom::EventHandlerNonNull* GetOn##_event()               \
   {                                                                       \
     return GetEventHandler(nsGkAtoms::on##_event);                        \
   }                                                                       \
   inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback, \
-                            ErrorResult& aRv)                             \
+                            mozilla::ErrorResult& aRv)                    \
   {                                                                       \
     SetEventHandler(nsGkAtoms::on##_event, aCallback, aRv);               \
   }
 
 /* Use this macro to declare functions that forward the behavior of this
  * interface to another object.
  * This macro doesn't forward PreHandleEvent because sometimes subclasses
  * want to override it.
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -328,20 +328,16 @@ using mozilla::dom::workers::ResolveWork
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Likely.h"
 
 #ifdef MOZ_TIME_MANAGER
 #include "TimeManager.h"
 #endif
 
-#ifdef MOZ_WEBRTC
-#include "nsIDOMDataChannel.h"
-#endif
-
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
 
@@ -899,21 +895,16 @@ static nsDOMClassInfoData sClassInfoData
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 #ifdef MOZ_TIME_MANAGER
   NS_DEFINE_CLASSINFO_DATA(MozTimeManager, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
-
-#ifdef MOZ_WEBRTC
-  NS_DEFINE_CLASSINFO_DATA(DataChannel, nsEventTargetSH,
-                           EVENTTARGET_SCRIPTABLE_FLAGS)
-#endif
 };
 
 #define NS_DEFINE_CONTRACT_CTOR(_class, _contract_id)                           \
   static nsresult                                                               \
   _class##Ctor(nsISupports** aInstancePtrResult)                                \
   {                                                                             \
     nsresult rv = NS_OK;                                                        \
     nsCOMPtr<nsISupports> native = do_CreateInstance(_contract_id, &rv);        \
@@ -2273,23 +2264,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
 #ifdef MOZ_TIME_MANAGER
   DOM_CLASSINFO_MAP_BEGIN(MozTimeManager, nsIDOMMozTimeManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozTimeManager)
   DOM_CLASSINFO_MAP_END
 #endif
 
-#ifdef MOZ_WEBRTC
-  DOM_CLASSINFO_MAP_BEGIN(DataChannel, nsIDOMDataChannel)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMDataChannel)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-  DOM_CLASSINFO_MAP_END
-#endif
-
   MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount,
                     "The number of items in sClassInfoData doesn't match the "
                     "number of nsIDOMClassInfo ID's, this is bad! Fix it!");
 
 #ifdef DEBUG
   for (size_t i = 0; i < eDOMClassInfoIDCount; i++) {
     if (!sClassInfoData[i].u.mConstructorFptr ||
         sClassInfoData[i].mDebugID != i) {
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -234,10 +234,9 @@ DOMCI_CLASS(LockedFile)
 
 DOMCI_CLASS(CSSFontFeatureValuesRule)
 
 #ifdef MOZ_TIME_MANAGER
 DOMCI_CLASS(MozTimeManager)
 #endif
 
 #ifdef MOZ_WEBRTC
-DOMCI_CLASS(DataChannel)
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -226,16 +226,20 @@ DOMInterfaces = {
 'CSSValue': {
   'concrete': False
 },
 
 'CSSValueList': {
   'nativeType': 'nsDOMCSSValueList'
 },
 
+'DataChannel': {
+    'nativeType': 'nsDOMDataChannel',
+},
+
 'DataContainerEvent': {
     'nativeType': 'nsDOMDataContainerEvent',
 },
 
 'DelayNode': [
 {
     'resultNotAddRefed': [ 'delayTime' ],
 }],
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6052,17 +6052,17 @@ class ClassMethod(ClassItem):
         args = ', '.join([a.define() for a in self.args])
 
         body = CGIndenter(CGGeneric(self.getBody())).define()
 
         return string.Template("""${templateClause}${decorators}${returnType}
 ${className}::${name}(${args})${const}
 {
 ${body}
-}\n
+}
 """).substitute({ 'templateClause': templateClause,
                   'decorators': self.getDecorators(False),
                   'returnType': self.returnType,
                   'className': cgClass.getNameString(),
                   'name': self.name,
                   'args': args,
                   'const': ' const' if self.const else '',
                   'body': body })
@@ -6091,17 +6091,17 @@ class ClassConstructor(ClassItem):
     """
     def __init__(self, args, inline=False, bodyInHeader=False,
                  visibility="private", explicit=False, baseConstructors=None,
                  body=""):
         self.args = args
         self.inline = inline or bodyInHeader
         self.bodyInHeader = bodyInHeader
         self.explicit = explicit
-        self.baseConstructors = baseConstructors
+        self.baseConstructors = baseConstructors or []
         self.body = body
         ClassItem.__init__(self, None, visibility)
 
     def getDecorators(self, declaring):
         decorators = []
         if self.explicit:
             decorators.append('explicit')
         if self.inline and declaring:
@@ -6109,17 +6109,17 @@ class ClassConstructor(ClassItem):
         if decorators:
             return ' '.join(decorators) + ' '
         return ''
 
     def getInitializationList(self, cgClass):
         items = [str(c) for c in self.baseConstructors]
         for m in cgClass.members:
             if not m.static:
-                initialize = m.getBody()
+                initialize = m.body
                 if initialize:
                     items.append(m.name + "(" + initialize + ")")
             
         if len(items) > 0:
             return '\n  : ' + ',\n    '.join(items)
         return ''
 
     def getBody(self):
@@ -6150,17 +6150,17 @@ class ClassConstructor(ClassItem):
 
         body = '  ' + self.getBody()
         body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n  '))
         if len(body) > 0:
             body += '\n'
 
         return string.Template("""${decorators}
 ${className}::${className}(${args})${initializationList}
-{${body}}\n
+{${body}}
 """).substitute({ 'decorators': self.getDecorators(False),
                   'className': cgClass.getNameString(),
                   'args': args,
                   'initializationList': self.getInitializationList(cgClass),
                   'body': body })
 
 class ClassDestructor(ClassItem):
     """
@@ -6220,17 +6220,17 @@ class ClassDestructor(ClassItem):
 
         body = '  ' + self.getBody()
         body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n  '))
         if len(body) > 0:
             body += '\n'
 
         return string.Template("""${decorators}
 ${className}::~${className}()
-{${body}}\n
+{${body}}
 """).substitute({ 'decorators': self.getDecorators(False),
                   'className': cgClass.getNameString(),
                   'body': body })
 
 class ClassMember(ClassItem):
     def __init__(self, name, type, visibility="private", static=False,
                  body=None):
         self.type = type;
@@ -6284,17 +6284,18 @@ class ClassEnum(ClassItem):
     def define(self, cgClass):
         # Only goes in the header
         return ''
 
 class CGClass(CGThing):
     def __init__(self, name, bases=[], members=[], constructors=[],
                  destructor=None, methods=[],
                  typedefs = [], enums=[], templateArgs=[],
-                 templateSpecialization=[], isStruct=False, indent='',
+                 templateSpecialization=[], isStruct=False,
+                 disallowCopyConstruction=False, indent='',
                  decorators='',
                  extradeclarations='',
                  extradefinitions=''):
         CGThing.__init__(self)
         self.name = name
         self.bases = bases
         self.members = members
         self.constructors = constructors
@@ -6302,16 +6303,17 @@ class CGClass(CGThing):
         # code wants lists of members.
         self.destructors = [destructor] if destructor else []
         self.methods = methods
         self.typedefs = typedefs
         self.enums = enums
         self.templateArgs = templateArgs
         self.templateSpecialization = templateSpecialization
         self.isStruct = isStruct
+        self.disallowCopyConstruction = disallowCopyConstruction
         self.indent = indent
         self.defaultVisibility ='public' if isStruct else 'private'
         self.decorators = decorators
         self.extradeclarations = extradeclarations
         self.extradefinitions = extradefinitions
 
     def getNameString(self):
         className = self.name
@@ -6387,19 +6389,30 @@ class CGClass(CGThing):
                             result = result + separator
                         declaration = member.declare(cgClass)
                         declaration = CGIndenter(CGGeneric(declaration)).define()
                         result = result + declaration
                         itemCount = itemCount + 1
                     lastVisibility = visibility
             return (result, lastVisibility, itemCount)
 
+        if self.disallowCopyConstruction:
+            class DisallowedCopyConstructor(object):
+                def __init__(self):
+                    self.visibility = "private"
+                def declare(self, cgClass):
+                    name = cgClass.getNameString()
+                    return "%s(const %s&) MOZ_DELETE;\n" % (name, name)
+            disallowedCopyConstructors = [DisallowedCopyConstructor()]
+        else:
+            disallowedCopyConstructors = []
+
         order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
-                 (self.constructors, '\n'), (self.destructors, '\n'),
-                 (self.methods, '\n')]
+                 (self.constructors + disallowedCopyConstructors, '\n'),
+                 (self.destructors, '\n'), (self.methods, '\n')]
 
         lastVisibility = self.defaultVisibility
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, lastVisibility, itemCount) = \
                 declareMembers(self, memberList, lastVisibility, itemCount,
                                separator)
             if self.indent:
@@ -6411,21 +6424,24 @@ class CGClass(CGThing):
         return result
 
     def define(self):
         def defineMembers(cgClass, memberList, itemCount, separator=''):
             result = ''
             for member in memberList:
                 if itemCount != 0:
                     result = result + separator
-                result = result + member.define(cgClass)
-                itemCount = itemCount + 1
+                definition = member.define(cgClass)
+                if definition:
+                    # Member variables would only produce empty lines here.
+                    result += definition
+                    itemCount += 1
             return (result, itemCount)
 
-        order = [(self.members, '\n'), (self.constructors, '\n'),
+        order = [(self.members, ''), (self.constructors, '\n'),
                  (self.destructors, '\n'), (self.methods, '\n')]
 
         result = self.extradefinitions
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
@@ -7487,188 +7503,214 @@ class CGNamespacedEnum(CGThing):
     def define(self):
         assert False # Only for headers.
 
 class CGDictionary(CGThing):
     def __init__(self, dictionary, descriptorProvider):
         self.dictionary = dictionary
         self.descriptorProvider = descriptorProvider
         self.workers = descriptorProvider.workers
+        # NOTE: jsids are per-runtime, so don't use them in workers
         self.needToInitIds = not self.workers and len(dictionary.members) > 0
         self.memberInfo = [
             (member,
              getJSToNativeConversionInfo(member.type,
                                          descriptorProvider,
                                          isMember="Dictionary",
                                          isOptional=(not member.defaultValue),
                                          defaultValue=member.defaultValue))
             for member in dictionary.members ]
+        self.structs = self.getStructs()
 
     def declare(self):
-        d = self.dictionary
-        if d.parent:
-            inheritance = "%s" % self.makeClassName(d.parent)
-        elif not self.workers:
-            inheritance = "MainThreadDictionaryBase"
-        else:
-            inheritance = "DictionaryBase"
-        memberDecls = ["  %s %s;" %
-                       (self.getMemberType(m),
-                        self.makeMemberName(m[0].identifier.name))
-                       for m in self.memberInfo]
-
-        return (string.Template(
-                "struct ${selfName} : public ${inheritance} {\n"
-                "  ${selfName}() {}\n"
-                "  bool Init(JSContext* cx, JS::Handle<JS::Value> val);\n" +
-                ("  bool Init(const nsAString& aJSON);\n" if not self.workers else "") +
-                "  bool ToObject(JSContext* cx, JS::Handle<JSObject*> parentObject, JS::Value *vp) const;\n"
-                "  void TraceDictionary(JSTracer* trc);\n"
-                "\n" +
-                "\n".join(memberDecls) + "\n"
-                "private:\n"
-                "  // Disallow copy-construction\n"
-                "  ${selfName}(const ${selfName}&) MOZ_DELETE;\n" +
-                # NOTE: jsids are per-runtime, so don't use them in workers
-                ("  static bool InitIds(JSContext* cx);\n"
-                 "  static bool initedIds;\n" if self.needToInitIds else "") +
-                "\n".join("  static jsid " +
-                          self.makeIdName(m.identifier.name) + ";" for
-                          m in d.members) + "\n"
-                "};\n"
-                "struct ${selfName}Initializer : public ${selfName} {\n"
-                "  ${selfName}Initializer() {\n"
-                "    // Safe to pass a null context if we pass a null value\n"
-                "    Init(nullptr, JS::NullHandleValue);\n"
-                "  }\n"
-                "};").substitute( { "selfName": self.makeClassName(d),
-                                    "inheritance": inheritance }))
+        return self.structs.declare()
 
     def define(self):
-        d = self.dictionary
-        if d.parent:
-            initParent = ("// Per spec, we init the parent's members first\n"
-                          "if (!%s::Init(cx, val)) {\n"
-                          "  return false;\n"
-                          "}\n" % self.makeClassName(d.parent))
-            toObjectParent = ("// Per spec, we define the parent's members first\n"
-                              "if (!%s::ToObject(cx, parentObject, vp)) {\n"
-                              "  return false;\n"
-                              "}\n" % self.makeClassName(d.parent))
-            ensureObject = "JS::Rooted<JSObject*> obj(cx, &vp->toObject());\n"
-            traceParent = ("%s::TraceDictionary(trc);\n" %
-                           self.makeClassName(d.parent))
-        else:
-            initParent = ""
-            toObjectParent = ""
-            ensureObject = ("JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));\n"
-                            "if (!obj) {\n"
-                            "  return false;\n"
-                            "}\n"
-                            "*vp = JS::ObjectValue(*obj);\n")
-            traceParent = ""
-
-        memberInits = [CGIndenter(self.getMemberConversion(m)).define()
+        return self.structs.define()
+
+    def base(self):
+        if self.dictionary.parent:
+            return self.makeClassName(self.dictionary.parent)
+        if not self.workers:
+            return "MainThreadDictionaryBase"
+        return "DictionaryBase"
+
+    def initMethod(self):
+        body = (
+            "// Passing a null JSContext is OK only if we're initing from null,\n"
+            "// Since in that case we will not have to do any property gets\n"
+            "MOZ_ASSERT_IF(!cx, val.isNull());\n")
+
+        if self.needToInitIds:
+            body += (
+                "if (cx && !initedIds && !InitIds(cx)) {\n"
+                "  return false;\n"
+                "}\n")
+
+        if self.dictionary.parent:
+            body += (
+                "// Per spec, we init the parent's members first\n"
+                "if (!%s::Init(cx, val)) {\n"
+                "  return false;\n"
+                "}\n") % self.makeClassName(self.dictionary.parent)
+
+        memberInits = [self.getMemberConversion(m).define()
                        for m in self.memberInfo]
+        if memberInits:
+            body += (
+                "JSBool found;\n"
+                "JS::Rooted<JS::Value> temp(cx);\n"
+                "bool isNull = val.isNullOrUndefined();\n")
+
+        body += (
+            "if (!IsConvertibleToDictionary(cx, val)) {\n"
+            "  return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY);\n"
+            "}\n"
+            "\n")
+
+        if memberInits:
+            body += "\n\n".join(memberInits) + "\n"
+
+        body += "return true;"
+
+        return ClassMethod("Init", "bool", [
+            Argument('JSContext*', 'cx'),
+            Argument('JS::Handle<JS::Value>', 'val'),
+        ], body=body)
+
+    def initFromJSONMethod(self):
+        assert not self.workers
+        return ClassMethod("Init", "bool", [
+                Argument('const nsAString&', 'aJSON'),
+            ], body=(
+                "AutoSafeJSContext cx;\n"
+                "JSAutoRequest ar(cx);\n"
+                "JS::Rooted<JS::Value> json(cx);\n"
+                "bool ok = ParseJSON(cx, aJSON, &json);\n"
+                "NS_ENSURE_TRUE(ok, false);\n"
+                "return Init(cx, json);"
+            ))
+
+    def toObjectMethod(self):
+        body = ""
+        if self.needToInitIds:
+            body += (
+                "if (!initedIds && !InitIds(cx)) {\n"
+                "  return false;\n"
+                "}\n")
+
+        if self.dictionary.parent:
+            body += (
+                "// Per spec, we define the parent's members first\n"
+                "if (!%s::ToObject(cx, parentObject, vp)) {\n"
+                "  return false;\n"
+                "}\n"
+                "JS::Rooted<JSObject*> obj(cx, &vp->toObject());\n"
+                "\n") % self.makeClassName(self.dictionary.parent)
+        else:
+            body += (
+                "JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));\n"
+                "if (!obj) {\n"
+                "  return false;\n"
+                "}\n"
+                "*vp = JS::ObjectValue(*obj);\n"
+                "\n")
+
+        body += "\n\n".join(self.getMemberDefinition(m).define()
+                            for m in self.memberInfo)
+        body += "\n\nreturn true;"
+
+        return ClassMethod("ToObject", "bool", [
+            Argument('JSContext*', 'cx'),
+            Argument('JS::Handle<JSObject*>', 'parentObject'),
+            Argument('JS::Value*', 'vp'),
+        ], const=True, body=body)
+
+    def initIdsMethod(self):
+        assert self.needToInitIds
         idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
                             (m.identifier.name + "_id", m.identifier.name))
-                  for m in d.members]
+                  for m in self.dictionary.members]
         idinit = CGList(idinit, " ||\n")
         idinit = CGWrapper(idinit, pre="if (",
                            post=(") {\n"
                                  "  return false;\n"
                                  "}"),
                            reindent=True)
-        memberDefines = [CGIndenter(self.getMemberDefinition(m)).define()
-                         for m in self.memberInfo]
-        memberTraces = [CGIndenter(self.getMemberTrace(m)).define()
+        body = (
+           "MOZ_ASSERT(!initedIds);\n"
+           "%s\n"
+           "initedIds = true;\n"
+           "return true;") % idinit.define()
+
+        return ClassMethod("InitIds", "bool", [
+            Argument("JSContext*", "cx"),
+        ], static=True, body=body, visibility="private")
+
+    def traceDictionaryMethod(self):
+        body = ""
+        if self.dictionary.parent:
+            cls = self.makeClassName(self.dictionary.parent)
+            body += "%s::TraceDictionary(trc);\n" % cls
+
+        memberTraces = [self.getMemberTrace(m)
                         for m in self.dictionary.members
                         if typeNeedsCx(m.type, self.descriptorProvider)]
 
-        return string.Template(
-            # NOTE: jsids are per-runtime, so don't use them in workers
-            ("bool ${selfName}::initedIds = false;\n" +
-             "\n".join("jsid ${selfName}::%s = JSID_VOID;" %
-                       self.makeIdName(m.identifier.name)
-                       for m in d.members) + "\n"
-             "\n"
-             "bool\n"
-             "${selfName}::InitIds(JSContext* cx)\n"
-             "{\n"
-             "  MOZ_ASSERT(!initedIds);\n"
-             "${idInit}\n"
-             "  initedIds = true;\n"
-             "  return true;\n"
-             "}\n"
-             "\n" if self.needToInitIds else "") +
-            "bool\n"
-            "${selfName}::Init(JSContext* cx, JS::Handle<JS::Value> val)\n"
-            "{\n"
-            "  // Passing a null JSContext is OK only if we're initing from null,\n"
-            "  // Since in that case we will not have to do any property gets\n"
-            "  MOZ_ASSERT_IF(!cx, val.isNull());\n" +
-            # NOTE: jsids are per-runtime, so don't use them in workers
-            ("  if (cx && !initedIds && !InitIds(cx)) {\n"
-             "    return false;\n"
-             "  }\n" if self.needToInitIds else "") +
-            "${initParent}" +
-            ("  JSBool found;\n"
-             "  JS::Rooted<JS::Value> temp(cx);\n"
-             "  bool isNull = val.isNullOrUndefined();\n" if len(memberInits) > 0 else "") +
-            "  if (!IsConvertibleToDictionary(cx, val)) {\n"
-            "    return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY);\n"
-            "  }\n"
-            "\n"
-            "${initMembers}\n"
-            "  return true;\n"
-            "}\n"
-            "\n" +
-            ("bool\n"
-             "${selfName}::Init(const nsAString& aJSON)\n"
-             "{\n"
-             "  AutoSafeJSContext cx;\n"
-             "  JSAutoRequest ar(cx);\n"
-             "  JS::Rooted<JS::Value> json(cx);\n"
-             "  bool ok = ParseJSON(cx, aJSON, &json);\n"
-             "  NS_ENSURE_TRUE(ok, false);\n"
-             "  return Init(cx, json);\n"
-             "}\n" if not self.workers else "") +
-            "\n"
-            "bool\n"
-            "${selfName}::ToObject(JSContext* cx, JS::Handle<JSObject*> parentObject, JS::Value *vp) const\n"
-            "{\n" +
-            # NOTE: jsids are per-runtime, so don't use them in workers
-            ("  if (!initedIds && !InitIds(cx)) {\n"
-             "    return false;\n"
-             "  }\n" if self.needToInitIds else "") +
-            "${toObjectParent}"
-            "${ensureObject}"
-            "\n"
-            "${defineMembers}\n"
-            "\n"
-            "  return true;\n"
-            "}\n"
-            "\n"
-            "void\n"
-            "${selfName}::TraceDictionary(JSTracer* trc)\n"
-            "{\n"
-            "${traceParent}"
-            "${traceMembers}\n"
-            "}").substitute({
-                "selfName": self.makeClassName(d),
-                "initParent": CGIndenter(CGGeneric(initParent)).define(),
-                "initMembers": "\n\n".join(memberInits),
-                "idInit": CGIndenter(idinit).define(),
-                "isMainThread": toStringBool(not self.workers),
-                "toObjectParent": CGIndenter(CGGeneric(toObjectParent)).define(),
-                "ensureObject": CGIndenter(CGGeneric(ensureObject)).define(),
-                "traceMembers": "\n\n".join(memberTraces),
-                "traceParent": CGIndenter(CGGeneric(traceParent)).define(),
-                "defineMembers": "\n\n".join(memberDefines)
-                })
+        body += "\n\n".join(memberTraces)
+
+        return ClassMethod("TraceDictionary", "void", [
+            Argument("JSTracer*", "trc"),
+        ], body=body)
+
+    def getStructs(self):
+        d = self.dictionary
+        selfName = self.makeClassName(d)
+        members = [ClassMember(self.makeMemberName(m[0].identifier.name),
+                               self.getMemberType(m),
+                               visibility="public") for m in self.memberInfo]
+        ctor = ClassConstructor([], bodyInHeader=True, visibility="public")
+        methods = []
+
+        if self.needToInitIds:
+            methods.append(self.initIdsMethod())
+            members.append(ClassMember("initedIds", "bool", static=True, body="false"))
+            members.extend(
+                ClassMember(self.makeIdName(m.identifier.name), "jsid", static=True, body="JSID_VOID")
+                for m in d.members)
+
+        methods.append(self.initMethod())
+
+        if not self.workers:
+            methods.append(self.initFromJSONMethod())
+
+        methods.append(self.toObjectMethod())
+        methods.append(self.traceDictionaryMethod())
+
+        struct = CGClass(selfName,
+            bases=[ClassBase(self.base())],
+            members=members,
+            constructors=[ctor],
+            methods=methods,
+            isStruct=True,
+            disallowCopyConstruction=True)
+
+
+        initializerCtor = ClassConstructor([],
+            bodyInHeader=True,
+            visibility="public",
+            body=(
+                "// Safe to pass a null context if we pass a null value\n"
+                "Init(nullptr, JS::NullHandleValue);"))
+        initializerStruct = CGClass(selfName + "Initializer",
+            bases=[ClassBase(selfName)],
+            constructors=[initializerCtor],
+            isStruct=True)
+
+        return CGList([struct, initializerStruct])
 
     def deps(self):
         return self.dictionary.getDeps()
 
     @staticmethod
     def makeDictionaryName(dictionary, workers):
         suffix = "Workers" if workers else ""
         return dictionary.identifier.name + suffix
@@ -7838,17 +7880,17 @@ class CGDictionary(CGThing):
             if type.nullable():
                 trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
         else:
             assert 0 # unknown type
 
         if not member.defaultValue:
             trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc)
 
-        return trace
+        return trace.define()
 
     @staticmethod
     def makeIdName(name):
         return name + "_id"
 
     @staticmethod
     def getDictionaryDependenciesFromType(type):
         if type.isDictionary():
copy from content/base/public/nsIDOMDataChannel.idl
copy to dom/webidl/DataChannel.webidl
--- a/content/base/public/nsIDOMDataChannel.idl
+++ b/dom/webidl/DataChannel.webidl
@@ -1,38 +1,50 @@
-#include "domstubs.idl"
-
-#include "nsIDOMEventTarget.idl"
+/* 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/. */
 
-interface nsIVariant;
+enum RTCDataChannelState {
+  "connecting",
+  "open",
+  "closing",
+  "closed"
+};
 
-[scriptable, builtinclass, uuid(1aed816d-1156-414e-8fe2-f01daa6021f0)]
-interface nsIDOMDataChannel : nsIDOMEventTarget
+enum RTCDataChannelType {
+  "arraybuffer",
+  "blob"
+};
+
+// XXX This interface is called RTCDataChannel in the spec.
+interface DataChannel : EventTarget
 {
   readonly attribute DOMString label;
-  readonly attribute DOMString protocol;
   readonly attribute boolean reliable;
-  readonly attribute boolean ordered;
-
-  readonly attribute DOMString readyState;
+  readonly attribute RTCDataChannelState readyState;
   readonly attribute unsigned long bufferedAmount;
-
-  readonly attribute unsigned short stream;
-
-  [implicit_jscontext] attribute jsval onopen;
-  [implicit_jscontext] attribute jsval onerror;
-  [implicit_jscontext] attribute jsval onclose;
-  [implicit_jscontext] attribute jsval onmessage;
+  [SetterThrows]
+  attribute EventHandler onopen;
+  [SetterThrows]
+  attribute EventHandler onerror;
+  [SetterThrows]
+  attribute EventHandler onclose;
+  void close();
+  [SetterThrows]
+  attribute EventHandler onmessage;
+  attribute RTCDataChannelType binaryType;
+  [Throws]
+  void send(DOMString data);
+  [Throws]
+  void send(Blob data);
+  [Throws]
+  void send(ArrayBuffer data);
+  [Throws]
+  void send(ArrayBufferView data);
+};
 
-  attribute DOMString binaryType;
-
-  void close();
-
-  /**
-   * Transmits data to other end of the connection.
-   * @param data The data to be transmitted.  Arraybuffers and Blobs are sent as
-   * binary data.  Strings are sent as UTF-8 text data.  Other types are
-   * converted to a String and sent as a String.
-   * @return if the connection is still established and the data was queued or
-   *         sent successfully.
-   */
-  void send(in nsIVariant data);
+// Mozilla extensions.
+partial interface DataChannel
+{
+  readonly attribute DOMString protocol;
+  readonly attribute boolean ordered;
+  readonly attribute unsigned short stream;
 };
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -354,16 +354,17 @@ endif
 ifdef MOZ_WEBGL
 webidl_files += \
   WebGLRenderingContext.webidl \
   $(NULL)
 endif
 
 ifdef MOZ_WEBRTC
 webidl_files += \
+  DataChannel.webidl \
   MediaStreamList.webidl \
   $(NULL)
 endif
 
 ifdef MOZ_WEBSPEECH
 webidl_files += \
   SpeechGrammar.webidl \
   SpeechGrammarList.webidl \
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -28,17 +28,17 @@
 #include "nsIConsoleService.h"
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
 
 #include "runnable_utils.h"
 #include "PeerConnectionCtx.h"
 #include "PeerConnectionImpl.h"
 #include "nsPIDOMWindow.h"
-#include "nsDOMDataChannel.h"
+#include "nsDOMDataChannelDeclarations.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsIDocument.h"
 #include "nsIScriptError.h"
 #include "nsPrintfCString.h"
 #include "nsURLHelper.h"
--- a/netwerk/sctp/datachannel/DataChannel.h
+++ b/netwerk/sctp/datachannel/DataChannel.h
@@ -405,17 +405,17 @@ public:
         return CONNECTING;
       return mState;
     }
 
   void SetReadyState(uint16_t aState) { mState = aState; }
 
   void GetLabel(nsAString& aLabel) { CopyUTF8toUTF16(mLabel, aLabel); }
   void GetProtocol(nsAString& aProtocol) { CopyUTF8toUTF16(mProtocol, aProtocol); }
-  void GetStream(uint16_t *aStream) { *aStream = mStream; }
+  uint16_t GetStream() { return mStream; }
 
   void AppReady();
 
   void SendOrQueue(DataChannelOnMessageAvailable *aMessage);
 
 protected:
   Mutex mListenerLock; // protects mListener and mContext
   DataChannelListener *mListener;