Bug 1335606 - Add 'display' value to Navigator.vrdisplayconnect, Navigator.vrdisplaydisconnect, and Navigator.vrdisplaypresentchange events r=smaug

MozReview-Commit-ID: FLZ7u98mqqi

--HG--
extra : rebase_source : dd783f3c085efc50c4114ea45ac3f695670079fd
This commit is contained in:
Kearwood Gilbert 2017-02-14 11:21:09 -08:00
Родитель 2fb7487fe1
Коммит 9d394c09bb
7 изменённых файлов: 197 добавлений и 66 удалений

Просмотреть файл

@ -10444,8 +10444,10 @@ void
nsGlobalWindow::DisableVRUpdates()
{
MOZ_ASSERT(IsInnerWindow());
mVREventObserver = nullptr;
if (mVREventObserver) {
mVREventObserver->DisconnectFromOwner();
mVREventObserver = nullptr;
}
}
void
@ -13472,6 +13474,8 @@ void
nsGlobalWindow::DispatchVRDisplayActivate(uint32_t aDisplayID,
mozilla::dom::VRDisplayEventReason aReason)
{
// Search for the display identified with aDisplayID and fire the
// event if found.
for (auto display : mVRDisplays) {
if (display->DisplayId() == aDisplayID
&& !display->IsAnyPresenting()) {
@ -13479,7 +13483,7 @@ nsGlobalWindow::DispatchVRDisplayActivate(uint32_t aDisplayID,
// display already.
VRDisplayEventInit init;
init.mBubbles = true;
init.mBubbles = false;
init.mCancelable = false;
init.mDisplay = display;
init.mReason.Construct(aReason);
@ -13494,7 +13498,9 @@ nsGlobalWindow::DispatchVRDisplayActivate(uint32_t aDisplayID,
event->SetTrusted(true);
bool defaultActionEnabled;
Unused << DispatchEvent(event, &defaultActionEnabled);
break;
// Once we dispatch the event, we must not access any members as an event
// listener can do anything, including closing windows.
return;
}
}
}
@ -13503,13 +13509,15 @@ void
nsGlobalWindow::DispatchVRDisplayDeactivate(uint32_t aDisplayID,
mozilla::dom::VRDisplayEventReason aReason)
{
// Search for the display identified with aDisplayID and fire the
// event if found.
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.mBubbles = false;
init.mCancelable = false;
init.mDisplay = display;
init.mReason.Construct(aReason);
@ -13518,9 +13526,96 @@ nsGlobalWindow::DispatchVRDisplayDeactivate(uint32_t aDisplayID,
VRDisplayEvent::Constructor(this,
NS_LITERAL_STRING("vrdisplaydeactivate"),
init);
event->SetTrusted(true);
bool defaultActionEnabled;
Unused << DispatchEvent(event, &defaultActionEnabled);
break;
// Once we dispatch the event, we must not access any members as an event
// listener can do anything, including closing windows.
return;
}
}
}
void
nsGlobalWindow::DispatchVRDisplayConnect(uint32_t aDisplayID)
{
// Search for the display identified with aDisplayID and fire the
// event if found.
for (auto display : mVRDisplays) {
if (display->DisplayId() == aDisplayID) {
// Fire event even if not presenting to the display.
VRDisplayEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mDisplay = display;
// VRDisplayEvent.reason is not set for vrdisplayconnect
RefPtr<VRDisplayEvent> event =
VRDisplayEvent::Constructor(this,
NS_LITERAL_STRING("vrdisplayconnect"),
init);
event->SetTrusted(true);
bool defaultActionEnabled;
Unused << DispatchEvent(event, &defaultActionEnabled);
// Once we dispatch the event, we must not access any members as an event
// listener can do anything, including closing windows.
return;
}
}
}
void
nsGlobalWindow::DispatchVRDisplayDisconnect(uint32_t aDisplayID)
{
// Search for the display identified with aDisplayID and fire the
// event if found.
for (auto display : mVRDisplays) {
if (display->DisplayId() == aDisplayID) {
// Fire event even if not presenting to the display.
VRDisplayEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mDisplay = display;
// VRDisplayEvent.reason is not set for vrdisplaydisconnect
RefPtr<VRDisplayEvent> event =
VRDisplayEvent::Constructor(this,
NS_LITERAL_STRING("vrdisplaydisconnect"),
init);
event->SetTrusted(true);
bool defaultActionEnabled;
Unused << DispatchEvent(event, &defaultActionEnabled);
// Once we dispatch the event, we must not access any members as an event
// listener can do anything, including closing windows.
return;
}
}
}
void
nsGlobalWindow::DispatchVRDisplayPresentChange(uint32_t aDisplayID)
{
// Search for the display identified with aDisplayID and fire the
// event if found.
for (auto display : mVRDisplays) {
if (display->DisplayId() == aDisplayID) {
// Fire event even if not presenting to the display.
VRDisplayEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mDisplay = display;
// VRDisplayEvent.reason is not set for vrdisplaypresentchange
RefPtr<VRDisplayEvent> event =
VRDisplayEvent::Constructor(this,
NS_LITERAL_STRING("vrdisplaypresentchange"),
init);
event->SetTrusted(true);
bool defaultActionEnabled;
Unused << DispatchEvent(event, &defaultActionEnabled);
// Once we dispatch the event, we must not access any members as an event
// listener can do anything, including closing windows.
return;
}
}
}

Просмотреть файл

@ -768,6 +768,9 @@ public:
mozilla::dom::VRDisplayEventReason aReason);
void DispatchVRDisplayDeactivate(uint32_t aDisplayID,
mozilla::dom::VRDisplayEventReason aReason);
void DispatchVRDisplayConnect(uint32_t aDisplayID);
void DispatchVRDisplayDisconnect(uint32_t aDisplayID);
void DispatchVRDisplayPresentChange(uint32_t aDisplayID);
#define EVENT(name_, id_, type_, struct_) \
mozilla::dom::EventHandlerNonNull* GetOn##name_() \
@ -2027,7 +2030,7 @@ protected:
// The VR Displays for this window
nsTArray<RefPtr<mozilla::dom::VRDisplay>> mVRDisplays;
nsAutoPtr<mozilla::dom::VREventObserver> mVREventObserver;
RefPtr<mozilla::dom::VREventObserver> mVREventObserver;
friend class nsDOMScriptableHelper;
friend class nsDOMWindowUtils;

