merge mozilla-inbound to mozilla-central a=merge FIREFOX_AURORA_51_BASE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 19 Sep 2016 12:14:36 +0200
changeset 314369 fc69febcbf6c0dcc4b3dfc7a346d8d348798a65f
parent 314358 1b4b21f3c1bdc60363b9719a03d2a5f472a2c9b3 (current diff)
parent 314368 672663f1a298ef69d17742a8da54c44f3b788aca (diff)
child 314370 4aa88f11093e005222c2b57a1b82bad84fcd1b95
child 314376 2b2ccdb21d028b7e5ad9e7011fcbf52ea52e2b35
child 314387 4193ef8a247ed85cbb1c9c24f7ba84c40222143b
child 314400 6fef7e47113c21ad3447db194f921bf2b6f97421
push idunknown
push userunknown
push dateunknown
reviewersmerge
milestone51.0a1
merge mozilla-inbound to mozilla-central a=merge
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -2226,17 +2226,16 @@ GK_ATOM(scrollbar_start_forward, "scroll
 GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
 GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
 GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
 GK_ATOM(images_in_menus, "images-in-menus")
 GK_ATOM(images_in_buttons, "images-in-buttons")
 GK_ATOM(overlay_scrollbars, "overlay-scrollbars")
 GK_ATOM(windows_default_theme, "windows-default-theme")
 GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
-GK_ATOM(mac_lion_theme, "mac-lion-theme")
 GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme")
 GK_ATOM(windows_compositor, "windows-compositor")
 GK_ATOM(windows_glass, "windows-glass")
 GK_ATOM(touch_enabled, "touch-enabled")
 GK_ATOM(menubar_drag, "menubar-drag")
 GK_ATOM(swipe_animation_enabled, "swipe-animation-enabled")
 GK_ATOM(physical_home_button, "physical-home-button")
 
@@ -2258,17 +2257,16 @@ GK_ATOM(_moz_scrollbar_start_forward, "-
 GK_ATOM(_moz_scrollbar_end_backward, "-moz-scrollbar-end-backward")
 GK_ATOM(_moz_scrollbar_end_forward, "-moz-scrollbar-end-forward")
 GK_ATOM(_moz_scrollbar_thumb_proportional, "-moz-scrollbar-thumb-proportional")
 GK_ATOM(_moz_images_in_menus, "-moz-images-in-menus")
 GK_ATOM(_moz_images_in_buttons, "-moz-images-in-buttons")
 GK_ATOM(_moz_overlay_scrollbars, "-moz-overlay-scrollbars")
 GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
 GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
-GK_ATOM(_moz_mac_lion_theme, "-moz-mac-lion-theme")
 GK_ATOM(_moz_mac_yosemite_theme, "-moz-mac-yosemite-theme")
 GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
 GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
 GK_ATOM(_moz_windows_glass, "-moz-windows-glass")
 GK_ATOM(_moz_windows_theme, "-moz-windows-theme")
 GK_ATOM(_moz_os_version, "-moz-os-version")
 GK_ATOM(_moz_touch_enabled, "-moz-touch-enabled")
 GK_ATOM(_moz_menubar_drag, "-moz-menubar-drag")
--- a/dom/media/AudioStream.h
+++ b/dom/media/AudioStream.h
@@ -216,17 +216,16 @@ public:
   int64_t GetPosition();
 
   // Return the position, measured in audio frames played since the stream
   // was opened, of the audio hardware.  Thread-safe.
   int64_t GetPositionInFrames();
 
   static uint32_t GetPreferredRate()
   {
-    CubebUtils::InitPreferredSampleRate();
     return CubebUtils::PreferredSampleRate();
   }
 
   uint32_t GetOutChannels() { return mOutChannels; }
 
   // Set playback rate as a multiple of the intrinsic playback rate. This is to
   // be called only with aPlaybackRate > 0.0.
   nsresult SetPlaybackRate(double aPlaybackRate);
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -25,17 +25,16 @@ namespace mozilla {
 
 namespace {
 
 // This mutex protects the variables below.
 StaticMutex sMutex;
 enum class CubebState {
   Uninitialized = 0,
   Initialized,
-  Error,
   Shutdown
 } sCubebState = CubebState::Uninitialized;
 cubeb* sCubebContext;
 double sVolumeScale;
 uint32_t sCubebLatency;
 bool sCubebLatencyPrefSet;
 bool sAudioStreamInitEverSucceeded = false;
 StaticAutoPtr<char> sBrandName;
@@ -124,29 +123,42 @@ double GetVolumeScale()
 }
 
 cubeb* GetCubebContext()
 {
   StaticMutexAutoLock lock(sMutex);
   return GetCubebContextUnlocked();
 }
 
-void InitPreferredSampleRate()
+bool InitPreferredSampleRate()
 {
   StaticMutexAutoLock lock(sMutex);
-  if (sPreferredSampleRate == 0) {
-    cubeb* context = GetCubebContextUnlocked();
-    if (context) {
-      if (cubeb_get_preferred_sample_rate(context,
-                                          &sPreferredSampleRate) != CUBEB_OK) {
-        // Query failed, use a sensible default.
-        sPreferredSampleRate = 44100;
-      }
-    }
+  if (sPreferredSampleRate != 0) {
+    return true;
+  }
+  cubeb* context = GetCubebContextUnlocked();
+  if (!context) {
+    return false;
+  }
+  if (cubeb_get_preferred_sample_rate(context,
+                                      &sPreferredSampleRate) != CUBEB_OK) {
+
+    return false;
   }
+  MOZ_ASSERT(sPreferredSampleRate);
+  return true;
+}
+
+uint32_t PreferredSampleRate()
+{
+  if (!InitPreferredSampleRate()) {
+    return 44100;
+  }
+  MOZ_ASSERT(sPreferredSampleRate);
+  return sPreferredSampleRate;
 }
 
 void InitBrandName()
 {
   if (sBrandName) {
     return;
   }
   nsXPIDLString brandName;
@@ -183,17 +195,17 @@ cubeb* GetCubebContextUnlocked()
     InitBrandName();
   } else {
     NS_WARNING_ASSERTION(
       sBrandName, "Did not initialize sbrandName, and not on the main thread?");
   }
 
   int rv = cubeb_init(&sCubebContext, sBrandName);
   NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
-  sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Error;
+  sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
 
   return sCubebContext;
 }
 
 void ReportCubebBackendUsed()
 {
   StaticMutexAutoLock lock(sMutex);
 
@@ -272,23 +284,16 @@ uint32_t MaxNumberOfChannels()
       cubeb_get_max_channel_count(cubebContext,
                                   &maxNumberOfChannels) == CUBEB_OK) {
     return maxNumberOfChannels;
   }
 
   return 0;
 }
 
-uint32_t PreferredSampleRate()
-{
-  MOZ_ASSERT(sPreferredSampleRate,
-             "sPreferredSampleRate has not been initialized!");
-  return sPreferredSampleRate;
-}
-
 #if defined(__ANDROID__) && defined(MOZ_B2G)
 cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
 {
   switch(aChannel) {
     case dom::AudioChannel::Normal:
       /* FALLTHROUGH */
     case dom::AudioChannel::Content:
       return CUBEB_STREAM_TYPE_MUSIC;
--- a/dom/media/CubebUtils.h
+++ b/dom/media/CubebUtils.h
@@ -21,22 +21,17 @@ void InitLibrary();
 
 // Shutdown Audio Library. Some Audio backends require shutting down the
 // library after using it.
 void ShutdownLibrary();
 
 // Returns the maximum number of channels supported by the audio hardware.
 uint32_t MaxNumberOfChannels();
 
-// Queries the samplerate the hardware/mixer runs at, and stores it.
-// Can be called on any thread. When this returns, it is safe to call
-// PreferredSampleRate.
-void InitPreferredSampleRate();
-
-// Get the aforementioned sample rate. Thread safe.
+// Get the sample rate the hardware/mixer runs at. Thread safe.
 uint32_t PreferredSampleRate();
 
 void PrefChanged(const char* aPref, void* aClosure);
 double GetVolumeScale();
 bool GetFirstStream();
 cubeb* GetCubebContext();
 cubeb* GetCubebContextUnlocked();
 void ReportCubebStreamInitFailure(bool aIsFirstStream);
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -3403,18 +3403,16 @@ MediaStreamGraph::GetInstance(MediaStrea
       nsCOMPtr<nsIAsyncShutdownClient> barrier = MediaStreamGraphImpl::GetShutdownBarrier();
       nsresult rv = barrier->
           AddBlocker(gMediaStreamGraphShutdownBlocker,
                      NS_LITERAL_STRING(__FILE__), __LINE__,
                      NS_LITERAL_STRING("MediaStreamGraph shutdown"));
       MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
     }
 
-    CubebUtils::InitPreferredSampleRate();
-
     graph = new MediaStreamGraphImpl(aGraphDriverRequested,
                                      CubebUtils::PreferredSampleRate(),
                                      aChannel);
 
     gGraphs.Put(channel, graph);
 
     STREAM_LOG(LogLevel::Debug,
         ("Starting up MediaStreamGraph %p for channel %s",
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -85,17 +85,16 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 static float GetSampleRateForAudioContext(bool aIsOffline, float aSampleRate)
 {
   if (aIsOffline) {
     return aSampleRate;
   } else {
-    CubebUtils::InitPreferredSampleRate();
     return static_cast<float>(CubebUtils::PreferredSampleRate());
   }
 }
 
 AudioContext::AudioContext(nsPIDOMWindowInner* aWindow,
                            bool aIsOffline,
                            AudioChannel aChannel,
                            uint32_t aNumberOfChannels,
--- a/dom/presentation/PresentationConnection.cpp
+++ b/dom/presentation/PresentationConnection.cpp
@@ -4,16 +4,17 @@
  * 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 "PresentationConnection.h"
 
 #include "ControllerConnectionCollection.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/File.h"
 #include "mozilla/dom/MessageEvent.h"
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/PresentationConnectionClosedEvent.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/DebugOnly.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIPresentationService.h"
@@ -49,16 +50,17 @@ PresentationConnection::PresentationConn
                                                const nsAString& aUrl,
                                                const uint8_t aRole,
                                                PresentationConnectionList* aList)
   : DOMEventTargetHelper(aWindow)
   , mId(aId)
   , mUrl(aUrl)
   , mState(PresentationConnectionState::Connecting)
   , mOwningConnectionList(aList)
+  , mBinaryType(PresentationConnectionBinaryType::Arraybuffer)
 {
   MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
              aRole == nsIPresentationService::ROLE_RECEIVER);
   mRole = aRole;
 }
 
 /* virtual */ PresentationConnection::~PresentationConnection()
 {
@@ -164,36 +166,142 @@ PresentationConnection::GetUrl(nsAString
 }
 
 PresentationConnectionState
 PresentationConnection::State() const
 {
   return mState;
 }
 
+PresentationConnectionBinaryType
+PresentationConnection::BinaryType() const
+{
+  return mBinaryType;
+}
+
+void
+PresentationConnection::SetBinaryType(PresentationConnectionBinaryType aType)
+{
+  mBinaryType = aType;
+}
+
 void
 PresentationConnection::Send(const nsAString& aData,
                              ErrorResult& aRv)
 {
   // Sending is not allowed if the session is not connected.
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if(NS_WARN_IF(!service)) {
-    aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send message due to an internal error."));
     return;
   }
 
   nsresult rv = service->SendSessionMessage(mId, mRole, aData);
   if(NS_WARN_IF(NS_FAILED(rv))) {
-    aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
+    const uint32_t kMaxMessageLength = 256;
+    nsAutoString data(Substring(aData, 0, kMaxMessageLength));
+
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send message: \"") + data +
+      NS_LITERAL_STRING("\""));
+  }
+}
+
+void
+PresentationConnection::Send(Blob& aData,
+                             ErrorResult& aRv)
+{
+  if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  nsCOMPtr<nsIPresentationService> service =
+    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+  if(NS_WARN_IF(!service)) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send message due to an internal error."));
+    return;
+  }
+
+  nsresult rv = service->SendSessionBlob(mId, mRole, &aData);
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send binary message for Blob message."));
+  }
+}
+
+void
+PresentationConnection::Send(const ArrayBuffer& aData,
+                             ErrorResult& aRv)
+{
+  if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  nsCOMPtr<nsIPresentationService> service =
+    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+  if(NS_WARN_IF(!service)) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send message due to an internal error."));
+    return;
+  }
+
+  aData.ComputeLengthAndData();
+
+  static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
+
+  uint32_t length = aData.Length();
+  char* data = reinterpret_cast<char*>(aData.Data());
+  nsDependentCSubstring msgString(data, length);
+
+  nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send binary message for ArrayBuffer message."));
+  }
+}
+
+void
+PresentationConnection::Send(const ArrayBufferView& aData,
+                             ErrorResult& aRv)
+{
+  if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  nsCOMPtr<nsIPresentationService> service =
+    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+  if(NS_WARN_IF(!service)) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send message due to an internal error."));
+    return;
+  }
+
+  aData.ComputeLengthAndData();
+
+  static_assert(sizeof(*aData.Data()) == 1, "byte-sized data required");
+
+  uint32_t length = aData.Length();
+  char* data = reinterpret_cast<char*>(aData.Data());
+  nsDependentCSubstring msgString(data, length);
+
+  nsresult rv = service->SendSessionBinaryMsg(mId, mRole, msgString);
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to send binary message for ArrayBufferView message."));
   }
 }
 
 void
 PresentationConnection::Close(ErrorResult& aRv)
 {
   // It only works when the state is CONNECTED or CONNECTING.
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
@@ -347,41 +455,75 @@ PresentationConnection::ProcessStateChan
     default:
       MOZ_CRASH("Unknown presentation session state.");
       return NS_ERROR_INVALID_ARG;
   }
 }
 
 NS_IMETHODIMP
 PresentationConnection::NotifyMessage(const nsAString& aSessionId,
-                                      const nsACString& aData)
+                                      const nsACString& aData,
+                                      bool aIsBinary)
 {
   PRES_DEBUG("connection %s:id[%s], data[%s], role[%d]\n", __func__,
              NS_ConvertUTF16toUTF8(aSessionId).get(),
              nsPromiseFlatCString(aData).get(), mRole);
 
   if (!aSessionId.Equals(mId)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   // No message should be expected when the session is not connected.
   if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
+  if (NS_WARN_IF(NS_FAILED(DoReceiveMessage(aData, aIsBinary)))) {
+    AsyncCloseConnectionWithErrorMsg(
+      NS_LITERAL_STRING("Unable to receive a message."));
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+PresentationConnection::DoReceiveMessage(const nsACString& aData, bool aIsBinary)
+{
   // Transform the data.
   AutoJSAPI jsapi;
   if (!jsapi.Init(GetOwner())) {
     return NS_ERROR_FAILURE;
   }
   JSContext* cx = jsapi.cx();
   JS::Rooted<JS::Value> jsData(cx);
-  NS_ConvertUTF8toUTF16 utf16Data(aData);
-  if(NS_WARN_IF(!ToJSValue(cx, utf16Data, &jsData))) {
-    return NS_ERROR_FAILURE;
+
+  nsresult rv;
+  if (aIsBinary) {
+    if (mBinaryType == PresentationConnectionBinaryType::Blob) {
+      rv = nsContentUtils::CreateBlobBuffer(cx, GetOwner(), aData, &jsData);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    } else if (mBinaryType == PresentationConnectionBinaryType::Arraybuffer) {
+      JS::Rooted<JSObject*> arrayBuf(cx);
+      rv = nsContentUtils::CreateArrayBuffer(cx, aData, arrayBuf.address());
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      jsData.setObject(*arrayBuf);
+    } else {
+      NS_RUNTIMEABORT("Unknown binary type!");
+      return NS_ERROR_UNEXPECTED;
+    }
+  } else {
+    NS_ConvertUTF8toUTF16 utf16Data(aData);
+    if(NS_WARN_IF(!ToJSValue(cx, utf16Data, &jsData))) {
+      return NS_ERROR_FAILURE;
+    }
   }
 
   return DispatchMessageEvent(jsData);
 }
 
 NS_IMETHODIMP
 PresentationConnection::NotifyReplaced()
 {
@@ -391,33 +533,39 @@ PresentationConnection::NotifyReplaced()
   return NotifyStateChange(mId,
                            nsIPresentationSessionListener::STATE_CLOSED,
                            NS_OK);
 }
 
 nsresult
 PresentationConnection::DispatchConnectionClosedEvent(
   PresentationConnectionClosedReason aReason,
-  const nsAString& aMessage)
+  const nsAString& aMessage,
+  bool aDispatchNow)
 {
   if (mState != PresentationConnectionState::Closed) {
     MOZ_ASSERT(false, "The connection state should be closed.");
     return NS_ERROR_FAILURE;
   }
 
   PresentationConnectionClosedEventInit init;
   init.mReason = aReason;
   init.mMessage = aMessage;
 
   RefPtr<PresentationConnectionClosedEvent> closedEvent =
     PresentationConnectionClosedEvent::Constructor(this,
                                                    NS_LITERAL_STRING("close"),
                                                    init);
   closedEvent->SetTrusted(true);
 
+  if (aDispatchNow) {
+    bool ignore;
+    return DOMEventTargetHelper::DispatchEvent(closedEvent, &ignore);
+  }
+
   RefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(this, static_cast<Event*>(closedEvent));
   return asyncDispatcher->PostDOMEvent();
 }
 
 nsresult
 PresentationConnection::DispatchMessageEvent(JS::Handle<JS::Value> aData)
 {
@@ -574,8 +722,44 @@ PresentationConnection::RemoveFromLoadGr
   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
   if (loadGroup) {
     mWeakLoadGroup = nullptr;
     return loadGroup->RemoveRequest(this, nullptr, NS_OK);
   }
 
   return NS_OK;
 }
+
+void
+PresentationConnection::AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage)
+{
+  if (mState == PresentationConnectionState::Terminated) {
+    return;
+  }
+
+  nsString message = nsString(aMessage);
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction([this, message]() -> void {
+      // Set |mState| to |PresentationConnectionState::Closed| here to avoid
+      // calling |ProcessStateChanged|.
+      mState = PresentationConnectionState::Closed;
+
+      // Make sure dispatching the event and closing the connection are invoked
+      // at the same time by setting |aDispatchNow| to true.
+      Unused << NS_WARN_IF(NS_FAILED(
+        DispatchConnectionClosedEvent(PresentationConnectionClosedReason::Error,
+                                      message,
+                                      true)));
+
+      nsCOMPtr<nsIPresentationService> service =
+        do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+      if(NS_WARN_IF(!service)) {
+        return;
+      }
+
+      Unused << NS_WARN_IF(NS_FAILED(
+        service->CloseSession(mId,
+                              mRole,
+                              nsIPresentationService::CLOSED_REASON_ERROR)));
+    });
+
+  Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)));
+}
--- a/dom/presentation/PresentationConnection.h
+++ b/dom/presentation/PresentationConnection.h
@@ -3,26 +3,28 @@
 /* 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 mozilla_dom_PresentationConnection_h
 #define mozilla_dom_PresentationConnection_h
 
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/TypedArray.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/dom/PresentationConnectionBinding.h"
 #include "mozilla/dom/PresentationConnectionClosedEventBinding.h"
 #include "nsIPresentationListener.h"
 #include "nsIRequest.h"
 #include "nsWeakReference.h"
 
 namespace mozilla {
 namespace dom {
 
+class Blob;
 class PresentationConnectionList;
 
 class PresentationConnection final : public DOMEventTargetHelper
                                    , public nsIPresentationSessionListener
                                    , public nsIRequest
                                    , public SupportsWeakPtr<PresentationConnection>
 {
 public:
@@ -47,19 +49,32 @@ public:
 
   // WebIDL (public APIs)
   void GetId(nsAString& aId) const;
 
   void GetUrl(nsAString& aUrl) const;
 
   PresentationConnectionState State() const;
 
+  PresentationConnectionBinaryType BinaryType() const;
+
+  void SetBinaryType(PresentationConnectionBinaryType aType);
+
   void Send(const nsAString& aData,
             ErrorResult& aRv);
 
+  void Send(Blob& aData,
+            ErrorResult& aRv);
+
+  void Send(const ArrayBuffer& aData,
+            ErrorResult& aRv);
+
+  void Send(const ArrayBufferView& aData,
+            ErrorResult& aRv);
+
   void Close(ErrorResult& aRv);
 
   void Terminate(ErrorResult& aRv);
 
   bool
   Equals(uint64_t aWindowId, const nsAString& aId);
 
   IMPL_EVENT_HANDLER(connect);
@@ -78,30 +93,36 @@ private:
 
   bool Init();
 
   void Shutdown();
 
   nsresult ProcessStateChanged(nsresult aReason);
 
   nsresult DispatchConnectionClosedEvent(PresentationConnectionClosedReason aReason,
-                                         const nsAString& aMessage);
+                                         const nsAString& aMessage,
+                                         bool aDispatchNow = false);
 
   nsresult DispatchMessageEvent(JS::Handle<JS::Value> aData);
 
   nsresult ProcessConnectionWentAway();
 
   nsresult AddIntoLoadGroup();
 
   nsresult RemoveFromLoadGroup();
 
+  void AsyncCloseConnectionWithErrorMsg(const nsAString& aMessage);
+
+  nsresult DoReceiveMessage(const nsACString& aData, bool aIsBinary);
+
   nsString mId;
   nsString mUrl;
   uint8_t mRole;
   PresentationConnectionState mState;
   RefPtr<PresentationConnectionList> mOwningConnectionList;
-  nsWeakPtr mWeakLoadGroup;;
+  nsWeakPtr mWeakLoadGroup;
+  PresentationConnectionBinaryType mBinaryType;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PresentationConnection_h
--- a/dom/presentation/PresentationDataChannelSessionTransport.js
+++ b/dom/presentation/PresentationDataChannelSessionTransport.js
@@ -22,17 +22,17 @@ const PRESENTATIONTRANSPORTBUILDER_CONTR
 
 function PresentationDataChannelDescription(aDataChannelSDP) {
   this._dataChannelSDP = JSON.stringify(aDataChannelSDP);
 }
 
 PresentationDataChannelDescription.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
   get type() {
-    return nsIPresentationChannelDescription.TYPE_DATACHANNEL;
+    return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
   },
   get tcpAddress() {
     return null;
   },
   get tcpPort() {
     return null;
   },
   get dataChannelSDP() {
@@ -89,16 +89,18 @@ PresentationTransportBuilder.prototype =
       case Ci.nsIPresentationService.ROLE_CONTROLLER:
         this._dataChannel = this._peerConnection.createDataChannel("presentationAPI");
         this._setDataChannel();
         break;
 
       case Ci.nsIPresentationService.ROLE_RECEIVER:
         this._peerConnection.ondatachannel = aEvent => {
           this._dataChannel = aEvent.channel;
+          // Ensure the binaryType of dataChannel is blob.
+          this._dataChannel.binaryType = "blob";
           this._setDataChannel();
         }
         break;
       default:
        throw Cr.NS_ERROR_ILLEGAL_VALUE;
     }
 
     // TODO bug 1228235 we should have a way to let device providers customize
@@ -129,17 +131,17 @@ PresentationTransportBuilder.prototype =
 
   _setDataChannel: function() {
     this._dataChannel.onopen = () => {
       log("data channel is open, notify the listener, role " + this._role);
 
       // Handoff the ownership of _peerConnection and _dataChannel to
       // _sessionTransport
       this._sessionTransport = new PresentationTransport();
-      this._sessionTransport.init(this._peerConnection, this._dataChannel);
+      this._sessionTransport.init(this._peerConnection, this._dataChannel, this._window);
       this._peerConnection = this._dataChannel = null;
 
       this._listener.onSessionTransport(this._sessionTransport);
       this._sessionTransport.callback.notifyTransportReady();
 
       this._cleanup(Cr.NS_OK);
     };
 
@@ -238,21 +240,22 @@ function PresentationTransport() {
   this._closeReason = Cr.NS_OK;
 }
 
 PresentationTransport.prototype = {
   classID: PRESENTATIONTRANSPORT_CID,
   contractID: PRESENTATIONTRANSPORT_CONTRACTID,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport]),
 
-  init: function(aPeerConnection, aDataChannel) {
+  init: function(aPeerConnection, aDataChannel, aWindow) {
     log("initWithDataChannel");
     this._enableDataNotification = false;
     this._dataChannel = aDataChannel;
     this._peerConnection = aPeerConnection;
+    this._window = aWindow;
 
     this._dataChannel.onopen = () => {
       log("data channel reopen. Should never touch here");
     };
 
     this._dataChannel.onclose = () => {
       log("data channel onclose");
       if (this._callback) {
@@ -264,17 +267,17 @@ PresentationTransport.prototype = {
     this._dataChannel.onmessage = aEvent => {
       log("data channel onmessage " + aEvent.data);
 
       if (!this._enableDataNotification || !this._callback) {
         log("queue message");
         this._messageQueue.push(aEvent.data);
         return;
       }
-      this._callback.notifyData(aEvent.data);
+      this._doNotifyData(aEvent.data);
     };
 
     this._dataChannel.onerror = aError => {
       log("data channel onerror " + aError.name + ":" + aError.message);
       if (this._callback) {
         this._callback.notifyTransportClosed(Cr.NS_ERROR_FAILURE);
       }
       this._cleanup();
@@ -294,29 +297,46 @@ PresentationTransport.prototype = {
     this._callback = aCallback;
   },
 
   send: function(aData) {
     log("send " + aData);
     this._dataChannel.send(aData);
   },
 
+  sendBinaryMsg: function(aData) {
+    log("sendBinaryMsg");
+
+    let array = new Uint8Array(aData.length);
+    for (let i = 0; i < aData.length; i++) {
+      array[i] = aData.charCodeAt(i);
+    }
+
+    this._dataChannel.send(array);
+  },
+
+  sendBlob: function(aBlob) {
+    log("sendBlob");
+
+    this._dataChannel.send(aBlob);
+  },
+
   enableDataNotification: function() {
     log("enableDataNotification");
     if (this._enableDataNotification) {
       return;
     }
 
     if (!this._callback) {
       throw NS_ERROR_NOT_AVAILABLE;
     }
 
     this._enableDataNotification = true;
 
-    this._messageQueue.forEach(aData => this._callback.notifyData(aData));
+    this._messageQueue.forEach(aData => this._doNotifyData(aData));
     this._messageQueue = [];
   },
 
   close: function(aReason) {
     this._closeReason = aReason;
 
     this._dataChannel.close();
   },
@@ -325,13 +345,30 @@ PresentationTransport.prototype = {
     this._dataChannel = null;
 
     if (this._peerConnection) {
       this._peerConnection.close();
       this._peerConnection = null;
     }
     this._callback = null;
     this._messageQueue = [];
+    this._window = null;
+  },
+
+  _doNotifyData: function(aData) {
+    if (!this._callback) {
+      throw NS_ERROR_NOT_AVAILABLE;
+    }
+
+    if (aData instanceof this._window.Blob) {
+      let reader = new this._window.FileReader();
+      reader.addEventListener("load", (aEvent) => {
+        this._callback.notifyData(aEvent.target.result, true);
+      });
+      reader.readAsBinaryString(aData);
+    } else {
+      this._callback.notifyData(aData, false);
+    }
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationTransportBuilder,
                                                      PresentationTransport]);
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -772,16 +772,54 @@ PresentationService::SendSessionMessage(
   if (NS_WARN_IF(!info)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return info->Send(aData);
 }
 
 NS_IMETHODIMP
+PresentationService::SendSessionBinaryMsg(const nsAString& aSessionId,
+                                          uint8_t aRole,
+                                          const nsACString &aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aData.IsEmpty());
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
+
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
+  if (NS_WARN_IF(!info)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return info->SendBinaryMsg(aData);
+}
+
+NS_IMETHODIMP
+PresentationService::SendSessionBlob(const nsAString& aSessionId,
+                                     uint8_t aRole,
+                                     nsIDOMBlob* aBlob)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
+  MOZ_ASSERT(aBlob);
+
+  RefPtr<PresentationSessionInfo> info = GetSessionInfo(aSessionId, aRole);
+  if (NS_WARN_IF(!info)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return info->SendBlob(aBlob);
+}
+
+NS_IMETHODIMP
 PresentationService::CloseSession(const nsAString& aSessionId,
                                   uint8_t aRole,
                                   uint8_t aClosedReason)
 {
   PRES_DEBUG("%s:id[%s], reason[%x], role[%d]\n", __func__,
              NS_ConvertUTF16toUTF8(aSessionId).get(), aClosedReason, aRole);
 
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/presentation/PresentationSessionInfo.cpp
+++ b/dom/presentation/PresentationSessionInfo.cpp
@@ -280,16 +280,44 @@ PresentationSessionInfo::Send(const nsAS
   if (NS_WARN_IF(!mTransport)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return mTransport->Send(aData);
 }
 
 nsresult
+PresentationSessionInfo::SendBinaryMsg(const nsACString& aData)
+{
+  if (NS_WARN_IF(!IsSessionReady())) {
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  if (NS_WARN_IF(!mTransport)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return mTransport->SendBinaryMsg(aData);
+}
+
+nsresult
+PresentationSessionInfo::SendBlob(nsIDOMBlob* aBlob)
+{
+  if (NS_WARN_IF(!IsSessionReady())) {
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  if (NS_WARN_IF(!mTransport)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return mTransport->SendBlob(aBlob);
+}
+
+nsresult
 PresentationSessionInfo::Close(nsresult aReason,
                                uint32_t aState)
 {
   if (NS_WARN_IF(!IsSessionReady())) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   // Do nothing if session is already terminated.
@@ -470,29 +498,29 @@ PresentationSessionInfo::NotifyTransport
     // Directly untrack the session info from the service.
     return UntrackFromService();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PresentationSessionInfo::NotifyData(const nsACString& aData)
+PresentationSessionInfo::NotifyData(const nsACString& aData, bool aIsBinary)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (NS_WARN_IF(!IsSessionReady())) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   if (NS_WARN_IF(!mListener)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  return mListener->NotifyMessage(mSessionId, aData);
+  return mListener->NotifyMessage(mSessionId, aData, aIsBinary);
 }
 
 // nsIPresentationSessionTransportBuilderListener
 NS_IMETHODIMP
 PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* transport)
 {
   PRES_DEBUG("%s:id[%s], role[%d], state[%d]\n", __func__,
              NS_ConvertUTF16toUTF8(mSessionId).get(), mRole, mState);
--- a/dom/presentation/PresentationSessionInfo.h
+++ b/dom/presentation/PresentationSessionInfo.h
@@ -94,16 +94,20 @@ public:
     mControlChannel = aControlChannel;
     if (mControlChannel) {
       mControlChannel->SetListener(this);
     }
   }
 
   nsresult Send(const nsAString& aData);
 
+  nsresult SendBinaryMsg(const nsACString& aData);
+
+  nsresult SendBlob(nsIDOMBlob* aBlob);
+
   nsresult Close(nsresult aReason,
                  uint32_t aState);
 
   nsresult OnTerminate(nsIPresentationControlChannel* aControlChannel);
 
   nsresult ReplyError(nsresult aReason);
 
   virtual bool IsAccessible(base::ProcessId aProcessId);
--- a/dom/presentation/PresentationTCPSessionTransport.cpp
+++ b/dom/presentation/PresentationTCPSessionTransport.cpp
@@ -413,16 +413,28 @@ PresentationTCPSessionTransport::Send(co
   mMultiplexStream->AppendStream(stream);
 
   EnsureCopying();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+PresentationTCPSessionTransport::SendBinaryMsg(const nsACString& aData)
+{
+  return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+}
+
+NS_IMETHODIMP
+PresentationTCPSessionTransport::SendBlob(nsIDOMBlob* aBlob)
+{
+  return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+}
+
+NS_IMETHODIMP
 PresentationTCPSessionTransport::Close(nsresult aReason)
 {
   PRES_DEBUG("%s:reason[%x]\n", __func__, aReason);
 
   if (mReadyState == ReadyState::CLOSED || mReadyState == ReadyState::CLOSING) {
     return NS_OK;
   }
 
@@ -568,10 +580,10 @@ PresentationTCPSessionTransport::OnDataA
 
   nsCString data;
   nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // Pass the incoming data to the listener.
-  return mCallback->NotifyData(data);
+  return mCallback->NotifyData(data, false);
 }
--- a/dom/presentation/interfaces/nsIPresentationListener.idl
+++ b/dom/presentation/interfaces/nsIPresentationListener.idl
@@ -27,17 +27,18 @@ interface nsIPresentationSessionListener
   void notifyStateChange(in DOMString sessionId,
                          in unsigned short state,
                          in nsresult reason);
 
   /*
    * Called when receive messages.
    */
   void notifyMessage(in DOMString sessionId,
-                     in ACString data);
+                     in ACString data,
+                     in boolean isBinary);
 
   /*
    * Called when this listener is replaced by another one.
    */
   void notifyReplaced();
 };
 
 [scriptable, uuid(27f101d7-9ed1-429e-b4f8-43b00e8e111c)]
