Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 20 May 2013 08:02:31 -0400
changeset 139512 a914d2d6dfdce6a044f1a2abe6e67bc31a42aaf7
parent 139511 d48112a83fb29975e3620ef338dd1edfcd02306c (current diff)
parent 139488 ca7f8131a8d4ee0de01ee7d513a3543815846997 (diff)
child 139513 d6ee8d80627cb264fed411cc56ef3ba7e1d88a30
push id3911
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 20:17:26 +0000
treeherdermozilla-aurora@7e26ca8db92b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.0a1
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;