Просмотреть файл

@ -33,6 +33,18 @@ VREventObserver::VREventObserver(nsGlobalWindow* aGlobalWindow)
VREventObserver::~VREventObserver()
{
DisconnectFromOwner();
}
void
VREventObserver::DisconnectFromOwner()
{
// In the event that nsGlobalWindow is deallocated, VREventObserver may
// still be AddRef'ed elsewhere. Ensure that we don't UAF by
// dereferencing mWindow.
mWindow = nullptr;
// Unregister from VRManagerChild
VRManagerChild* vmc = VRManagerChild::Get();
if (vmc) {
vmc->RemoveListener(this);
@ -42,7 +54,7 @@ VREventObserver::~VREventObserver()
void
VREventObserver::NotifyVRDisplayMounted(uint32_t aDisplayID)
{
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->DispatchVRDisplayActivate(aDisplayID,
VRDisplayEventReason::Mounted);
@ -52,7 +64,7 @@ VREventObserver::NotifyVRDisplayMounted(uint32_t aDisplayID)
void
VREventObserver::NotifyVRDisplayNavigation(uint32_t aDisplayID)
{
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->DispatchVRDisplayActivate(aDisplayID,
VRDisplayEventReason::Navigation);
@ -62,7 +74,7 @@ VREventObserver::NotifyVRDisplayNavigation(uint32_t aDisplayID)
void
VREventObserver::NotifyVRDisplayRequested(uint32_t aDisplayID)
{
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->DispatchVRDisplayActivate(aDisplayID,
VRDisplayEventReason::Requested);
@ -72,7 +84,7 @@ VREventObserver::NotifyVRDisplayRequested(uint32_t aDisplayID)
void
VREventObserver::NotifyVRDisplayUnmounted(uint32_t aDisplayID)
{
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->DispatchVRDisplayDeactivate(aDisplayID,
VRDisplayEventReason::Unmounted);
@ -80,39 +92,36 @@ VREventObserver::NotifyVRDisplayUnmounted(uint32_t aDisplayID)
}
void
VREventObserver::NotifyVRDisplayConnect()
VREventObserver::NotifyVRDisplayConnect(uint32_t aDisplayID)
{
/**
* 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()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->GetOuterWindow()->DispatchCustomEvent(
NS_LITERAL_STRING("vrdisplayconnected"));
mWindow->DispatchVRDisplayConnect(aDisplayID);
}
}
void
VREventObserver::NotifyVRDisplayDisconnect()
VREventObserver::NotifyVRDisplayDisconnect(uint32_t aDisplayID)
{
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
mWindow->NotifyActiveVRDisplaysChanged();
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->GetOuterWindow()->DispatchCustomEvent(
NS_LITERAL_STRING("vrdisplaydisconnected"));
mWindow->DispatchVRDisplayDisconnect(aDisplayID);
}
}
void
VREventObserver::NotifyVRDisplayPresentChange()
VREventObserver::NotifyVRDisplayPresentChange(uint32_t aDisplayID)
{
if (mWindow->AsInner()->IsCurrentInnerWindow()) {
if (mWindow && mWindow->AsInner()->IsCurrentInnerWindow()) {
mWindow->NotifyActiveVRDisplaysChanged();
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mWindow->GetOuterWindow()->DispatchCustomEvent(
NS_LITERAL_STRING("vrdisplaypresentchange"));
mWindow->DispatchVRDisplayPresentChange(aDisplayID);
}
}

Просмотреть файл

@ -8,6 +8,7 @@
#define mozilla_dom_VREventObserver_h
#include "mozilla/dom/VRDisplayEventBinding.h"
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
class nsGlobalWindow;
@ -17,18 +18,22 @@ namespace dom {
class VREventObserver final
{
public:
~VREventObserver();
NS_INLINE_DECL_REFCOUNTING(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();
void NotifyVRDisplayConnect(uint32_t aDisplayID);
void NotifyVRDisplayDisconnect(uint32_t aDisplayID);
void NotifyVRDisplayPresentChange(uint32_t aDisplayID);
void DisconnectFromOwner();
private:
~VREventObserver();
// Weak pointer, instance is owned by mWindow.
nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
};

Просмотреть файл

@ -113,7 +113,7 @@ VRDisplayClient::NotifyVsync()
// Check if we need to trigger onVRDisplayPresentChange event
if (bLastEventWasPresenting != isPresenting) {
bLastEventWasPresenting = isPresenting;
vm->FireDOMVRDisplayPresentChangeEvent();
vm->FireDOMVRDisplayPresentChangeEvent(mDisplayInfo.mDisplayID);
}
// Check if we need to trigger onvrdisplayactivate event

Просмотреть файл

@ -203,8 +203,8 @@ VRManagerChild::DeallocPVRLayerChild(PVRLayerChild* actor)
void
VRManagerChild::UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates)
{
bool bDisplayConnected = false;
bool bDisplayDisconnected = false;
nsTArray<uint32_t> disconnectedDisplays;
nsTArray<uint32_t> connectedDisplays;
// Check if any displays have been disconnected
for (auto& display : mDisplays) {
@ -217,7 +217,7 @@ VRManagerChild::UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates)
}
if (!found) {
display->NotifyDisconnected();
bDisplayDisconnected = true;
disconnectedDisplays.AppendElement(display->GetDisplayInfo().GetDisplayID());
}
}
@ -230,10 +230,10 @@ VRManagerChild::UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates)
const VRDisplayInfo& prevInfo = display->GetDisplayInfo();
if (prevInfo.GetDisplayID() == displayUpdate.GetDisplayID()) {
if (displayUpdate.GetIsConnected() && !prevInfo.GetIsConnected()) {
bDisplayConnected = true;
connectedDisplays.AppendElement(displayUpdate.GetDisplayID());
}
if (!displayUpdate.GetIsConnected() && prevInfo.GetIsConnected()) {
bDisplayDisconnected = true;
disconnectedDisplays.AppendElement(displayUpdate.GetDisplayID());
}
display->UpdateDisplayInfo(displayUpdate);
displays.AppendElement(display);
@ -243,17 +243,19 @@ VRManagerChild::UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates)
}
if (isNewDisplay) {
displays.AppendElement(new VRDisplayClient(displayUpdate));
bDisplayConnected = true;
connectedDisplays.AppendElement(displayUpdate.GetDisplayID());
}
}
mDisplays = displays;
if (bDisplayConnected) {
FireDOMVRDisplayConnectEvent();
// We wish to fire the events only after mDisplays is updated
for (uint32_t displayID : disconnectedDisplays) {
FireDOMVRDisplayDisconnectEvent(displayID);
}
if (bDisplayDisconnected) {
FireDOMVRDisplayDisconnectEvent();
for (uint32_t displayID : connectedDisplays) {
FireDOMVRDisplayConnectEvent(displayID);
}
mDisplaysInitialized = true;
@ -522,30 +524,36 @@ VRManagerChild::FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID)
}
void
VRManagerChild::FireDOMVRDisplayConnectEvent()
VRManagerChild::FireDOMVRDisplayConnectEvent(uint32_t aDisplayID)
{
nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
&VRManagerChild::FireDOMVRDisplayConnectEventInternal));
nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(this,
&VRManagerChild::FireDOMVRDisplayConnectEventInternal,
aDisplayID));
}
void
VRManagerChild::FireDOMVRDisplayDisconnectEvent()
VRManagerChild::FireDOMVRDisplayDisconnectEvent(uint32_t aDisplayID)
{
nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
&VRManagerChild::FireDOMVRDisplayDisconnectEventInternal));
nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(this,
&VRManagerChild::FireDOMVRDisplayDisconnectEventInternal,
aDisplayID));
}
void
VRManagerChild::FireDOMVRDisplayPresentChangeEvent()
VRManagerChild::FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID)
{
nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
&VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal));
nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(this,
&VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal,
aDisplayID));
}
void
VRManagerChild::FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID)
{
for (auto& listener : mListeners) {
// Iterate over a copy of mListeners, as dispatched events may modify it.
nsTArray<RefPtr<dom::VREventObserver>> listeners;
listeners = mListeners;
for (auto& listener : listeners) {
listener->NotifyVRDisplayMounted(aDisplayID);
}
}
@ -553,32 +561,44 @@ VRManagerChild::FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID)
void
VRManagerChild::FireDOMVRDisplayUnmountedEventInternal(uint32_t aDisplayID)
{
for (auto& listener : mListeners) {
// Iterate over a copy of mListeners, as dispatched events may modify it.
nsTArray<RefPtr<dom::VREventObserver>> listeners;
listeners = mListeners;
for (auto& listener : listeners) {
listener->NotifyVRDisplayUnmounted(aDisplayID);
}
}
void
VRManagerChild::FireDOMVRDisplayConnectEventInternal()
VRManagerChild::FireDOMVRDisplayConnectEventInternal(uint32_t aDisplayID)
{
for (auto& listener : mListeners) {
listener->NotifyVRDisplayConnect();
// Iterate over a copy of mListeners, as dispatched events may modify it.
nsTArray<RefPtr<dom::VREventObserver>> listeners;
listeners = mListeners;
for (auto& listener : listeners) {
listener->NotifyVRDisplayConnect(aDisplayID);
}
}
void
VRManagerChild::FireDOMVRDisplayDisconnectEventInternal()
VRManagerChild::FireDOMVRDisplayDisconnectEventInternal(uint32_t aDisplayID)
{
for (auto& listener : mListeners) {
listener->NotifyVRDisplayDisconnect();
// Iterate over a copy of mListeners, as dispatched events may modify it.
nsTArray<RefPtr<dom::VREventObserver>> listeners;
listeners = mListeners;
for (auto& listener : listeners) {
listener->NotifyVRDisplayDisconnect(aDisplayID);
}
}
void
VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal()
VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal(uint32_t aDisplayID)
{
for (auto& listener : mListeners) {
listener->NotifyVRDisplayPresentChange();
// Iterate over a copy of mListeners, as dispatched events may modify it.
nsTArray<RefPtr<dom::VREventObserver>> listeners;
listeners = mListeners;
for (auto& listener : listeners) {
listener->NotifyVRDisplayPresentChange(aDisplayID);
}
}

Просмотреть файл

@ -81,9 +81,9 @@ public:
void UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates);
void FireDOMVRDisplayMountedEvent(uint32_t aDisplayID);
void FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID);
void FireDOMVRDisplayConnectEvent();
void FireDOMVRDisplayDisconnectEvent();
void FireDOMVRDisplayPresentChangeEvent();
void FireDOMVRDisplayConnectEvent(uint32_t aDisplayID);
void FireDOMVRDisplayDisconnectEvent(uint32_t aDisplayID);
void FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID);
virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
@ -141,9 +141,9 @@ private:
void FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID);
void FireDOMVRDisplayUnmountedEventInternal(uint32_t aDisplayID);
void FireDOMVRDisplayConnectEventInternal();
void FireDOMVRDisplayDisconnectEventInternal();
void FireDOMVRDisplayPresentChangeEventInternal();
void FireDOMVRDisplayConnectEventInternal(uint32_t aDisplayID);
void FireDOMVRDisplayDisconnectEventInternal(uint32_t aDisplayID);
void FireDOMVRDisplayPresentChangeEventInternal(uint32_t aDisplayID);
/**
* Notify id of Texture When host side end its use. Transaction id is used to
* make sure if there is no newer usage.
@ -167,8 +167,7 @@ private:
int32_t mFrameRequestCallbackCounter;
mozilla::TimeStamp mStartTimeStamp;
// Array of Weak pointers, instance is owned by nsGlobalWindow::mVREventObserver.
nsTArray<dom::VREventObserver*> mListeners;
nsTArray<RefPtr<dom::VREventObserver>> mListeners;
/**
* Hold TextureClients refs until end of their usages on host side.