--- a/dom/presentation/interfaces/nsIPresentationService.idl
+++ b/dom/presentation/interfaces/nsIPresentationService.idl
@@ -1,14 +1,15 @@
 /* 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 "nsISupports.idl"
 
+interface nsIDOMBlob;
 interface nsIDOMEventTarget;
 interface nsIInputStream;
 interface nsIPresentationAvailabilityListener;
 interface nsIPresentationRespondingListener;
 interface nsIPresentationSessionListener;
 interface nsIPresentationTransportBuilderConstructor;
 
 %{C++
@@ -91,16 +92,38 @@ interface nsIPresentationService : nsISu
    * @param role: Identify the function called by controller or receiver.
    * @param data: the message being sent out.
    */
   void sendSessionMessage(in DOMString sessionId,
 							            in uint8_t role,
                           in DOMString data);
 
   /*
+   * Send the binary message to the session.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
+   * @param data: the message being sent out.
+   */
+  void sendSessionBinaryMsg(in DOMString sessionId,
+                            in uint8_t role,
+                            in ACString data);
+
+  /*
+   * Send the blob to the session.
+   *
+   * @param sessionId: An ID to identify presentation session.
+   * @param role: Identify the function called by controller or receiver.
+   * @param blob: The input blob to be sent.
+   */
+  void sendSessionBlob(in DOMString sessionId,
+                       in uint8_t role,
+                       in nsIDOMBlob blob);
+
+  /*
    * Close the session.
    *
    * @param sessionId: An ID to identify presentation session.
    * @param role: Identify the function called by controller or receiver.
    */
   void closeSession(in DOMString sessionId,
                     in uint8_t role,
                     in uint8_t closedReason);
