Bug 1069230 - Presentation API implementation. Part 1 - WebIDL Bindings. r=smaug
authorSean Lin <selin@mozilla.com>
Thu, 19 Mar 2015 15:48:28 +0800
changeset 288281 91124e7dba5fe7541d8d9d290bc8a963426bda17
parent 288280 74679bd915642f5b3aadec2cb2d8459607235b84
child 288282 6dfe03f1db49962abe61328dfcdb81fe62055227
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1069230
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1069230 - Presentation API implementation. Part 1 - WebIDL Bindings. r=smaug
dom/apps/PermissionsTable.jsm
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/base/nsGkAtomList.h
dom/presentation/Presentation.cpp
dom/presentation/Presentation.h
dom/presentation/PresentationSession.cpp
dom/presentation/PresentationSession.h
dom/presentation/moz.build
dom/webidl/Navigator.webidl
dom/webidl/Presentation.webidl
dom/webidl/PresentationAvailableEvent.webidl
dom/webidl/PresentationSession.webidl
dom/webidl/moz.build
layout/build/nsLayoutModule.cpp
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -561,17 +561,23 @@ this.PermissionsTable =  { geolocation: 
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "system-update": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
-                           }
+                           },
+                           "presentation": {
+                             app: DENY_ACTION,
+                             trusted: DENY_ACTION,
+                             privileged: ALLOW_ACTION,
+                             certified: ALLOW_ACTION
+                           },
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
  * @param array aAccess
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -36,16 +36,17 @@
 #include "mozilla/dom/PowerManager.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/CellBroadcast.h"
 #include "mozilla/dom/IccManager.h"
 #include "mozilla/dom/InputPortManager.h"
 #include "mozilla/dom/MobileMessageManager.h"
 #include "mozilla/dom/Permissions.h"
+#include "mozilla/dom/Presentation.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/Telephony.h"
 #include "mozilla/dom/Voicemail.h"
 #include "mozilla/dom/TVManager.h"
 #include "mozilla/dom/VRDevice.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
 #include "mozilla/ClearOnShutdown.h"
@@ -210,16 +211,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults)
 #ifdef MOZ_EME
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
 #endif
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageAreaListener)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Navigator)
 
 void
 Navigator::Invalidate()
 {
@@ -329,16 +331,20 @@ Navigator::Invalidate()
     mDeviceStorageStores[i]->Shutdown();
   }
   mDeviceStorageStores.Clear();
 
   if (mTimeManager) {
     mTimeManager = nullptr;
   }
 
+  if (mPresentation) {
+    mPresentation = nullptr;
+  }
+
   mServiceWorkerContainer = nullptr;
 
 #ifdef MOZ_EME
   if (mMediaKeySystemAccessManager) {
     mMediaKeySystemAccessManager->Shutdown();
     mMediaKeySystemAccessManager = nullptr;
   }
 #endif
@@ -2758,10 +2764,24 @@ Navigator::RequestMediaKeySystemAccess(c
   }
 
   mMediaKeySystemAccessManager->Request(promise, aKeySystem, aOptions);
   return promise.forget();
 }
 
 #endif
 
+Presentation*
+Navigator::GetPresentation(ErrorResult& aRv)
+{
+  if (!mPresentation) {
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
+    }
+    mPresentation = Presentation::Create(mWindow);
+  }
+
+  return mPresentation;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -92,16 +92,17 @@ class MobileConnectionArray;
 class PowerManager;
 class CellBroadcast;
 class IccManager;
 class Telephony;
 class Voicemail;
 class TVManager;
 class InputPortManager;
 class DeviceStorageAreaListener;
