--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -945,17 +945,19 @@ GK_ATOM(onunderflow, "onunderflow")
GK_ATOM(onunload, "onunload")
GK_ATOM(onupdatefound, "onupdatefound")
GK_ATOM(onupdateready, "onupdateready")
GK_ATOM(onupgradeneeded, "onupgradeneeded")
GK_ATOM(onussdreceived, "onussdreceived")
GK_ATOM(onversionchange, "onversionchange")
GK_ATOM(onvoicechange, "onvoicechange")
GK_ATOM(onvoiceschanged, "onvoiceschanged")
+GK_ATOM(onvrdisplayactivate, "onvrdisplayactivate")
GK_ATOM(onvrdisplayconnect, "onvrdisplayconnect")
+GK_ATOM(onvrdisplaydeactivate, "onvrdisplaydeactivate")
GK_ATOM(onvrdisplaydisconnect, "onvrdisplaydisconnect")
GK_ATOM(onvrdisplaypresentchange, "onvrdisplaypresentchange")
GK_ATOM(onwebkitAnimationEnd, "onwebkitAnimationEnd")
GK_ATOM(onwebkitAnimationIteration, "onwebkitAnimationIteration")
GK_ATOM(onwebkitAnimationStart, "onwebkitAnimationStart")
GK_ATOM(onwebkitTransitionEnd, "onwebkitTransitionEnd")
GK_ATOM(onwebkitanimationend, "onwebkitanimationend")
GK_ATOM(onwebkitanimationiteration, "onwebkitanimationiteration")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -196,16 +196,18 @@
#include "mozilla/dom/IDBFactory.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadManager.h"
#include "mozilla/dom/VRDisplay.h"
+#include "mozilla/dom/VRDisplayEvent.h"
+#include "mozilla/dom/VRDisplayEventBinding.h"
#include "mozilla/dom/VREventObserver.h"
#include "nsRefreshDriver.h"
#include "Layers.h"
#include "mozilla/AddonPathService.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Services.h"
@@ -12933,17 +12935,19 @@ nsGlobalWindow::SetHasGamepadEventListen
EnableGamepadUpdates();
}
}
void
nsGlobalWindow::EventListenerAdded(nsIAtom* aType)
{
- if (aType == nsGkAtoms::onvrdisplayconnect ||
+ if (aType == nsGkAtoms::onvrdisplayactivate ||
+ aType == nsGkAtoms::onvrdisplayconnect ||
+ aType == nsGkAtoms::onvrdisplaydeactivate ||
aType == nsGkAtoms::onvrdisplaydisconnect ||
aType == nsGkAtoms::onvrdisplaypresentchange) {
NotifyVREventListenerAdded();
}
}
void
nsGlobalWindow::NotifyVREventListenerAdded()
@@ -13107,16 +13111,72 @@ nsGlobalWindow::NotifyActiveVRDisplaysCh
{
MOZ_ASSERT(IsInnerWindow());
if (mNavigator) {
mNavigator->NotifyActiveVRDisplaysChanged();
}
}
+void
+nsGlobalWindow::DispatchVRDisplayActivate(uint32_t aDisplayID,
+ mozilla::dom::VRDisplayEventReason aReason)
+{
+ for (auto display : mVRDisplays) {
+ if (display->DisplayId() == aDisplayID
+ && !display->IsAnyPresenting()) {
+ // We only want to trigger this event if nobody is presenting to the
+ // display already.
+
+ VRDisplayEventInit init;
+ init.mBubbles = true;
+ init.mCancelable = false;
+ init.mDisplay = display;
+ init.mReason.Construct(aReason);
+
+ RefPtr<VRDisplayEvent> event =
+ VRDisplayEvent::Constructor(this,
+ NS_LITERAL_STRING("vrdisplayactivate"),
+ init);
+ // vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent
+ // to be used in response to link traversal, user request (chrome UX), and
+ // HMD mounting detection sensors.
+ event->SetTrusted(true);
+ bool defaultActionEnabled;
+ Unused << DispatchEvent(event, &defaultActionEnabled);
+ break;
+ }
+ }
+}
+
+void
+nsGlobalWindow::DispatchVRDisplayDeactivate(uint32_t aDisplayID,
+ mozilla::dom::VRDisplayEventReason aReason)
+{
+ for (auto display : mVRDisplays) {
+ if (display->DisplayId() == aDisplayID && display->IsPresenting()) {
+ // We only want to trigger this event to content that is presenting to
+ // the display already.
+
+ VRDisplayEventInit init;
+ init.mBubbles = true;
+ init.mCancelable = false;
+ init.mDisplay = display;
+ init.mReason.Construct(aReason);
+
+ RefPtr<VRDisplayEvent> event =
+ VRDisplayEvent::Constructor(this,
+ NS_LITERAL_STRING("vrdisplaydeactivate"),
+ init);
+ bool defaultActionEnabled;
+ Unused << DispatchEvent(event, &defaultActionEnabled);
+ break;
+ }
+ }
+}
// nsGlobalChromeWindow implementation
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,
nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -129,16 +129,17 @@ class PostMessageEvent;
struct RequestInit;
class RequestOrUSVString;
class Selection;
class SpeechSynthesis;
class TabGroup;
class Timeout;
class U2F;
class VRDisplay;
+enum class VRDisplayEventReason : uint8_t;
class VREventObserver;
class WakeLock;
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
class WindowOrientationObserver;
#endif
class Worklet;
namespace cache {
class CacheStorage;
@@ -750,16 +751,21 @@ public:
// Update the VR displays for this window
bool UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDisplays);
// Inner windows only.
// Called to inform that the set of active VR displays has changed.
void NotifyActiveVRDisplaysChanged();
+ void DispatchVRDisplayActivate(uint32_t aDisplayID,
+ mozilla::dom::VRDisplayEventReason aReason);
+ void DispatchVRDisplayDeactivate(uint32_t aDisplayID,
+ mozilla::dom::VRDisplayEventReason aReason);
+
#define EVENT(name_, id_, type_, struct_) \
mozilla::dom::EventHandlerNonNull* GetOn##name_() \
{ \
mozilla::EventListenerManager* elm = GetExistingListenerManager(); \
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
: nullptr; \
} \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler) \
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -602,16 +602,24 @@ WINDOW_ONLY_EVENT(deviceproximity,
WINDOW_ONLY_EVENT(userproximity,
eUserProximity,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(devicelight,
eDeviceLight,
EventNameType_None,
eBasicEventClass)
+WINDOW_ONLY_EVENT(vrdisplayactivate,
+ eVRDisplayActivate,
+ EventNameType_None,
+ eBasicEventClass)
+WINDOW_ONLY_EVENT(vrdisplaydeactivate,
+ eVRDisplayDeactivate,
+ EventNameType_None,
+ eBasicEventClass)
WINDOW_ONLY_EVENT(vrdisplayconnect,
eVRDisplayConnect,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(vrdisplaydisconnect,
eVRDisplayDisconnect,
EventNameType_None,
eBasicEventClass)
--- a/dom/vr/VRDisplay.cpp
+++ b/dom/vr/VRDisplay.cpp
@@ -459,19 +459,22 @@ VRDisplay::RequestPresent(const nsTArray
}
RefPtr<Promise> promise = Promise::Create(global, aRv);
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, nullptr);
- if (mClient->GetIsPresenting()) {
+ if (!IsPresenting() && IsAnyPresenting()) {
// Only one presentation allowed per VRDisplay
// on a first-come-first-serve basis.
+ // If this Javascript context is presenting, then we can replace our
+ // presentation with a new one containing new layers but we should never
+ // replace the presentation of another context.
promise->MaybeRejectWithUndefined();
} else {
mPresentation = mClient->BeginPresentation(aLayers);
mFrameInfo.Clear();
nsresult rv = obs->AddObserver(this, "inner-window-destroyed", false);
if (NS_WARN_IF(NS_FAILED(rv))) {
mPresentation = nullptr;
@@ -581,16 +584,24 @@ bool
VRDisplay::IsPresenting() const
{
// IsPresenting returns true only if this Javascript context is presenting
// and will return false if another context is presenting.
return mPresentation != nullptr;
}
bool
+VRDisplay::IsAnyPresenting() const
+{
+ // IsAnyPresenting returns true if any Javascript context is presenting
+ // even if this context is not presenting.
+ return IsPresenting() || mClient->GetIsPresenting();
+}
+
+bool
VRDisplay::IsConnected() const
{
return mClient->GetIsConnected();
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(VRDisplay, DOMEventTargetHelper, mCapabilities, mStageParameters)
NS_IMPL_ADDREF_INHERITED(VRDisplay, DOMEventTargetHelper)
--- a/dom/vr/VRDisplay.h
+++ b/dom/vr/VRDisplay.h
@@ -269,16 +269,17 @@ class VRDisplay final : public DOMEventT
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIOBSERVER
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VRDisplay, DOMEventTargetHelper)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
bool IsPresenting() const;
+ bool IsAnyPresenting() const;
bool IsConnected() const;
VRDisplayCapabilities* Capabilities();
VRStageParameters* GetStageParameters();
uint32_t DisplayId() const { return mDisplayId; }
void GetDisplayName(nsAString& aDisplayName) const { aDisplayName = mDisplayName; }
new file mode 100644
--- /dev/null
+++ b/dom/vr/VRDisplayEvent.cpp
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VRDisplayEvent.h"
+#include "js/GCAPI.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/PrimitiveConversions.h"
+
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(VRDisplayEvent)
+
+NS_IMPL_ADDREF_INHERITED(VRDisplayEvent, Event)
+NS_IMPL_RELEASE_INHERITED(VRDisplayEvent, Event)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VRDisplayEvent, Event)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(VRDisplayEvent, Event)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VRDisplayEvent, Event)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(VRDisplayEvent)
+NS_INTERFACE_MAP_END_INHERITING(Event)
+
+VRDisplayEvent::VRDisplayEvent(mozilla::dom::EventTarget* aOwner)
+ : Event(aOwner, nullptr, nullptr)
+{
+}
+
+VRDisplayEvent::~VRDisplayEvent()
+{
+}
+
+VRDisplay*
+VRDisplayEvent::Display()
+{
+ return mDisplay;
+}
+
+JSObject*
+VRDisplayEvent::WrapObjectInternal(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto)
+{
+ return VRDisplayEventBinding::Wrap(aCx, this, aGivenProto);
+}
+
+already_AddRefed<VRDisplayEvent>
+VRDisplayEvent::Constructor(mozilla::dom::EventTarget* aOwner,
+ const nsAString& aType,
+ const VRDisplayEventInit& aEventInitDict)
+{
+ RefPtr<VRDisplayEvent> e = new VRDisplayEvent(aOwner);
+ bool trusted = e->Init(aOwner);
+ e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
+ if (aEventInitDict.mReason.WasPassed()) {
+ e->mReason = Some(aEventInitDict.mReason.Value());
+ }
+ e->SetTrusted(trusted);
+ e->SetComposed(aEventInitDict.mComposed);
+ return e.forget();
+}
+
+already_AddRefed<VRDisplayEvent>
+VRDisplayEvent::Constructor(const GlobalObject& aGlobal, const nsAString& aType,
+ const VRDisplayEventInit& aEventInitDict,
+ ErrorResult& aRv)
+{
+ nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports());
+ return Constructor(owner, aType, aEventInitDict);
+}
+
+Nullable<VRDisplayEventReason>
+VRDisplayEvent::GetReason() const
+{
+ if (mReason.isSome()) {
+ return mReason.value();
+ } else {
+ return nullptr;
+ }
+
+}
+
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/vr/VRDisplayEvent.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_VRDisplayEvent_h_
+#define mozilla_dom_VRDisplayEvent_h_
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/VRDisplayEventBinding.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/Event.h"
+
+#include "gfxVR.h"
+
+struct JSContext;
+
+namespace mozilla {
+namespace gfx {
+class VRDisplay;
+} // namespace gfx
+
+namespace dom {
+
+class VRDisplayEvent final : public Event
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(VRDisplayEvent, Event)
+
+ VRDisplay* Display();
+ Nullable<VRDisplayEventReason> GetReason() const;
+
+protected:
+ virtual ~VRDisplayEvent();
+ explicit VRDisplayEvent(mozilla::dom::EventTarget* aOwner);
+ VRDisplayEvent(EventTarget* aOwner,
+ nsPresContext* aPresContext,
+ InternalClipboardEvent* aEvent);
+
+ Maybe<VRDisplayEventReason> mReason;
+ RefPtr<VRDisplay> mDisplay;
+
+public:
+
+ virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ static already_AddRefed<VRDisplayEvent> Constructor(mozilla::dom::EventTarget* aOwner, const nsAString& aType, const VRDisplayEventInit& aEventInitDict);
+
+ static already_AddRefed<VRDisplayEvent> Constructor(const GlobalObject& aGlobal, const nsAString& aType, const VRDisplayEventInit& aEventInitDict, ErrorResult& aRv);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/vr/VREventObserver.cpp
+++ b/dom/vr/VREventObserver.cpp
@@ -11,17 +11,18 @@
#include "VRManagerChild.h"
namespace mozilla {
namespace dom {
using namespace gfx;
/**
- * This class is used by nsGlobalWindow to implement window.onvrdisplayconnected,
+ * This class is used by nsGlobalWindow to implement window.onvrdisplayactivate,
+ * window.onvrdisplaydeactivate, window.onvrdisplayconnected,
* window.onvrdisplaydisconnected, and window.onvrdisplaypresentchange.
*/
VREventObserver::VREventObserver(nsGlobalWindow* aGlobalWindow)
: mWindow(aGlobalWindow)
{
MOZ_ASSERT(aGlobalWindow && aGlobalWindow->IsInnerWindow());
VRManagerChild* vmc = VRManagerChild::Get();
@@ -34,16 +35,56 @@ VREventObserver::~VREventObserver()
{
VRManagerChild* vmc = VRManagerChild::Get();
if (vmc) {
vmc->RemoveListener(this);
}
}
void
+VREventObserver::NotifyVRDisplayMounted(uint32_t aDisplayID)
+{
+ if (mWindow->AsInner()->IsCurrentInnerWindow()) {
+ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+ mWindow->DispatchVRDisplayActivate(aDisplayID,
+ VRDisplayEventReason::Mounted);
+ }
+}
+
+void
+VREventObserver::NotifyVRDisplayNavigation(uint32_t aDisplayID)
+{
+ if (mWindow->AsInner()->IsCurrentInnerWindow()) {
+ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+ mWindow->DispatchVRDisplayActivate(aDisplayID,
+ VRDisplayEventReason::Navigation);
+ }
+}
+
+void
+VREventObserver::NotifyVRDisplayRequested(uint32_t aDisplayID)
+{
+ if (mWindow->AsInner()->IsCurrentInnerWindow()) {
+ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+ mWindow->DispatchVRDisplayActivate(aDisplayID,
+ VRDisplayEventReason::Requested);
+ }
+}
+
+void
+VREventObserver::NotifyVRDisplayUnmounted(uint32_t aDisplayID)
+{
+ if (mWindow->AsInner()->IsCurrentInnerWindow()) {
+ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+ mWindow->DispatchVRDisplayDeactivate(aDisplayID,
+ VRDisplayEventReason::Unmounted);
+ }
+}
+
+void
VREventObserver::NotifyVRDisplayConnect()
{
/**
* We do not call nsGlobalWindow::NotifyActiveVRDisplaysChanged here, as we
* can assume that a newly enumerated display is not presenting WebVR
* content.
*/
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
--- a/dom/vr/VREventObserver.h
+++ b/dom/vr/VREventObserver.h
@@ -2,27 +2,33 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_VREventObserver_h
#define mozilla_dom_VREventObserver_h
+#include "mozilla/dom/VRDisplayEventBinding.h"
+
class nsGlobalWindow;
namespace mozilla {
namespace dom {
class VREventObserver final
{
public:
~VREventObserver();
explicit VREventObserver(nsGlobalWindow* aGlobalWindow);
+ void NotifyVRDisplayMounted(uint32_t aDisplayID);
+ void NotifyVRDisplayUnmounted(uint32_t aDisplayID);
+ void NotifyVRDisplayNavigation(uint32_t aDisplayID);
+ void NotifyVRDisplayRequested(uint32_t aDisplayID);
void NotifyVRDisplayConnect();
void NotifyVRDisplayDisconnect();
void NotifyVRDisplayPresentChange();
private:
// Weak pointer, instance is owned by mWindow.
nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
};
--- a/dom/vr/moz.build
+++ b/dom/vr/moz.build
@@ -1,21 +1,23 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS.mozilla.dom += [
'VRDisplay.h',
+ 'VRDisplayEvent.h',
'VREventObserver.h',
]
UNIFIED_SOURCES = [
'VRDisplay.cpp',
+ 'VRDisplayEvent.cpp',
'VREventObserver.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/base'
new file mode 100644
--- /dev/null
+++ b/dom/webidl/VRDisplayEvent.webidl
@@ -0,0 +1,23 @@
+/* -*- 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 VRDisplayEventReason {
+ "mounted",
+ "navigation",
+ "requested",
+ "unmounted",
+};
+
+dictionary VRDisplayEventInit : EventInit {
+ required VRDisplay display;
+ VRDisplayEventReason reason;
+};
+
+[Pref="dom.vr.enabled",
+ Constructor(DOMString type, VRDisplayEventInit eventInitDict)]
+interface VRDisplayEvent : Event {
+ readonly attribute VRDisplay display;
+ readonly attribute VRDisplayEventReason? reason;
+};
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -467,16 +467,20 @@ interface ChromeWindow {
};
partial interface Window {
[Pref="dom.vr.enabled"]
attribute EventHandler onvrdisplayconnect;
[Pref="dom.vr.enabled"]
attribute EventHandler onvrdisplaydisconnect;
[Pref="dom.vr.enabled"]
+ attribute EventHandler onvrdisplayactivate;
+ [Pref="dom.vr.enabled"]
+ attribute EventHandler onvrdisplaydeactivate;
+ [Pref="dom.vr.enabled"]
attribute EventHandler onvrdisplaypresentchange;
};
// https://webaudio.github.io/web-audio-api/#widl-Window-audioWorklet
partial interface Window {
[Pref="dom.audioWorklet.enabled", Throws, SameObject]
readonly attribute Worklet audioWorklet;
};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -568,16 +568,17 @@ WEBIDL_FILES = [
'URL.webidl',
'URLSearchParams.webidl',
'ValidityState.webidl',
'VideoPlaybackQuality.webidl',
'VideoStreamTrack.webidl',
'VideoTrack.webidl',
'VideoTrackList.webidl',
'VRDisplay.webidl',
+ 'VRDisplayEvent.webidl',
'VTTCue.webidl',
'VTTRegion.webidl',
'WaveShaperNode.webidl',
'WebAuthentication.webidl',
'WebComponents.webidl',
'WebGL2RenderingContext.webidl',
'WebGLRenderingContext.webidl',
'WebKitCSSMatrix.webidl',
--- a/gfx/vr/VRDisplayClient.cpp
+++ b/gfx/vr/VRDisplayClient.cpp
@@ -24,16 +24,17 @@
#include "VRManagerChild.h"
#include "VRLayerChild.h"
using namespace mozilla;
using namespace mozilla::gfx;
VRDisplayClient::VRDisplayClient(const VRDisplayInfo& aDisplayInfo)
: mDisplayInfo(aDisplayInfo)
+ , bLastEventWasMounted(false)
, bLastEventWasPresenting(false)
, mPresentationCount(0)
{
MOZ_COUNT_CTOR(VRDisplayClient);
}
VRDisplayClient::~VRDisplayClient() {
MOZ_COUNT_DTOR(VRDisplayClient);
@@ -109,16 +110,28 @@ VRDisplayClient::NotifyVsync()
mLastVSyncTime = TimeStamp::Now();
}
// Check if we need to trigger onVRDisplayPresentChange event
if (bLastEventWasPresenting != isPresenting) {
bLastEventWasPresenting = isPresenting;
vm->FireDOMVRDisplayPresentChangeEvent();
}
+
+ // Check if we need to trigger onvrdisplayactivate event
+ if (!bLastEventWasMounted && mDisplayInfo.mIsMounted) {
+ bLastEventWasMounted = true;
+ vm->FireDOMVRDisplayMountedEvent(mDisplayInfo.mDisplayID);
+ }
+
+ // Check if we need to trigger onvrdisplaydeactivate event
+ if (bLastEventWasMounted && !mDisplayInfo.mIsMounted) {
+ bLastEventWasMounted = false;
+ vm->FireDOMVRDisplayUnmountedEvent(mDisplayInfo.mDisplayID);
+ }
}
void
VRDisplayClient::NotifyVRVsync()
{
VRManagerChild *vm = VRManagerChild::Get();
vm->RunFrameRequestCallbacks();
mLastVSyncTime = TimeStamp::Now();
--- a/gfx/vr/VRDisplayClient.h
+++ b/gfx/vr/VRDisplayClient.h
@@ -44,16 +44,17 @@ public:
void NotifyDisconnected();
protected:
virtual ~VRDisplayClient();
VRDisplayInfo mDisplayInfo;
+ bool bLastEventWasMounted;
bool bLastEventWasPresenting;
TimeStamp mLastVSyncTime;
int mPresentationCount;
};
} // namespace gfx
} // namespace mozilla
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -74,19 +74,24 @@ enum class VRDisplayCapabilityFlags : ui
*/
Cap_LinearAcceleration = 1 << 6,
/**
* Cap_StageParameters is set if the VRDisplay is capable of room scale VR
* and can report the StageParameters to describe the space.
*/
Cap_StageParameters = 1 << 7,
/**
+ * Cap_MountDetection is set if the VRDisplay is capable of sensing when the
+ * user is wearing the device.
+ */
+ Cap_MountDetection = 1 << 8,
+ /**
* Cap_All used for validity checking during IPC serialization
*/
- Cap_All = (1 << 8) - 1
+ Cap_All = (1 << 9) - 1
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(VRDisplayCapabilityFlags)
struct VRFieldOfView {
VRFieldOfView() {}
VRFieldOfView(double up, double right, double down, double left)
: upDegrees(up), rightDegrees(right), downDegrees(down), leftDegrees(left)
@@ -132,16 +137,17 @@ struct VRDisplayInfo
uint32_t GetDisplayID() const { return mDisplayID; }
const nsCString& GetDisplayName() const { return mDisplayName; }
VRDisplayCapabilityFlags GetCapabilities() const { return mCapabilityFlags; }
const IntSize& SuggestedEyeResolution() const { return mEyeResolution; }
const Point3D& GetEyeTranslation(uint32_t whichEye) const { return mEyeTranslation[whichEye]; }
const VRFieldOfView& GetEyeFOV(uint32_t whichEye) const { return mEyeFOV[whichEye]; }
bool GetIsConnected() const { return mIsConnected; }
+ bool GetIsMounted() const { return mIsMounted; }
bool GetIsPresenting() const { return mIsPresenting; }
const Size& GetStageSize() const { return mStageSize; }
const Matrix4x4& GetSittingToStandingTransform() const { return mSittingToStandingTransform; }
enum Eye {
Eye_Left,
Eye_Right,
NumEyes
@@ -150,27 +156,29 @@ struct VRDisplayInfo
uint32_t mDisplayID;
VRDeviceType mType;
nsCString mDisplayName;
VRDisplayCapabilityFlags mCapabilityFlags;
VRFieldOfView mEyeFOV[VRDisplayInfo::NumEyes];
Point3D mEyeTranslation[VRDisplayInfo::NumEyes];
IntSize mEyeResolution;
bool mIsConnected;
+ bool mIsMounted;
bool mIsPresenting;
Size mStageSize;
Matrix4x4 mSittingToStandingTransform;
bool operator==(const VRDisplayInfo& other) const {
return mType == other.mType &&
mDisplayID == other.mDisplayID &&
mDisplayName == other.mDisplayName &&
mCapabilityFlags == other.mCapabilityFlags &&
mEyeResolution == other.mEyeResolution &&
mIsConnected == other.mIsConnected &&
+ mIsMounted == other.mIsMounted &&
mIsPresenting == other.mIsPresenting &&
mEyeFOV[0] == other.mEyeFOV[0] &&
mEyeFOV[1] == other.mEyeFOV[1] &&
mEyeTranslation[0] == other.mEyeTranslation[0] &&
mEyeTranslation[1] == other.mEyeTranslation[1] &&
mStageSize == other.mStageSize &&
mSittingToStandingTransform == other.mSittingToStandingTransform;
}
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -330,29 +330,31 @@ VRDisplayOculus::VRDisplayOculus(ovrSess
, mVertexBuffer(nullptr)
, mInputLayout(nullptr)
, mIsPresenting(false)
{
MOZ_COUNT_CTOR_INHERITED(VRDisplayOculus, VRDisplayHost);
mDisplayInfo.mDisplayName.AssignLiteral("Oculus VR HMD");
mDisplayInfo.mIsConnected = true;
+ mDisplayInfo.mIsMounted = false;
mDesc = ovr_GetHmdDesc(aSession);
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None;
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Orientation) {
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Orientation;
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
}
if (mDesc.AvailableTrackingCaps & ovrTrackingCap_Position) {
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Position;
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
}
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_External;
+ mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_MountDetection;
mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_Present;
mFOVPort[VRDisplayInfo::Eye_Left] = mDesc.DefaultEyeFov[ovrEye_Left];
mFOVPort[VRDisplayInfo::Eye_Right] = mDesc.DefaultEyeFov[ovrEye_Right];
mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Left] = FromFovPort(mFOVPort[VRDisplayInfo::Eye_Left]);
mDisplayInfo.mEyeFOV[VRDisplayInfo::Eye_Right] = FromFovPort(mFOVPort[VRDisplayInfo::Eye_Right]);
@@ -464,16 +466,17 @@ VRDisplayOculus::GetSensorState(double t
result.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
result.linearAcceleration[0] = pose.LinearAcceleration.x;
result.linearAcceleration[1] = pose.LinearAcceleration.y;
result.linearAcceleration[2] = pose.LinearAcceleration.z;
}
result.flags |= VRDisplayCapabilityFlags::Cap_External;
+ result.flags |= VRDisplayCapabilityFlags::Cap_MountDetection;
result.flags |= VRDisplayCapabilityFlags::Cap_Present;
return result;
}
void
VRDisplayOculus::StartPresentation()
{
@@ -932,9 +935,10 @@ VRDisplayOculus::SubmitFrame(TextureSour
}
void
VRDisplayOculus::NotifyVSync()
{
ovrSessionStatus sessionStatus;
ovrResult ovr = ovr_GetSessionStatus(mSession, &sessionStatus);
mDisplayInfo.mIsConnected = (ovr == ovrSuccess && sessionStatus.HmdPresent);
+ mDisplayInfo.mIsMounted = (ovr == ovrSuccess && sessionStatus.HmdMounted);
}
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -132,23 +132,30 @@ VRDisplayOpenVR::VRDisplayOpenVR(::vr::I
, mVRChaperone(aVRChaperone)
, mVRCompositor(aVRCompositor)
, mIsPresenting(false)
{
MOZ_COUNT_CTOR_INHERITED(VRDisplayOpenVR, VRDisplayHost);
mDisplayInfo.mDisplayName.AssignLiteral("OpenVR HMD");
mDisplayInfo.mIsConnected = true;
+ mDisplayInfo.mIsMounted = false;
mDisplayInfo.mCapabilityFlags = VRDisplayCapabilityFlags::Cap_None |
VRDisplayCapabilityFlags::Cap_Orientation |
VRDisplayCapabilityFlags::Cap_Position |
VRDisplayCapabilityFlags::Cap_External |
VRDisplayCapabilityFlags::Cap_Present |
VRDisplayCapabilityFlags::Cap_StageParameters;
+ ::vr::ETrackedPropertyError err;
+ bool bHasProximitySensor = mVRSystem->GetBoolTrackedDeviceProperty(::vr::k_unTrackedDeviceIndex_Hmd, ::vr::Prop_ContainsProximitySensor_Bool, &err);
+ if (err == ::vr::TrackedProp_Success && bHasProximitySensor) {
+ mDisplayInfo.mCapabilityFlags |= VRDisplayCapabilityFlags::Cap_MountDetection;
+ }
+
mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
uint32_t w, h;
mVRSystem->GetRecommendedRenderTargetSize(&w, &h);
mDisplayInfo.mEyeResolution.width = w;
mDisplayInfo.mEyeResolution.height = h;
// SteamVR gives the application a single FOV to use; it's not configurable as with Oculus
@@ -253,25 +260,41 @@ VRDisplayOpenVR::GetSensorState()
}
VRHMDSensorState
VRDisplayOpenVR::GetImmediateSensorState()
{
return GetSensorState(0.0f);
}
+void
+VRDisplayOpenVR::PollEvents()
+{
+ ::vr::VREvent_t event;
+ while (mVRSystem->PollNextEvent(&event, sizeof(event))) {
+ if (event.trackedDeviceIndex == ::vr::k_unTrackedDeviceIndex_Hmd) {
+ switch (event.eventType) {
+ case ::vr::VREvent_TrackedDeviceUserInteractionStarted:
+ mDisplayInfo.mIsMounted = true;
+ break;
+ case ::vr::VREvent_TrackedDeviceUserInteractionEnded:
+ mDisplayInfo.mIsMounted = false;
+ break;
+ default:
+ // ignore
+ break;
+ }
+ }
+ }
+}
+
VRHMDSensorState
VRDisplayOpenVR::GetSensorState(double timeOffset)
{
- {
- ::vr::VREvent_t event;
- while (mVRSystem->PollNextEvent(&event, sizeof(event))) {
- // ignore
- }
- }
+ PollEvents();
::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount];
// Note: We *must* call WaitGetPoses in order for any rendering to happen at all
mVRCompositor->WaitGetPoses(poses, ::vr::k_unMaxTrackedDeviceCount, nullptr, 0);
VRHMDSensorState result;
result.Clear();
result.timestamp = PR_Now();
@@ -387,16 +410,19 @@ VRDisplayOpenVR::SubmitFrame(TextureSour
#endif
void
VRDisplayOpenVR::NotifyVSync()
{
// We update mIsConneced once per frame.
mDisplayInfo.mIsConnected = vr_IsHmdPresent();
+
+ // Make sure we respond to OpenVR events even when not presenting
+ PollEvents();
}
VRSystemManagerOpenVR::VRSystemManagerOpenVR()
: mVRSystem(nullptr), mOpenVRInstalled(false)
{
}
/*static*/ already_AddRefed<VRSystemManagerOpenVR>
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -61,16 +61,17 @@ protected:
// not owned by us; global from OpenVR
::vr::IVRSystem *mVRSystem;
::vr::IVRChaperone *mVRChaperone;
::vr::IVRCompositor *mVRCompositor;
bool mIsPresenting;
void UpdateStageParameters();
+ void PollEvents();
};
class VRControllerOpenVR : public VRControllerHost
{
public:
explicit VRControllerOpenVR();
void SetTrackedIndex(uint32_t aTrackedIndex);
uint32_t GetTrackedIndex();
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -501,16 +501,32 @@ VRManagerChild::RunFrameRequestCallbacks
callbacks.AppendElements(mFrameRequestCallbacks);
mFrameRequestCallbacks.Clear();
for (auto& callback : callbacks) {
callback.mCallback->Call(timeStamp);
}
}
void
+VRManagerChild::FireDOMVRDisplayMountedEvent(uint32_t aDisplayID)
+{
+ nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(this,
+ &VRManagerChild::FireDOMVRDisplayMountedEventInternal,
+ aDisplayID));
+}
+
+void
+VRManagerChild::FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID)
+{
+ nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(this,
+ &VRManagerChild::FireDOMVRDisplayUnmountedEventInternal,
+ aDisplayID));
+}
+
+void
VRManagerChild::FireDOMVRDisplayConnectEvent()
{
nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
&VRManagerChild::FireDOMVRDisplayConnectEventInternal));
}
void
VRManagerChild::FireDOMVRDisplayDisconnectEvent()
@@ -522,16 +538,32 @@ VRManagerChild::FireDOMVRDisplayDisconne
void
VRManagerChild::FireDOMVRDisplayPresentChangeEvent()
{
nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
&VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal));
}
void
+VRManagerChild::FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID)
+{
+ for (auto& listener : mListeners) {
+ listener->NotifyVRDisplayMounted(aDisplayID);
+ }
+}
+
+void
+VRManagerChild::FireDOMVRDisplayUnmountedEventInternal(uint32_t aDisplayID)
+{
+ for (auto& listener : mListeners) {
+ listener->NotifyVRDisplayUnmounted(aDisplayID);
+ }
+}
+
+void
VRManagerChild::FireDOMVRDisplayConnectEventInternal()
{
for (auto& listener : mListeners) {
listener->NotifyVRDisplayConnect();
}
}
void
--- a/gfx/vr/ipc/VRManagerChild.h
+++ b/gfx/vr/ipc/VRManagerChild.h
@@ -75,16 +75,18 @@ public:
virtual base::ProcessId GetParentPid() const override { return OtherPid(); }
nsresult ScheduleFrameRequestCallback(mozilla::dom::FrameRequestCallback& aCallback,
int32_t *aHandle);
void CancelFrameRequestCallback(int32_t aHandle);
void RunFrameRequestCallbacks();
void UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates);
+ void FireDOMVRDisplayMountedEvent(uint32_t aDisplayID);
+ void FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID);
void FireDOMVRDisplayConnectEvent();
void FireDOMVRDisplayDisconnectEvent();
void FireDOMVRDisplayPresentChangeEvent();
virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
protected:
explicit VRManagerChild();
@@ -133,16 +135,18 @@ protected:
{
return OtherPid() == base::GetCurrentProcId();
}
friend class layers::CompositorBridgeChild;
private:
+ void FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID);
+ void FireDOMVRDisplayUnmountedEventInternal(uint32_t aDisplayID);
void FireDOMVRDisplayConnectEventInternal();
void FireDOMVRDisplayDisconnectEventInternal();
void FireDOMVRDisplayPresentChangeEventInternal();
/**
* Notify id of Texture When host side end its use. Transaction id is used to
* make sure if there is no newer usage.
*/
void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
--- a/gfx/vr/ipc/VRMessageUtils.h
+++ b/gfx/vr/ipc/VRMessageUtils.h
@@ -34,16 +34,17 @@ struct ParamTraits<mozilla::gfx::VRDispl
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mType);
WriteParam(aMsg, aParam.mDisplayID);
WriteParam(aMsg, aParam.mDisplayName);
WriteParam(aMsg, aParam.mCapabilityFlags);
WriteParam(aMsg, aParam.mEyeResolution);
WriteParam(aMsg, aParam.mIsConnected);
+ WriteParam(aMsg, aParam.mIsMounted);
WriteParam(aMsg, aParam.mIsPresenting);
WriteParam(aMsg, aParam.mStageSize);
WriteParam(aMsg, aParam.mSittingToStandingTransform);
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
WriteParam(aMsg, aParam.mEyeFOV[i]);
WriteParam(aMsg, aParam.mEyeTranslation[i]);
}
}
@@ -51,16 +52,17 @@ struct ParamTraits<mozilla::gfx::VRDispl
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->mType)) ||
!ReadParam(aMsg, aIter, &(aResult->mDisplayID)) ||
!ReadParam(aMsg, aIter, &(aResult->mDisplayName)) ||
!ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
!ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
!ReadParam(aMsg, aIter, &(aResult->mIsConnected)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mIsMounted)) ||
!ReadParam(aMsg, aIter, &(aResult->mIsPresenting)) ||
!ReadParam(aMsg, aIter, &(aResult->mStageSize)) ||
!ReadParam(aMsg, aIter, &(aResult->mSittingToStandingTransform))) {
return false;
}
for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
if (!ReadParam(aMsg, aIter, &(aResult->mEyeFOV[i])) ||
!ReadParam(aMsg, aIter, &(aResult->mEyeTranslation[i]))) {
--- a/widget/EventMessageList.h
+++ b/widget/EventMessageList.h
@@ -373,16 +373,18 @@ NS_EVENT_MESSAGE(eDeviceMotion)
NS_EVENT_MESSAGE(eDeviceProximity)
NS_EVENT_MESSAGE(eUserProximity)
NS_EVENT_MESSAGE(eDeviceLight)
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
NS_EVENT_MESSAGE(eOrientationChange)
#endif
// WebVR events
+NS_EVENT_MESSAGE(eVRDisplayActivate)
+NS_EVENT_MESSAGE(eVRDisplayDeactivate)
NS_EVENT_MESSAGE(eVRDisplayConnect)
NS_EVENT_MESSAGE(eVRDisplayDisconnect)
NS_EVENT_MESSAGE(eVRDisplayPresentChange)
NS_EVENT_MESSAGE(eShow)
// Fullscreen DOM API
NS_EVENT_MESSAGE(eFullscreenChange)