--- a/dom/presentation/interfaces/nsIPresentationSessionTransport.idl
+++ b/dom/presentation/interfaces/nsIPresentationSessionTransport.idl
@@ -1,31 +1,32 @@
 /* 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 "nsISupports.idl"
 
+interface nsIDOMBlob;
 interface nsIInputStream;
 interface nsINetAddr;
 
 %{C++
 #define PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID \
   "@mozilla.org/presentation/presentationtcpsessiontransport;1"
 %}
 
 /*
  * The callback for session transport events.
  */
 [scriptable, uuid(9f158786-41a6-4a10-b29b-9497f25d4b67)]
 interface nsIPresentationSessionTransportCallback : nsISupports
 {
   void notifyTransportReady();
   void notifyTransportClosed(in nsresult reason);
-  void notifyData(in ACString data);
+  void notifyData(in ACString data, in boolean isBinary);
 };
 
 /*
  * App-to-App transport channel for the presentation session.
  */
 [scriptable, uuid(670b7e1b-65be-42b6-a596-be571907fa18)]
 interface nsIPresentationSessionTransport : nsISupports
 {
@@ -44,13 +45,25 @@ interface nsIPresentationSessionTranspor
 
   /*
    * Send message to the remote endpoint.
    * @param data The message to send.
    */
   void send(in DOMString data);
 
   /*
+   * Send the binary message to the remote endpoint.
+   * @param data: the message being sent out.
+   */
+  void sendBinaryMsg(in ACString data);
+
+  /*
+   * Send the blob to the remote endpoint.
+   * @param blob: The input blob to be sent.
+   */
+  void sendBlob(in nsIDOMBlob blob);
+
+  /*
    * Close this session transport.
    * @param reason The reason for closing this session transport.
    */
   void close(in nsresult reason);
 };