+class Presentation;
 
 namespace time {
 class TimeManager;
 } // namespace time
 
 namespace system {
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 class AudioChannelManager;
@@ -263,16 +264,18 @@ public:
 #endif // MOZ_B2G_BT
 #ifdef MOZ_TIME_MANAGER
   time::TimeManager* GetMozTime(ErrorResult& aRv);
 #endif // MOZ_TIME_MANAGER
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
 #endif // MOZ_AUDIO_CHANNEL_MANAGER
 
+  Presentation* GetPresentation(ErrorResult& aRv);
+
   bool SendBeacon(const nsAString& aUrl,
                   const Nullable<ArrayBufferViewOrBlobOrStringOrFormData>& aData,
                   ErrorResult& aRv);
 
 #ifdef MOZ_MEDIA_NAVIGATOR
   void MozGetUserMedia(const MediaStreamConstraints& aConstraints,
                        NavigatorUserMediaSuccessCallback& aOnSuccess,
                        NavigatorUserMediaErrorCallback& aOnError,
@@ -384,16 +387,17 @@ private:
   nsRefPtr<nsDOMCameraManager> mCameraManager;
   nsRefPtr<MediaDevices> mMediaDevices;
   nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
   nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
   nsRefPtr<time::TimeManager> mTimeManager;
   nsRefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsRefPtr<DeviceStorageAreaListener> mDeviceStorageAreaListener;
+  nsRefPtr<Presentation> mPresentation;
 
   // Hashtable for saving cached objects DoResolve created, so we don't create
   // the object twice if asked for it twice, whether due to use of "delete" or
   // due to Xrays.  We could probably use a nsJSThingHashtable here, but then
   // we'd need to figure out exactly how to trace that, and that seems to be
   // rocket science.  :(
   nsInterfaceHashtable<nsStringHashKey, nsISupports> mCachedResolveResults;
 };
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -678,16 +678,17 @@ GK_ATOM(onafterscriptexecute, "onaftersc
 GK_ATOM(onalerting, "onalerting")
 GK_ATOM(onanimationend, "onanimationend")
 GK_ATOM(onanimationiteration, "onanimationiteration")
 GK_ATOM(onanimationstart, "onanimationstart")
 GK_ATOM(onantennaavailablechange, "onantennaavailablechange")
 GK_ATOM(onAppCommand, "onAppCommand")
 GK_ATOM(onattributechanged, "onattributechanged")
 GK_ATOM(onaudioprocess, "onaudioprocess")
+GK_ATOM(onavailablechange, "onavailablechange")
 GK_ATOM(onbeforecopy, "onbeforecopy")
 GK_ATOM(onbeforecut, "onbeforecut")
 GK_ATOM(onbeforepaste, "onbeforepaste")
 GK_ATOM(onbeforeevicted, "onbeforeevicted")
 GK_ATOM(onbeforeprint, "onbeforeprint")
 GK_ATOM(onbeforescriptexecute, "onbeforescriptexecute")
 GK_ATOM(onbeforeunload, "onbeforeunload")
 GK_ATOM(onblocked, "onblocked")
new file mode 100644
--- /dev/null
+++ b/dom/presentation/Presentation.cpp
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "mozilla/dom/PresentationBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIPresentationDeviceManager.h"
+#include "nsServiceManagerUtils.h"
+#include "Presentation.h"
+#include "PresentationSession.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Presentation)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Presentation, DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSession)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Presentation, DOMEventTargetHelper)
+  tmp->Shutdown();
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSession)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ADDREF_INHERITED(Presentation, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(Presentation, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Presentation)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+/* static */ already_AddRefed<Presentation>
+Presentation::Create(nsPIDOMWindow* aWindow)
+{
+  nsRefPtr<Presentation> presentation = new Presentation(aWindow);
+  return NS_WARN_IF(!presentation->Init()) ? nullptr : presentation.forget();
+}
+
+Presentation::Presentation(nsPIDOMWindow* aWindow)
+  : DOMEventTargetHelper(aWindow)
+  , mAvailable(false)
+{
+}
+
+Presentation::~Presentation()
+{
+  Shutdown();
+}
+
+bool
+Presentation::Init()
+{
+  // TODO: Register listener for |mAvailable| changes.
+
+  return true;
+}
+
+void Presentation::Shutdown()
+{
+  mSession = nullptr;
+
+  // TODO: Unregister listener for |mAvailable| changes.
+}
+
+/* virtual */ JSObject*
+Presentation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return PresentationBinding::Wrap(aCx, this, aGivenProto);
+}
+
+already_AddRefed<Promise>
+Presentation::StartSession(const nsAString& aUrl,
+                           const Optional<nsAString>& aId,
+                           ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (NS_WARN_IF(!global)) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  // TODO: Resolve/reject the promise.
+
+  return promise.forget();
+}
+
+already_AddRefed<PresentationSession>
+Presentation::GetSession() const
+{
+  nsRefPtr<PresentationSession> session = mSession;
+  return session.forget();
+}
+
+bool
+Presentation::CachedAvailable() const
+{
+  return mAvailable;
+}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/Presentation.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_Presentation_h
+#define mozilla_dom_Presentation_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+class PresentationSession;
+
+class Presentation final : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Presentation,
+                                           DOMEventTargetHelper)
+
+  static already_AddRefed<Presentation> Create(nsPIDOMWindow* aWindow);
+  virtual JSObject*
+    WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  // WebIDL (public APIs)
+  already_AddRefed<Promise> StartSession(const nsAString& aUrl,
+                                         const Optional<nsAString>& aId,
+                                         ErrorResult& aRv);
+  already_AddRefed<PresentationSession> GetSession() const;
+  bool CachedAvailable() const;
+  IMPL_EVENT_HANDLER(availablechange);
+
+private:
+  explicit Presentation(nsPIDOMWindow* aWindow);
+  ~Presentation();
+
+  bool Init();
+  void Shutdown();
+
+  bool mAvailable;
+  nsRefPtr<PresentationSession> mSession;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_Presentation_h
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationSession.cpp
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsCycleCollectionParticipant.h"
+#include "nsServiceManagerUtils.h"
+#include "nsStringStream.h"
+#include "PresentationSession.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationSession)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationSession, DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationSession, DOMEventTargetHelper)
+  tmp->Shutdown();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ADDREF_INHERITED(PresentationSession, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(PresentationSession, DOMEventTargetHelper)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PresentationSession)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+PresentationSession::PresentationSession(nsPIDOMWindow* aWindow,
+                                         const nsAString& aId,
+                                         PresentationSessionState aState)
+  : DOMEventTargetHelper(aWindow)
+  , mId(aId)
+  , mState(aState)
+{
+}
+
+/* virtual */ PresentationSession::~PresentationSession()
+{
+}
+
+/* static */ already_AddRefed<PresentationSession>
+PresentationSession::Create(nsPIDOMWindow* aWindow,
+                            const nsAString& aId,
+                            PresentationSessionState aState)
+{
+  nsRefPtr<PresentationSession> session =
+    new PresentationSession(aWindow, aId, aState);
+  return NS_WARN_IF(!session->Init()) ? nullptr : session.forget();
+}
+
+bool
+PresentationSession::Init()
+{
+  if (NS_WARN_IF(mId.IsEmpty())) {
+    return false;
+  }
+
+  // TODO: Register listener for session state changes.
+
+  return true;
+}
+
+void
+PresentationSession::Shutdown()
+{
+  // TODO: Unregister listener for session state changes.
+}
+
+/* virtual */ JSObject*
+PresentationSession::WrapObject(JSContext* aCx,
+                                JS::Handle<JSObject*> aGivenProto)
+{
+  return PresentationSessionBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+PresentationSession::GetId(nsAString& aId) const
+{
+  aId = mId;
+}
+
+PresentationSessionState
+PresentationSession::State() const
+{
+  // TODO: Dispatch event when the value of |mState| is changed.
+  return mState;
+}
+
+void
+PresentationSession::Send(const nsAString& aData,
+                          ErrorResult& aRv)
+{
+  // Sending is not allowed if the session is not connected.
+  if (NS_WARN_IF(mState != PresentationSessionState::Connected)) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return;
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsIStringInputStream> stream =
+    do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
+  NS_ConvertUTF16toUTF8 msgString(aData);
+  rv = stream->SetData(msgString.BeginReading(), msgString.Length());
+  if(NS_WARN_IF(NS_FAILED(rv))) {
+    aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
+    return;
+  }
+
+  // TODO: Send the message to the stream.
+}
+
+void
+PresentationSession::Close()
+{
+  // Closing does nothing if the session is already terminated.
+  if (NS_WARN_IF(mState == PresentationSessionState::Terminated)) {
+    return;
+  }
+
+  // TODO: Terminate the socket.
+}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/PresentationSession.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PresentationSession_h
+#define mozilla_dom_PresentationSession_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/PresentationSessionBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+class PresentationSession final : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PresentationSession,
+                                           DOMEventTargetHelper)
+
+  static already_AddRefed<PresentationSession>
+    Create(nsPIDOMWindow* aWindow,
+           const nsAString& aId,
+           PresentationSessionState aState);
+  virtual JSObject*
+    WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  // WebIDL (public APIs)
+  void GetId(nsAString& aId) const;
+  PresentationSessionState State() const;
+  void Send(const nsAString& aData, ErrorResult& aRv);
+  void Close();
+
+  IMPL_EVENT_HANDLER(statechange);
+  IMPL_EVENT_HANDLER(message);
+
+private:
+  explicit PresentationSession(nsPIDOMWindow* aWindow,
+                               const nsAString& aId,
+                               PresentationSessionState aState);
+  ~PresentationSession();
+
+  bool Init();
+  void Shutdown();
+
+  nsString mId;
+  PresentationSessionState mState;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationSession_h
--- a/dom/presentation/moz.build
+++ b/dom/presentation/moz.build
@@ -4,22 +4,26 @@
 # 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/.
 
 DIRS += ['interfaces', 'provider']
 
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
 
