mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 20:35:50 +00:00
Bug 1336763 - Add a hasBeforeUnload attribute to nsITabParent. r=Ehsan
This will return true if any of the frames loaded in the associated TabChild have set at least one onbeforeunload event handler. If those handlers are all removed, or all of the documents with onbeforeunload event handlers are unloaded, this becomes false again. Note that subframes that are sandboxed without the allow-modals permission will not affect the hasBeforeUnload attribute, since those iframes should never cause the beforeunload confirmation dialog to display. MozReview-Commit-ID: 8b0gBYWwMDn --HG-- extra : rebase_source : 69f3b692d6e73f6277e6982aad02bcd1ebdd8acf
This commit is contained in:
parent
750b3f5764
commit
cf1d141d21
@ -1570,7 +1570,8 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
mIsValidatingTabGroup(false),
|
||||
#endif
|
||||
mCanSkipCCGeneration(0),
|
||||
mAutoActivateVRDisplayID(0)
|
||||
mAutoActivateVRDisplayID(0),
|
||||
mBeforeUnloadListenerCount(0)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
@ -1607,6 +1608,13 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
MOZ_ASSERT(IsFrozen());
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
|
||||
if (docShell) {
|
||||
mTabChild = docShell->GetTabChild();
|
||||
}
|
||||
}
|
||||
|
||||
// We could have failed the first time through trying
|
||||
// to create the entropy collector, so we should
|
||||
// try to get one until we succeed.
|
||||
@ -2122,6 +2130,12 @@ nsGlobalWindow::FreeInnerObjects()
|
||||
DisableVRUpdates();
|
||||
mHasVREvents = false;
|
||||
mVRDisplays.Clear();
|
||||
|
||||
if (mTabChild) {
|
||||
while (mBeforeUnloadListenerCount-- > 0) {
|
||||
mTabChild->BeforeUnloadRemoved();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
@ -2261,6 +2275,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
|
||||
@ -2344,6 +2359,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
|
||||
@ -13411,6 +13427,15 @@ nsGlobalWindow::EventListenerAdded(nsIAtom* aType)
|
||||
NotifyVREventListenerAdded();
|
||||
}
|
||||
|
||||
if (aType == nsGkAtoms::onbeforeunload &&
|
||||
mTabChild &&
|
||||
(!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
mBeforeUnloadListenerCount++;
|
||||
MOZ_ASSERT(mBeforeUnloadListenerCount > 0);
|
||||
mTabChild->BeforeUnloadAdded();
|
||||
}
|
||||
|
||||
// We need to initialize localStorage in order to receive notifications.
|
||||
if (aType == nsGkAtoms::onstorage) {
|
||||
ErrorResult rv;
|
||||
@ -13419,6 +13444,19 @@ nsGlobalWindow::EventListenerAdded(nsIAtom* aType)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::EventListenerRemoved(nsIAtom* aType)
|
||||
{
|
||||
if (aType == nsGkAtoms::onbeforeunload &&
|
||||
mTabChild &&
|
||||
(!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS))) {
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
mBeforeUnloadListenerCount--;
|
||||
MOZ_ASSERT(mBeforeUnloadListenerCount >= 0);
|
||||
mTabChild->BeforeUnloadRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::NotifyVREventListenerAdded()
|
||||
{
|
||||
|
@ -87,6 +87,7 @@ class nsIControllers;
|
||||
class nsIJSID;
|
||||
class nsIScriptContext;
|
||||
class nsIScriptTimeoutHandler;
|
||||
class nsITabChild;
|
||||
class nsITimeoutHandler;
|
||||
class nsIWebBrowserChrome;
|
||||
class mozIDOMWindowProxy;
|
||||
@ -459,6 +460,8 @@ public:
|
||||
|
||||
using EventTarget::EventListenerAdded;
|
||||
virtual void EventListenerAdded(nsIAtom* aType) override;
|
||||
using EventTarget::EventListenerRemoved;
|
||||
virtual void EventListenerRemoved(nsIAtom* aType) override;
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
@ -1952,6 +1955,8 @@ protected:
|
||||
|
||||
// These member variables are used on both inner and the outer windows.
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
// mTabChild is only ever populated in the content process.
|
||||
nsCOMPtr<nsITabChild> mTabChild;
|
||||
|
||||
uint32_t mSuspendDepth;
|
||||
uint32_t mFreezeDepth;
|
||||
@ -2040,6 +2045,7 @@ protected:
|
||||
// after loading. The value is the ID of the VRDisplay that content should
|
||||
// begin presentation on.
|
||||
uint32_t mAutoActivateVRDisplayID; // Outer windows only
|
||||
int64_t mBeforeUnloadListenerCount; // Inner windows only
|
||||
|
||||
#ifdef ENABLE_INTL_API
|
||||
RefPtr<mozilla::dom::IntlUtils> mIntlUtils;
|
||||
|
@ -34,5 +34,8 @@ interface nsITabChild : nsISupports
|
||||
[array, size_is(linksCount)] in nsIDroppedLinkItem links);
|
||||
|
||||
readonly attribute uint64_t tabId;
|
||||
|
||||
[noscript, notxpcom] void beforeUnloadAdded();
|
||||
[noscript, notxpcom] void beforeUnloadRemoved();
|
||||
};
|
||||
|
||||
|
@ -69,4 +69,10 @@ interface nsITabParent : nsISupports
|
||||
* permissions required to load a document with the given principal.
|
||||
*/
|
||||
void transmitPermissionsForPrincipal(in nsIPrincipal aPrincipal);
|
||||
|
||||
/**
|
||||
* True if any of the frames loaded in the TabChild have registered
|
||||
* an onbeforeunload event handler.
|
||||
*/
|
||||
readonly attribute boolean hasBeforeUnload;
|
||||
};
|
||||
|
@ -555,6 +555,8 @@ parent:
|
||||
|
||||
async AccessKeyNotHandled(WidgetKeyboardEvent event);
|
||||
|
||||
async SetHasBeforeUnload(bool aHasBeforeUnload);
|
||||
|
||||
child:
|
||||
async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
|
||||
|
||||
|
@ -379,6 +379,7 @@ TabChild::TabChild(nsIContentChild* aManager,
|
||||
, mChromeFlags(aChromeFlags)
|
||||
, mActiveSuppressDisplayport(0)
|
||||
, mLayersId(0)
|
||||
, mBeforeUnloadListeners(0)
|
||||
, mLayersConnected(true)
|
||||
, mDidFakeShow(false)
|
||||
, mNotified(false)
|
||||
@ -3315,6 +3316,28 @@ TabChild::ForcePaint(uint64_t aLayerObserverEpoch)
|
||||
RecvSetDocShellIsActive(true, false, aLayerObserverEpoch);
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::BeforeUnloadAdded()
|
||||
{
|
||||
if (mBeforeUnloadListeners == 0) {
|
||||
SendSetHasBeforeUnload(true);
|
||||
}
|
||||
|
||||
mBeforeUnloadListeners++;
|
||||
MOZ_ASSERT(mBeforeUnloadListeners >= 0);
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::BeforeUnloadRemoved()
|
||||
{
|
||||
mBeforeUnloadListeners--;
|
||||
MOZ_ASSERT(mBeforeUnloadListeners >= 0);
|
||||
|
||||
if (mBeforeUnloadListeners == 0) {
|
||||
SendSetHasBeforeUnload(false);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsISHistory>
|
||||
TabChild::GetRelatedSHistory()
|
||||
{
|
||||
|
@ -780,6 +780,7 @@ private:
|
||||
uint32_t mChromeFlags;
|
||||
int32_t mActiveSuppressDisplayport;
|
||||
uint64_t mLayersId;
|
||||
int64_t mBeforeUnloadListeners;
|
||||
CSSRect mUnscaledOuterRect;
|
||||
nscolor mLastBackgroundColor;
|
||||
bool mLayersConnected;
|
||||
|
@ -168,6 +168,7 @@ TabParent::TabParent(nsIContentParent* aManager,
|
||||
, mLayerTreeEpoch(0)
|
||||
, mPreserveLayers(false)
|
||||
, mHasPresented(false)
|
||||
, mHasBeforeUnload(false)
|
||||
{
|
||||
MOZ_ASSERT(aManager);
|
||||
}
|
||||
@ -2025,6 +2026,13 @@ TabParent::RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent)
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
TabParent::RecvSetHasBeforeUnload(const bool& aHasBeforeUnload)
|
||||
{
|
||||
mHasBeforeUnload = aHasBeforeUnload;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
|
||||
{
|
||||
@ -2797,6 +2805,13 @@ TabParent::TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal)
|
||||
->TransmitPermissionsForPrincipal(aPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::GetHasBeforeUnload(bool* aResult)
|
||||
{
|
||||
*aResult = mHasBeforeUnload;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class LayerTreeUpdateRunnable final
|
||||
: public mozilla::Runnable
|
||||
{
|
||||
|
@ -170,6 +170,9 @@ public:
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvSetHasBeforeUnload(const bool& aHasBeforeUnload) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
|
||||
PRenderFrameParent* aRenderFrame,
|
||||
const nsString& aURL,
|
||||
@ -762,6 +765,10 @@ private:
|
||||
// at least once.
|
||||
bool mHasPresented;
|
||||
|
||||
// True if at least one window hosted in the TabChild has added a
|
||||
// beforeunload event listener.
|
||||
bool mHasBeforeUnload;
|
||||
|
||||
public:
|
||||
static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user