--- a/dom/presentation/ipc/PPresentation.ipdl
+++ b/dom/presentation/ipc/PPresentation.ipdl
@@ -74,17 +74,17 @@ sync protocol PPresentation
   manages PPresentationBuilder;
   manages PPresentationRequest;
 
 child:
   async NotifyAvailableChange(bool aAvailable);
   async NotifySessionStateChange(nsString aSessionId,
                                  uint16_t aState,
                                  nsresult aReason);
-  async NotifyMessage(nsString aSessionId, nsCString aData);
+  async NotifyMessage(nsString aSessionId, nsCString aData, bool aIsBinary);
   async NotifySessionConnect(uint64_t aWindowId, nsString aSessionId);
 
   async PPresentationBuilder(nsString aSessionId, uint8_t aRole);
 
 parent:
   async __delete__();
 
   async RegisterAvailabilityHandler();
--- a/dom/presentation/ipc/PresentationChild.cpp
+++ b/dom/presentation/ipc/PresentationChild.cpp
@@ -107,20 +107,23 @@ PresentationChild::RecvNotifySessionStat
                                                                       aState,
                                                                       aReason)));
   }
   return true;
 }
 
 bool
 PresentationChild::RecvNotifyMessage(const nsString& aSessionId,
-                                     const nsCString& aData)
+                                     const nsCString& aData,
+                                     const bool& aIsBinary)
 {
   if (mService) {
-    Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData)));
+    Unused << NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId,
+                                                           aData,
+                                                           aIsBinary)));
   }
   return true;
 }
 
 bool
 PresentationChild::RecvNotifySessionConnect(const uint64_t& aWindowId,
                                             const nsString& aSessionId)
 {
--- a/dom/presentation/ipc/PresentationChild.h
+++ b/dom/presentation/ipc/PresentationChild.h
@@ -47,17 +47,18 @@ public:
 
   virtual bool
   RecvNotifySessionStateChange(const nsString& aSessionId,
                                const uint16_t& aState,
                                const nsresult& aReason) override;
 
   virtual bool
   RecvNotifyMessage(const nsString& aSessionId,
-                    const nsCString& aData) override;
+                    const nsCString& aData,
+                    const bool& aIsBinary) override;
 
   virtual bool
   RecvNotifySessionConnect(const uint64_t& aWindowId,
                            const nsString& aSessionId) override;
 
 private:
   virtual ~PresentationChild();
 