-EXPORTS.mozilla.dom.presentation += [
+EXPORTS.mozilla.dom += [
+    'Presentation.h',
     'PresentationDeviceManager.h',
+    'PresentationSession.h',
 ]
 
-SOURCES += [
+UNIFIED_SOURCES += [
+    'Presentation.cpp',
     'PresentationDeviceManager.cpp',
+    'PresentationSession.cpp',
     'PresentationSessionRequest.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'PresentationDeviceInfoManager.js',
     'PresentationDeviceInfoManager.manifest',
 ]
 
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -425,16 +425,21 @@ partial interface Navigator {
   readonly attribute TVManager? tv;
 };
 
 partial interface Navigator {
   [Throws, Pref="dom.inputport.enabled", CheckAnyPermissions="inputport", AvailableIn=CertifiedApps]
   readonly attribute InputPortManager inputPortManager;
 };
 
+partial interface Navigator {
+  [Throws, Pref="dom.presentation.enabled", CheckAnyPermissions="presentation", AvailableIn="PrivilegedApps"]
+  readonly attribute Presentation? presentation;
+};
+
 #ifdef MOZ_EME
 partial interface Navigator {
   [Pref="media.eme.apiVisible", NewObject]
   Promise<MediaKeySystemAccess>
   requestMediaKeySystemAccess(DOMString keySystem,
                               optional sequence<MediaKeySystemOptions> supportedConfigurations);
 };
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Presentation.webidl
@@ -0,0 +1,64 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Pref="dom.presentation.enabled",
+ CheckAnyPermissions="presentation",
+ AvailableIn="PrivilegedApps"]
+interface Presentation : EventTarget {
+  /*
+   * A requesting page use startSession() to start a new session, and the
+   * session will be returned with the promise. UA may show a prompt box with a
+   * list of available devices and ask the user to grant permission, choose a
+   * device, or cancel the operation.
+   *
+   * @url: The URL of presenting page.
+   * @sessionId: Optional. If it's not specified, a random alphanumeric value of
+   *             at least 16 characters drawn from the character [A-Za-z0-9] is
+   *             automatically generated as the id of the session.
+   *
+   * The promise is resolved when the presenting page is successfully loaded and
+   * the communication channel is established, i.e., the session state is
+   * "connected".
+   *
+   * The promise may be rejected duo to one of the following reasons:
+   * - "InternalError":        Unexpected internal error occurs.
+   * - "NoDeviceAvailable":    No available device.
+   * - "PermissionDenied":     User dismiss the device prompt box.
+   * - "ControlChannelFailed": Failed to establish control channel.
+   * - "NoApplicationFound":  app:// scheme is supported on Firefox OS, but no
+   *                           corresponding application is found on remote side.
+   * - "PageLoadTimeout":      Presenting page takes too long to load.
+   * - "DataChannelFailed":    Failed to establish data channel.
+   */
+  [Throws]
+  Promise<PresentationSession> startSession(DOMString url,
+                                            optional DOMString sessionId);
+
+  /*
+   * This attribute is only available on the presenting page. It should be
+   * created when loading the presenting page, and it's ready to be used after
+   * 'onload' event is dispatched.
+   */
+  [Pure]
+  readonly attribute PresentationSession? session;
+
+ /*
+  * Device availability. If there is more than one device discovered by UA,
+  * the value is |true|. Otherwise, its value should be |false|.
+  *
+  * UA triggers device discovery mechanism periodically and cache the latest
+  * result in this attribute. Thus, it may be out-of-date when we're not in
+  * discovery mode, however, it is still useful to give the developers an idea
+  * that whether there are devices nearby some time ago.
+  */
+  readonly attribute boolean cachedAvailable;
+
+  /*
+   * It is called when device availability changes. New value is dispatched with
+   * the event.
+   */
+  attribute EventHandler onavailablechange;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PresentationAvailableEvent.webidl
@@ -0,0 +1,20 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+[Constructor(DOMString typeArg,
+ optional PresentationAvailableEventInit eventInitDict),
+ Pref="dom.presentation.enabled",
+ CheckAnyPermissions="presentation",
+ AvailableIn="PrivilegedApps"]
+interface PresentationAvailableEvent : Event
+{
+  readonly attribute boolean available;
+};
+
+dictionary PresentationAvailableEventInit : EventInit
+{
+  boolean available = false;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PresentationSession.webidl
@@ -0,0 +1,70 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+enum PresentationSessionState
+{
+  // Existing presentation, and the communication channel is active.
+  "connected",
+
+  // Existing presentation, but the communication channel is inactive.
+  "disconnected",
+
+  // The presentation is nonexistent anymore. It could be terminated manually,
+  // or either requesting page or presenting page is no longer available.
+  "terminated"
+};
+
+[Pref="dom.presentation.enabled",
+ CheckAnyPermissions="presentation",
+ AvailableIn="PrivilegedApps"]
+interface PresentationSession : EventTarget {
+  /*
+   * Unique id for all existing sessions.
+   */
+  [Constant]
+  readonly attribute DOMString id;
+
+  /*
+   * Please refer to PresentationSessionStateEvent.webidl for the declaration of
+   * PresentationSessionState.
+   *
+   * @value "connected", "disconnected", or "terminated".
+   */
+  readonly attribute PresentationSessionState state;
+
+  /*
+   * It is called when session state changes. New state is dispatched with the
+   * event.
+   */
+  attribute EventHandler onstatechange;
+
+  /*
+   * After a communication channel has been established between the requesting
+   * page and the presenting page, send() is called to send message out, and the
+   * event handler "onmessage" will be invoked on the remote side.
+   *
+   * This function only works when state equals "connected".
+   *
+   * @data: String literal-only for current implementation.
+   */
+  [Throws]
+  void send(DOMString data);
+
+  /*
+   * It is triggered when receiving messages.
+   */
+  attribute EventHandler onmessage;
+
+  /*
+   * Both the requesting page and the presenting page can close the session by
+   * calling terminate(). Then, the session is destroyed and its state is
+   * truned into "terminated". After getting into the state of "terminated",
+   * resumeSession() is incapable of re-establishing the connection.
+   *
+   * This function does nothing if the state has already been "terminated".
+   */
+  void close();
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -360,17 +360,19 @@ WEBIDL_FILES = [
     'PermissionStatus.webidl',
     'PhoneNumberService.webidl',
     'Plugin.webidl',
     'PluginArray.webidl',
     'PointerEvent.webidl',
     'PopupBoxObject.webidl',
     'Position.webidl',
     'PositionError.webidl',
+    'Presentation.webidl',
     'PresentationDeviceInfoManager.webidl',
+    'PresentationSession.webidl',
     'ProcessingInstruction.webidl',
     'ProfileTimelineMarker.webidl',
     'Promise.webidl',
     'PromiseDebugging.webidl',
     'RadioNodeList.webidl',
     'Range.webidl',
     'Rect.webidl',
     'Request.webidl',
@@ -778,16 +780,17 @@ GENERATED_EVENTS_WEBIDL_FILES = [
     'MozSmsEvent.webidl',
     'MozStkCommandEvent.webidl',
     'MozVoicemailEvent.webidl',
     'PageTransitionEvent.webidl',
     'PerformanceEntryEvent.webidl',
     'PluginCrashedEvent.webidl',
     'PopStateEvent.webidl',
     'PopupBlockedEvent.webidl',
+    'PresentationAvailableEvent.webidl',
     'ProgressEvent.webidl',
     'RecordErrorEvent.webidl',
     'ScrollViewChangeEvent.webidl',
     'SelectionStateChangedEvent.webidl',
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
     'TrackEvent.webidl',
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -255,17 +255,17 @@ static void Shutdown();
 
 #ifdef MOZ_WIDGET_GONK
 #include "GonkGPSGeolocationProvider.h"
 #endif
 #include "MediaManager.h"
 
 #include "GMPService.h"
 
-#include "mozilla/dom/presentation/PresentationDeviceManager.h"
+#include "mozilla/dom/PresentationDeviceManager.h"
 
 #include "mozilla/TextInputProcessor.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::alarm::AlarmHalService;
 using mozilla::dom::power::PowerManagerService;
 using mozilla::dom::quota::QuotaManager;