Bug 1069230 - Presentation API implementation. Part 1 - WebIDL Bindings. r=smaug

This commit is contained in:
Sean Lin 2015-03-19 15:48:28 +08:00
parent 6db2c5f3dc
commit d2cfdcf0f4
15 changed files with 541 additions and 4 deletions

View File

@ -566,7 +566,13 @@ this.PermissionsTable = { geolocation: {
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
}
},
"presentation": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
};
/**

View File

@ -41,6 +41,7 @@
#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"
@ -215,6 +216,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
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
@ -334,6 +336,10 @@ Navigator::Invalidate()
mTimeManager = nullptr;
}
if (mPresentation) {
mPresentation = nullptr;
}
mServiceWorkerContainer = nullptr;
#ifdef MOZ_EME
@ -2763,5 +2769,19 @@ Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
#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

View File

@ -97,6 +97,7 @@ class Voicemail;
class TVManager;
class InputPortManager;
class DeviceStorageAreaListener;
class Presentation;
namespace time {
class TimeManager;
@ -268,6 +269,8 @@ public:
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);
@ -389,6 +392,7 @@ private:
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

View File

@ -683,6 +683,7 @@ 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")

View File

@ -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;
}

View File

@ -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

View File

@ -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.
}

View File

@ -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

View File

@ -9,12 +9,16 @@ 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',
]

View File

@ -430,6 +430,11 @@ partial interface Navigator {
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]

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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();
};

View File

@ -365,7 +365,9 @@ WEBIDL_FILES = [
'PopupBoxObject.webidl',
'Position.webidl',
'PositionError.webidl',
'Presentation.webidl',
'PresentationDeviceInfoManager.webidl',
'PresentationSession.webidl',
'ProcessingInstruction.webidl',
'ProfileTimelineMarker.webidl',
'Promise.webidl',
@ -783,6 +785,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'PluginCrashedEvent.webidl',
'PopStateEvent.webidl',
'PopupBlockedEvent.webidl',
'PresentationAvailableEvent.webidl',
'ProgressEvent.webidl',
'RecordErrorEvent.webidl',
'ScrollViewChangeEvent.webidl',

View File

@ -260,7 +260,7 @@ static void Shutdown();
#include "GMPService.h"
#include "mozilla/dom/presentation/PresentationDeviceManager.h"
#include "mozilla/dom/PresentationDeviceManager.h"
#include "mozilla/TextInputProcessor.h"