--- a/dom/presentation/ipc/PresentationContentSessionInfo.cpp
+++ b/dom/presentation/ipc/PresentationContentSessionInfo.cpp
@@ -31,16 +31,36 @@ PresentationContentSessionInfo::Send(con
   if (!mTransport) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return mTransport->Send(aData);
 }
 
 nsresult
+PresentationContentSessionInfo::SendBinaryMsg(const nsACString& aData)
+{
+  if (NS_WARN_IF(!mTransport)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return mTransport->SendBinaryMsg(aData);
+}
+
+nsresult
+PresentationContentSessionInfo::SendBlob(nsIDOMBlob* aBlob)
+{
+  if (NS_WARN_IF(!mTransport)) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  return mTransport->SendBlob(aBlob);
+}
+
+nsresult
 PresentationContentSessionInfo::Close(nsresult aReason)
 {
   if (!mTransport) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   return mTransport->Close(aReason);
 }
@@ -66,23 +86,24 @@ PresentationContentSessionInfo::NotifyTr
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   return static_cast<PresentationIPCService*>(service.get())->
            NotifyTransportClosed(mSessionId, mRole, aReason);
 }
 
 NS_IMETHODIMP
-PresentationContentSessionInfo::NotifyData(const nsACString& aData)
+PresentationContentSessionInfo::NotifyData(const nsACString& aData,
+                                           bool aIsBinary)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIPresentationService> service =
     do_GetService(PRESENTATION_SERVICE_CONTRACTID);
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   return static_cast<PresentationIPCService*>(service.get())->
-           NotifyMessage(mSessionId, aData);
+           NotifyMessage(mSessionId, aData, aIsBinary);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/presentation/ipc/PresentationContentSessionInfo.h
+++ b/dom/presentation/ipc/PresentationContentSessionInfo.h
@@ -37,16 +37,20 @@ public:
                aRole == nsIPresentationService::ROLE_RECEIVER);
     MOZ_ASSERT(aTransport);
   }
 
   nsresult Init();
 
   nsresult Send(const nsAString& aData);
 
+  nsresult SendBinaryMsg(const nsACString& aData);
+
+  nsresult SendBlob(nsIDOMBlob* aBlob);
+
   nsresult Close(nsresult aReason);
 
 private:
   virtual ~PresentationContentSessionInfo() {}
 
   nsString mSessionId;
   uint8_t mRole;
   nsCOMPtr<nsIPresentationSessionTransport> mTransport;
--- a/dom/presentation/ipc/PresentationIPCService.cpp
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -97,16 +97,56 @@ PresentationIPCService::SendSessionMessa
   }
 
   return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId),
                                                         aRole,
                                                         nsString(aData)));
 }
 
 NS_IMETHODIMP
+PresentationIPCService::SendSessionBinaryMsg(const nsAString& aSessionId,
+                                             uint8_t aRole,
+                                             const nsACString &aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aData.IsEmpty());
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
+
+  RefPtr<PresentationContentSessionInfo> info;
+  // data channel session transport is maintained by content process
+  if (mSessionInfos.Get(aSessionId, getter_AddRefs(info))) {
+    return info->SendBinaryMsg(aData);
+  }
+
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::SendSessionBlob(const nsAString& aSessionId,
+                                        uint8_t aRole,
+                                        nsIDOMBlob* aBlob)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aRole == nsIPresentationService::ROLE_CONTROLLER ||
+             aRole == nsIPresentationService::ROLE_RECEIVER);
+  MOZ_ASSERT(aBlob);
+
+  RefPtr<PresentationContentSessionInfo> info;
+  // data channel session transport is maintained by content process
+  if (mSessionInfos.Get(aSessionId, getter_AddRefs(info))) {
+    return info->SendBlob(aBlob);
+  }
+
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
 PresentationIPCService::CloseSession(const nsAString& aSessionId,
                                      uint8_t aRole,
                                      uint8_t aClosedReason)
 {
   MOZ_ASSERT(!aSessionId.IsEmpty());
 
   nsresult rv = SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId),
                                                          aRole,
@@ -327,24 +367,25 @@ PresentationIPCService::NotifySessionSta
   }
 
   return listener->NotifyStateChange(aSessionId, aState, aReason);
 }
 
 // Only used for OOP RTCDataChannel session transport case.
 nsresult
 PresentationIPCService::NotifyMessage(const nsAString& aSessionId,
-                                      const nsACString& aData)
+                                      const nsACString& aData,
+                                      const bool& aIsBinary)
 {
   nsCOMPtr<nsIPresentationSessionListener> listener;
   if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
     return NS_OK;
   }
 
-  return listener->NotifyMessage(aSessionId, aData);
+  return listener->NotifyMessage(aSessionId, aData, aIsBinary);
 }
 
 // Only used for OOP RTCDataChannel session transport case.
 nsresult
 PresentationIPCService::NotifyTransportClosed(const nsAString& aSessionId,
                                               uint8_t aRole,
                                               nsresult aReason)
 {
--- a/dom/presentation/ipc/PresentationIPCService.h
+++ b/dom/presentation/ipc/PresentationIPCService.h
@@ -32,17 +32,18 @@ public:
 
   nsresult NotifyAvailableChange(bool aAvailable);
 
   nsresult NotifySessionStateChange(const nsAString& aSessionId,
                                     uint16_t aState,
                                     nsresult aReason);
 
   nsresult NotifyMessage(const nsAString& aSessionId,
-                         const nsACString& aData);
+                         const nsACString& aData,
+                         const bool& aIsBinary);
 
   nsresult NotifySessionConnect(uint64_t aWindowId,
                                 const nsAString& aSessionId);
 
   void NotifyPresentationChildDestroyed();
 
   nsresult MonitorResponderLoading(const nsAString& aSessionId,
                                    nsIDocShell* aDocShell);
--- a/dom/presentation/ipc/PresentationParent.cpp
+++ b/dom/presentation/ipc/PresentationParent.cpp
@@ -310,20 +310,23 @@ PresentationParent::NotifyReplaced()
 {
   // Do nothing here, since |PresentationIPCService::RegisterSessionListener|
   // already dealt with this in content process.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationParent::NotifyMessage(const nsAString& aSessionId,
-                                  const nsACString& aData)
+                                  const nsACString& aData,
+                                  bool aIsBinary)
 {
   if (NS_WARN_IF(mActorDestroyed ||
-                 !SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
+                 !SendNotifyMessage(nsString(aSessionId),
+                                    nsCString(aData),
+                                    aIsBinary))) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PresentationParent::NotifySessionConnect(uint64_t aWindowId,
                                          const nsAString& aSessionId)
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
@@ -291,17 +291,17 @@ const mockedSessionTransport = {
   close: function(reason) {
     sendAsyncMessage('data-transport-closed', reason);
     this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
   },
   simulateTransportReady: function() {
     this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
   },
   simulateIncomingMessage: function(message) {
-    this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message);
+    this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
   },
   onOffer: function(aOffer) {
   },
   onAnswer: function(aAnswer) {
   }
 };
 
 const mockedNetworkInfo = {
--- a/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript1UA.js
@@ -72,16 +72,28 @@ const mockControlChannelOfSender = {
     mockControlChannelOfReceiver.disconnect();
   },
   terminate: function(presentationId) {
     sendAsyncMessage('sender-terminate');
   },
   reconnect: function(presentationId, url) {
     sendAsyncMessage('start-reconnect', url);
   },
+  sendIceCandidate: function(candidate) {
+    mockControlChannelOfReceiver.notifyIceCandidate(candidate);
+  },
+  notifyIceCandidate: function(candidate) {
+    if (!this._listener) {
+      return;
+    }
+
+    this._listener
+        .QueryInterface(Ci.nsIPresentationControlChannelListener)
+        .onIceCandidate(candidate);
+  },
 };
 
 // control channel of receiver
 const mockControlChannelOfReceiver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]),
   set listener(listener) {
     // PresentationPresentingInfo::SetControlChannel
     if (listener) {
@@ -125,17 +137,29 @@ const mockControlChannelOfReceiver = {
     }
 
     this._listener
         .QueryInterface(Ci.nsIPresentationControlChannelListener)
         .notifyDisconnected(reason);
     sendAsyncMessage('control-channel-receiver-closed', reason);
   },
   terminate: function(presentaionId) {
-  }
+  },
+  sendIceCandidate: function(candidate) {
+    mockControlChannelOfReceiver.notifyIceCandidate(candidate);
+  },
+  notifyIceCandidate: function(candidate) {
+    if (!this._listener) {
+      return;
+    }
+
+    this._listener
+        .QueryInterface(Ci.nsIPresentationControlChannelListener)
+        .onIceCandidate(candidate);
+  },
 };
 
 const mockDevice = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
   id:   'id',
   name: 'name',
   type: 'type',
   establishControlChannel: function(url, presentationId) {
--- a/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js
+++ b/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js
@@ -129,17 +129,17 @@ function loadPrivilegedScriptTest() {
       sendMessage('data-transport-closed', reason);
       this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportClosed(reason);
       this._callback = null;
     },
     simulateTransportReady: function() {
       this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyTransportReady();
     },
     simulateIncomingMessage: function(message) {
-      this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message);
+      this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message, false);
     },
     onOffer: function(aOffer) {
       this._listener.sendAnswer(mockedChannelDescription);
       this._onSessionTransport();
     },
     onAnswer: function(aAnswer) {
       this._onSessionTransport();
     },
--- a/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
+++ b/dom/presentation/tests/mochitest/file_presentation_1ua_receiver.html
@@ -31,16 +31,37 @@ function command(name, data) {
   alert('COMMAND ' + JSON.stringify({name: name, data: data}));
 }
 
 function finish() {
   alert('DONE');
 }
 
 var connection;
+const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
+const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
+const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
+TYPED_DATA_ARRAY.set(DATA_ARRAY);
+
+function is_same_buffer(recv_data, expect_data) {
+  let recv_dataview = new Uint8Array(recv_data);
+  let expected_dataview = new Uint8Array(expect_data);
+
+  if (recv_dataview.length !== expected_dataview.length) {
+    return false;
+  }
+
+  for (let i = 0; i < recv_dataview.length; i++) {
+    if (recv_dataview[i] != expected_dataview[i]) {
+      info('discover byte differenct at ' + i);
+      return false;
+    }
+  }
+  return true;
+}
 
 function testConnectionAvailable() {
   return new Promise(function(aResolve, aReject) {
     info('Receiver: --- testConnectionAvailable ---');
     ok(navigator.presentation, "Receiver: navigator.presentation should be available.");
     ok(navigator.presentation.receiver, "Receiver: navigator.presentation.receiver should be available.");
 
     navigator.presentation.receiver.connectionList
@@ -100,16 +121,29 @@ function testSendMessage() {
       if (message.type === 'message-from-receiver-received') {
         window.removeEventListener('hashchange', hashchangeHandler);
         aResolve();
       }
     });
   });
 }
 
+function testIncomingBlobMessage() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testIncomingBlobMessage ---');
+    connection.send('testIncomingBlobMessage');
+    connection.addEventListener('message', function messageHandler(evt) {
+      connection.removeEventListener('message', messageHandler);
+      let recvData= String.fromCharCode.apply(null, new Uint8Array(evt.data));
+      is(recvData, "Hello World", 'expected same string data');
+      aResolve();
+    });
+  });
+}
+
 function testConnectionClosed() {
   return new Promise(function(aResolve, aReject) {
     info('Receiver: --- testConnectionClosed ---');
     connection.onclose = function() {
       connection.onclose = null;
       is(connection.state, "closed", "Receiver: Connection should be closed.");
       command('forward-command', JSON.stringify({ name: 'receiver-closed' }));
       aResolve();
@@ -125,23 +159,56 @@ function testReconnectConnection() {
     connection.onconnect = function() {
       connection.onconnect = null;
       ok(true, "The connection is reconnected.")
       aResolve();
     };
   });
 }
 
+function testIncomingArrayBuffer() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testIncomingArrayBuffer ---');
+    connection.binaryType = "blob";
+    connection.send('testIncomingArrayBuffer');
+    connection.addEventListener('message', function messageHandler(evt) {
+      connection.removeEventListener('message', messageHandler);
+      var fileReader = new FileReader();
+      fileReader.onload = function() {
+        ok(is_same_buffer(DATA_ARRAY_BUFFER, this.result), "expected same buffer data");
+        aResolve();
+      };
+      fileReader.readAsArrayBuffer(evt.data);
+    });
+  });
+}
+
+function testIncomingArrayBufferView() {
+  return new Promise(function(aResolve, aReject) {
+    info('Receiver: --- testIncomingArrayBufferView ---');
+    connection.binaryType = "arraybuffer";
+    connection.send('testIncomingArrayBufferView');
+    connection.addEventListener('message', function messageHandler(evt) {
+      connection.removeEventListener('message', messageHandler);
+      ok(is_same_buffer(evt.data, TYPED_DATA_ARRAY), "expected same buffer data");
+      aResolve();
+    });
+  });
+}
+
 function runTests() {
   testConnectionAvailable()
   .then(testConnectionReady)
   .then(testIncomingMessage)
   .then(testSendMessage)
+  .then(testIncomingBlobMessage)
   .then(testConnectionClosed)
   .then(testReconnectConnection)
+  .then(testIncomingArrayBuffer)
+  .then(testIncomingArrayBufferView)
   .then(testConnectionClosed);
 }
 
 runTests();
 
 </script>
   </body>
 </html>
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
@@ -10,16 +10,20 @@ function debug(str) {
 }
 
 var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js'));
 var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_receiver.html');
 var request;
 var connection;
 var receiverIframe;
 var presentationId;
+const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
+const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
+const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
+TYPED_DATA_ARRAY.set(DATA_ARRAY);
 
 function postMessageToIframe(aType) {
   receiverIframe.src = receiverUrl + "#" +
                        encodeURIComponent(JSON.stringify({ type: aType }));
 }
 
 function setup() {
 
@@ -154,16 +158,56 @@ function testIncomingMessage() {
       is(msg, "msg-receiver-to-sender", "Sender: Sender should receive message from Receiver");
       postMessageToIframe('message-from-receiver-received');
       aResolve();
     });
     postMessageToIframe('trigger-message-from-receiver');
   });
 }
 
+function testSendBlobMessage() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testSendBlobMessage ---');
+    connection.addEventListener('message', function messageHandler(evt) {
+      connection.removeEventListener('message', messageHandler);
+      let msg = evt.data;
+      is(msg, "testIncomingBlobMessage", "Sender: Sender should receive message from Receiver");
+      let blob = new Blob(["Hello World"], {type : 'text/plain'});
+      connection.send(blob);
+      aResolve();
+    });
+  });
+}
+
+function testSendArrayBuffer() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testSendArrayBuffer ---');
+    connection.addEventListener('message', function messageHandler(evt) {
+      connection.removeEventListener('message', messageHandler);
+      let msg = evt.data;
+      is(msg, "testIncomingArrayBuffer", "Sender: Sender should receive message from Receiver");
+      connection.send(DATA_ARRAY_BUFFER);
+      aResolve();
+    });
+  });
+}
+
+function testSendArrayBufferView() {
+  return new Promise(function(aResolve, aReject) {
+    info('Sender: --- testSendArrayBufferView ---');
+    connection.addEventListener('message', function messageHandler(evt) {
+      connection.removeEventListener('message', messageHandler);
+      let msg = evt.data;
+      is(msg, "testIncomingArrayBufferView", "Sender: Sender should receive message from Receiver");
+      connection.send(TYPED_DATA_ARRAY);
+      aResolve();
+    });
+  });
+}
+
 function testCloseConnection() {
   info('Sender: --- testCloseConnection ---');
   // Test terminate immediate after close.
   function controlChannelEstablishedHandler()
   {
     gScript.removeMessageListener('control-channel-established',
                                   controlChannelEstablishedHandler);
     ok(false, "terminate after close should do nothing");
@@ -264,31 +308,35 @@ function teardown() {
   gScript.sendAsyncMessage('teardown');
 }
 
 function runTests() {
   setup().then(testCreateRequest)
          .then(testStartConnection)
          .then(testSendMessage)
          .then(testIncomingMessage)
+         .then(testSendBlobMessage)
          .then(testCloseConnection)
          .then(testReconnect)
+         .then(testSendArrayBuffer)
+         .then(testSendArrayBufferView)
          .then(testCloseConnection)
          .then(testTerminateAfterClose)
          .then(teardown);
 }
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event');
 SpecialPowers.pushPermissions([
   {type: 'presentation-device-manage', allow: false, context: document},
   {type: "browser", allow: true, context: document},
 ], () => {
   SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
                                       /* Mocked TCP session transport builder in the test */
-                                      ["dom.presentation.session_transport.data_channel.enable", false],
+                                      ["dom.presentation.session_transport.data_channel.enable", true],
                                       ["dom.presentation.controller.enabled", true],
                                       ["dom.presentation.receiver.enabled", true],
                                       ["dom.presentation.test.enabled", true],
                                       ["dom.presentation.test.stage", 0],
-                                      ["dom.mozBrowserFramesEnabled", true]]},
+                                      ["dom.mozBrowserFramesEnabled", true],
+                                      ["media.navigator.permission.disabled", true]]},
                             runTests);
 });
--- a/dom/webidl/PresentationConnection.webidl
+++ b/dom/webidl/PresentationConnection.webidl
@@ -15,16 +15,22 @@ enum PresentationConnectionState
   // Existing presentation, but the communication channel is inactive.
   "closed",
 
   // The presentation is nonexistent anymore. It could be terminated manually,
   // or either controlling or receiving browsing context is no longer available.
   "terminated"
 };
 
+enum PresentationConnectionBinaryType
+{
+  "blob",
+  "arraybuffer"
+};
+
 [Pref="dom.presentation.enabled"]
 interface PresentationConnection : EventTarget {
   /*
    * Unique id for all existing connections.
    */
   [Constant]
   readonly attribute DOMString id;
 
@@ -36,30 +42,37 @@ interface PresentationConnection : Event
   /*
    * @value "connected", "closed", or "terminated".
    */
   readonly attribute PresentationConnectionState state;
 
   attribute EventHandler onconnect;
   attribute EventHandler onclose;
   attribute EventHandler onterminate;
+  attribute PresentationConnectionBinaryType binaryType;
 
   /*
    * After a communication channel has been established between the controlling
    * and receiving context, this function is called to send message out, and the
    * event handler "onmessage" will be invoked at the remote side.
    *
    * This function only works when the state is "connected".
-   *
-   * TODO bug 1228474 Implement PresentationSessionTransport with DataChannel to
-   * support other binary types.
    */
   [Throws]
   void send(DOMString data);
 
+  [Throws]
+  void send(Blob data);
+
+  [Throws]
+  void send(ArrayBuffer data);
+
+  [Throws]
+  void send(ArrayBufferView data);
+
   /*
    * It is triggered when receiving messages.
    */
   attribute EventHandler onmessage;
 
   /*
    * Both the controlling and receiving browsing context can close the
    * connection. Then the connection state should turn into "closed".
--- a/gfx/ipc/VsyncBridgeChild.cpp
+++ b/gfx/ipc/VsyncBridgeChild.cpp
@@ -130,13 +130,13 @@ void
 VsyncBridgeChild::DeallocPVsyncBridgeChild()
 {
   Release();
 }
 
 void
 VsyncBridgeChild::ProcessingError(Result aCode, const char* aReason)
 {
-  MOZ_RELEASE_ASSERT(aCode != MsgDropped, "Processing error in VsyncBridgeChild");
+  MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in VsyncBridgeChild");
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/layers/ipc/APZCTreeManagerParent.cpp
+++ b/gfx/layers/ipc/APZCTreeManagerParent.cpp
@@ -177,24 +177,20 @@ APZCTreeManagerParent::RecvSetTargetAPZC
 {
   for (size_t i = 0; i < aTargets.Length(); i++) {
     if (aTargets[i].mLayersId != mLayersId) {
       // Guard against bad data from hijacked child processes
       NS_ERROR("Unexpected layers id in RecvSetTargetAPZC; dropping message...");
       return false;
     }
   }
-
-  void (IAPZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
-      = &IAPZCTreeManager::SetTargetAPZC;
-
   APZThreadUtils::RunOnControllerThread(NewRunnableMethod
                                         <uint64_t,
                                          StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>
-                                        (mTreeManager, setTargetApzcFunc, aInputBlockId, aTargets));
+                                        (mTreeManager, &IAPZCTreeManager::SetTargetAPZC, aInputBlockId, aTargets));
 
   return true;
 }
 
 bool
 APZCTreeManagerParent::RecvUpdateZoomConstraints(
     const ScrollableLayerGuid& aGuid,
     const MaybeZoomConstraints& aConstraints)
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1619,25 +1619,25 @@ fuzzy-if(Android,8,20) == 602200-3.html 
 == 605138-1.html 605138-1-ref.html
 == 605157-1.xhtml 605157-1-ref.xhtml
 == 607267-1.html 607267-1-ref.html
 == 608636-1.html 608636-1-ref.html
 == 608756-1a.html 608756-1-ref.html
 == 608756-1b.html 608756-1-ref.html
 == 608756-2.html 608756-2-ref.html
 fuzzy-if(Android,4,196) == 609272-1.html 609272-1-ref.html
-needs-focus == 613433-1.html 613433-1-ref.html
-needs-focus == 613433-1.html 613433-2-ref.html
-needs-focus == 613433-1.html 613433-3-ref.html
-needs-focus == 613433-2.html 613433-1-ref.html
-needs-focus == 613433-2.html 613433-2-ref.html
-needs-focus == 613433-2.html 613433-3-ref.html
-needs-focus == 613433-3.html 613433-1-ref.html
-needs-focus == 613433-3.html 613433-2-ref.html
-needs-focus == 613433-3.html 613433-3-ref.html
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-1.html 613433-1-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-1.html 613433-2-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-1.html 613433-3-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-2.html 613433-1-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-2.html 613433-2-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-2.html 613433-3-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-3.html 613433-1-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-3.html 613433-2-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
+needs-focus skip-if(/^Linux\x20i686/.test(http.oscpu)) == 613433-3.html 613433-3-ref.html # bug 1292460 - doesn't get the focus it needs if it's first in a chunk
 == 614272-1.svg  614272-1-ref.svg
 HTTP(..) == 615121-1.html 615121-1-ref.html
 HTTP(..) != 615121-2.html 615121-2-notref.html
 == 617242-1.html 617242-1-ref.html
 != 618071.html 618071-notref.html
 == 619117-1.html 619117-1-ref.html
 HTTP(..) == 619511-1.html 619511-1-ref.html
 skip-if(Android) HTTP(..) == 621253-1-externalFilter.html 621253-1-ref.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1131,21 +1131,16 @@ InitSystemMetrics()
     sSystemMetrics->AppendElement(nsGkAtoms::windows_default_theme);
   }
 
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacGraphiteTheme, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::mac_graphite_theme);
   }
 
-  rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacLionTheme, &metricResult);
-  if (NS_SUCCEEDED(rv) && metricResult) {
-    sSystemMetrics->AppendElement(nsGkAtoms::mac_lion_theme);
-  }
-
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacYosemiteTheme, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::mac_yosemite_theme);
   }
 
   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::windows_compositor);
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -712,24 +712,16 @@ nsMediaFeatures::features[] = {
     &nsGkAtoms::_moz_mac_graphite_theme,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
     { &nsGkAtoms::mac_graphite_theme },
     GetSystemMetric
   },
   {
-    &nsGkAtoms::_moz_mac_lion_theme,
-    nsMediaFeature::eMinMaxNotAllowed,
-    nsMediaFeature::eBoolInteger,
-    nsMediaFeature::eNoRequirements,
-    { &nsGkAtoms::mac_lion_theme },
-    GetSystemMetric
-  },
-  {
     &nsGkAtoms::_moz_mac_yosemite_theme,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eNoRequirements,
     { &nsGkAtoms::mac_yosemite_theme },
     GetSystemMetric
   },
   {
--- a/layout/style/test/test_media_queries.html
+++ b/layout/style/test/test_media_queries.html
@@ -624,17 +624,16 @@ function run() {
   expression_should_be_parseable("-moz-scrollbar-end-backward");
   expression_should_be_parseable("-moz-scrollbar-end-forward");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional");
   expression_should_be_parseable("-moz-images-in-menus");
   expression_should_be_parseable("-moz-images-in-buttons");
   expression_should_be_parseable("-moz-overlay-scrollbars");
   expression_should_be_parseable("-moz-windows-default-theme");
   expression_should_be_parseable("-moz-mac-graphite-theme");
-  expression_should_be_parseable("-moz-mac-lion-theme");
   expression_should_be_parseable("-moz-mac-yosemite-theme");
   expression_should_be_parseable("-moz-windows-compositor");
   expression_should_be_parseable("-moz-windows-classic");
   expression_should_be_parseable("-moz-windows-glass");
   expression_should_be_parseable("-moz-touch-enabled");
   expression_should_be_parseable("-moz-swipe-animation-enabled");
 
   expression_should_be_parseable("-moz-scrollbar-start-backward: 0");
@@ -642,17 +641,16 @@ function run() {
   expression_should_be_parseable("-moz-scrollbar-end-backward: 0");
   expression_should_be_parseable("-moz-scrollbar-end-forward: 0");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 0");
   expression_should_be_parseable("-moz-images-in-menus: 0");
   expression_should_be_parseable("-moz-images-in-buttons: 0");
   expression_should_be_parseable("-moz-overlay-scrollbars: 0");
   expression_should_be_parseable("-moz-windows-default-theme: 0");
   expression_should_be_parseable("-moz-mac-graphite-theme: 0");
-  expression_should_be_parseable("-moz-mac-lion-theme: 0");
   expression_should_be_parseable("-moz-mac-yosemite-theme: 0");
   expression_should_be_parseable("-moz-windows-compositor: 0");
   expression_should_be_parseable("-moz-windows-classic: 0");
   expression_should_be_parseable("-moz-windows-glass: 0");
   expression_should_be_parseable("-moz-touch-enabled: 0");
   expression_should_be_parseable("-moz-swipe-animation-enabled: 0");
 
   expression_should_be_parseable("-moz-scrollbar-start-backward: 1");
@@ -660,17 +658,16 @@ function run() {
   expression_should_be_parseable("-moz-scrollbar-end-backward: 1");
   expression_should_be_parseable("-moz-scrollbar-end-forward: 1");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 1");
   expression_should_be_parseable("-moz-images-in-menus: 1");
   expression_should_be_parseable("-moz-images-in-buttons: 1");
   expression_should_be_parseable("-moz-overlay-scrollbars: 1");
   expression_should_be_parseable("-moz-windows-default-theme: 1");
   expression_should_be_parseable("-moz-mac-graphite-theme: 1");
-  expression_should_be_parseable("-moz-mac-lion-theme: 1");
   expression_should_be_parseable("-moz-mac-yosemite-theme: 1");
   expression_should_be_parseable("-moz-windows-compositor: 1");
   expression_should_be_parseable("-moz-windows-classic: 1");
   expression_should_be_parseable("-moz-windows-glass: 1");
   expression_should_be_parseable("-moz-touch-enabled: 1");
   expression_should_be_parseable("-moz-swipe-animation-enabled: 1");
 
   expression_should_not_be_parseable("-moz-scrollbar-start-backward: -1");
@@ -678,17 +675,16 @@ function run() {
   expression_should_not_be_parseable("-moz-scrollbar-end-backward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-end-forward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: -1");
   expression_should_not_be_parseable("-moz-images-in-menus: -1");
   expression_should_not_be_parseable("-moz-images-in-buttons: -1");
   expression_should_not_be_parseable("-moz-overlay-scrollbars: -1");
   expression_should_not_be_parseable("-moz-windows-default-theme: -1");
   expression_should_not_be_parseable("-moz-mac-graphite-theme: -1");
-  expression_should_not_be_parseable("-moz-mac-lion-theme: -1");
   expression_should_not_be_parseable("-moz-mac-yosemite-theme: -1");
   expression_should_not_be_parseable("-moz-windows-compositor: -1");
   expression_should_not_be_parseable("-moz-windows-classic: -1");
   expression_should_not_be_parseable("-moz-windows-glass: -1");
   expression_should_not_be_parseable("-moz-touch-enabled: -1");
   expression_should_not_be_parseable("-moz-swipe-animation-enabled: -1");
 
   expression_should_not_be_parseable("-moz-scrollbar-start-backward: true");
@@ -696,17 +692,16 @@ function run() {
   expression_should_not_be_parseable("-moz-scrollbar-end-backward: true");
   expression_should_not_be_parseable("-moz-scrollbar-end-forward: true");
   expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: true");
   expression_should_not_be_parseable("-moz-images-in-menus: true");
   expression_should_not_be_parseable("-moz-images-in-buttons: true");
   expression_should_not_be_parseable("-moz-overlay-scrollbars: true");
   expression_should_not_be_parseable("-moz-windows-default-theme: true");
   expression_should_not_be_parseable("-moz-mac-graphite-theme: true");
-  expression_should_not_be_parseable("-moz-mac-lion-theme: true");
   expression_should_not_be_parseable("-moz-mac-yosemite-theme: true");
   expression_should_not_be_parseable("-moz-windows-compositor: true");
   expression_should_not_be_parseable("-moz-windows-classic: true");
   expression_should_not_be_parseable("-moz-windows-glass: true");
   expression_should_not_be_parseable("-moz-touch-enabled: true");
   expression_should_not_be_parseable("-moz-swipe-animation-enabled: true");
 
   // windows theme media queries
--- a/toolkit/content/aboutSupport.xhtml
+++ b/toolkit/content/aboutSupport.xhtml
@@ -150,17 +150,17 @@
               &aboutSupport.appBasicsProfileDir;
 #endif
 #endif
             </th>
 
             <td>
               <button id="profile-dir-button">
 #ifdef XP_WIN
-                &aboutSupport.showWin.label;
+                &aboutSupport.showWin2.label;
 #else
 #ifdef XP_MACOSX
                 &aboutSupport.showMac.label;
 #else
                 &aboutSupport.showDir.label;
 #endif
 #endif
                </button>
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
@@ -67,19 +67,19 @@ Windows/Mac use the term "Folder" instea
 
 <!ENTITY aboutSupport.appBasicsSafeMode "Safe Mode">
 
 <!ENTITY aboutSupport.showDir.label "Open Directory">
 <!-- LOCALIZATION NOTE (aboutSupport.showMac.label): This is the Mac-specific
 variant of aboutSupport.showDir.label.  This allows us to use the preferred
 "Finder" terminology on Mac. -->
 <!ENTITY aboutSupport.showMac.label "Show in Finder">
-<!-- LOCALIZATION NOTE (aboutSupport.showWin.label): This is the Windows-specific
+<!-- LOCALIZATION NOTE (aboutSupport.showWin2.label): This is the Windows-specific
 variant of aboutSupport.showDir.label. -->
-<!ENTITY aboutSupport.showWin.label "Show Folder">
+<!ENTITY aboutSupport.showWin2.label "Open Folder">
 
 <!ENTITY aboutSupport.modifiedKeyPrefsTitle "Important Modified Preferences">
 <!ENTITY aboutSupport.modifiedPrefsName "Name">
 <!ENTITY aboutSupport.modifiedPrefsValue "Value">
 
 <!-- LOCALIZATION NOTE (aboutSupport.userJSTitle, aboutSupport.userJSDescription): user.js is the name of the preference override file being checked. -->
 <!ENTITY aboutSupport.userJSTitle "user.js Preferences">
 <!ENTITY aboutSupport.userJSDescription "Your profile folder contains a <a id='prefs-user-js-link'>user.js file</a>, which includes preferences that were not created by &brandShortName;.">
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -286,26 +286,16 @@ public:
      * A Boolean value to determine whether the Mac graphite theme is
      * being used.
      *
      * The value of this metric is not used on other platforms. These platforms
      * should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
      */
     eIntID_MacGraphiteTheme,
 
-    /*
-     * A Boolean value to determine whether the Mac OS X Lion-specific theming
-     * should be used.
-     *
-     * The value of this metric is not used on non-Mac platforms. These
-     * platforms should return NS_ERROR_NOT_IMPLEMENTED when queried for this
-     * metric.
-     */
-    eIntID_MacLionTheme,
-
    /*
     * A Boolean value to determine whether the Mac OS X Yosemite-specific theming
     * should be used.
     *
     * The value of this metric is not used on non-Mac platforms. These
     * platforms should return NS_ERROR_NOT_IMPLEMENTED when queried for this
     * metric.
     */
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -405,19 +405,16 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
     case eIntID_WindowsThemeIdentifier:
     case eIntID_OperatingSystemVersionIdentifier:
       aResult = 0;
       res = NS_ERROR_NOT_IMPLEMENTED;
       break;
     case eIntID_MacGraphiteTheme:
       aResult = [NSColor currentControlTint] == NSGraphiteControlTint;
       break;
-    case eIntID_MacLionTheme:
-      aResult = 1;
-      break;
     case eIntID_MacYosemiteTheme:
       aResult = nsCocoaFeatures::OnYosemiteOrLater();
       break;
     case eIntID_AlertNotificationOrigin:
       aResult = NS_ALERT_TOP;
       break;
     case eIntID_TabFocusModel:
     {
@@ -591,9 +588,9 @@ nsLookAndFeel::RefreshImpl()
 {
   // We should only clear the cache if we're in the main browser process.
   // Otherwise, we should wait for the parent to inform us of new values
   // to cache via LookAndFeel::SetIntCache.
   if (XRE_IsParentProcess()) {
     mUseOverlayScrollbarsCached = false;
     mAllowOverlayScrollbarsOverlapCached = false;
   }
-}
\ No newline at end of file
+}
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -762,17 +762,16 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
         aResult = mozilla::widget::WidgetUtils::IsTouchDeviceSupportPresent();
         break;
 #else
         aResult = 0;
         res = NS_ERROR_NOT_IMPLEMENTED;
 #endif
         break;
     case eIntID_MacGraphiteTheme:
-    case eIntID_MacLionTheme:
         aResult = 0;
         res = NS_ERROR_NOT_IMPLEMENTED;
         break;
     case eIntID_AlertNotificationOrigin:
         aResult = NS_ALERT_TOP;
         break;
     case eIntID_IMERawInputUnderlineStyle:
     case eIntID_IMEConvertedTextUnderlineStyle:
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1016,22 +1016,19 @@ void nsBaseWidget::ConfigureAPZControlle
   // By default the controller thread is the main thread.
   APZThreadUtils::SetControllerThread(MessageLoop::current());
 }
 
 void
 nsBaseWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
                                      const nsTArray<ScrollableLayerGuid>& aTargets) const
 {
-  // Need to specifically bind this since it's overloaded.
-  void (IAPZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray<ScrollableLayerGuid>&)
-          = &IAPZCTreeManager::SetTargetAPZC;
   APZThreadUtils::RunOnControllerThread(NewRunnableMethod
     <uint64_t, StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>(mAPZC,
-                                                                   setTargetApzcFunc,
+                                                                   &IAPZCTreeManager::SetTargetAPZC,
                                                                    aInputBlockId, aTargets));
 }
 
 void
 nsBaseWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
                                     const FrameMetrics::ViewID& aViewId,
                                     const Maybe<ZoomConstraints>& aConstraints)
 {
--- a/widget/windows/nsLookAndFeel.cpp
+++ b/widget/windows/nsLookAndFeel.cpp
@@ -408,17 +408,16 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
 
     case eIntID_OperatingSystemVersionIdentifier:
     {
         aResult = GetOperatingSystemVersion();
         break;
     }
 
     case eIntID_MacGraphiteTheme:
-    case eIntID_MacLionTheme:
         aResult = 0;
         res = NS_ERROR_NOT_IMPLEMENTED;
         break;
     case eIntID_DWMCompositor:
         aResult = nsUXThemeData::CheckForCompositor();
         break;
     case eIntID_WindowsGlass:
         // Aero Glass is only available prior to Windows 8 when DWM is used.