From c5688b603e6bcfc416501de5f1090d405bab4a8a Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Fri, 12 Mar 2021 16:23:10 +0000 Subject: [PATCH] Bug 1640766 - Make nsGlobalWindowInner::Suspend/Resume suspend/resume all in-process descendants; r=smaug Differential Revision: https://phabricator.services.mozilla.com/D107762 --- dom/base/nsGlobalWindowInner.cpp | 69 +++++++++++++-------------- dom/base/nsGlobalWindowInner.h | 28 +++++++++-- dom/base/test/iframe1_bug1640766.html | 20 ++++++++ dom/base/test/iframe2_bug1640766.html | 10 ++++ dom/base/test/mochitest.ini | 4 ++ dom/base/test/test_bug1640766.html | 67 ++++++++++++++++++++++++++ 6 files changed, 158 insertions(+), 40 deletions(-) create mode 100644 dom/base/test/iframe1_bug1640766.html create mode 100644 dom/base/test/iframe2_bug1640766.html create mode 100644 dom/base/test/test_bug1640766.html diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp index 63e180c948b4..cee8d092e6e8 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -5452,10 +5452,11 @@ void nsGlobalWindowInner::Suspend(bool aIncludeSubWindows) { return; } - // All children are also suspended. This ensure mSuspendDepth is - // set properly and the timers are properly canceled for each child. + // All in-process descendants are also suspended. This ensure mSuspendDepth + // is set properly and the timers are properly canceled for each in-process + // descendant. if (aIncludeSubWindows) { - CallOnInProcessChildren(&nsGlobalWindowInner::Suspend, aIncludeSubWindows); + CallOnInProcessDescendants(&nsGlobalWindowInner::Suspend, false); } mSuspendDepth += 1; @@ -5501,10 +5502,11 @@ void nsGlobalWindowInner::Resume(bool aIncludeSubWindows) { return; } - // Resume all children. This restores timers recursively canceled - // in Suspend() and ensures all children have the correct mSuspendDepth. + // Resume all in-process descendants. This restores timers recursively + // canceled in Suspend() and ensures all in-process descendants have the + // correct mSuspendDepth. if (aIncludeSubWindows) { - CallOnInProcessChildren(&nsGlobalWindowInner::Resume, aIncludeSubWindows); + CallOnInProcessDescendants(&nsGlobalWindowInner::Resume, false); } if (mSuspendDepth == 0) { @@ -5683,43 +5685,36 @@ void nsGlobalWindowInner::SyncStateFromParentWindow() { } template -CallState nsGlobalWindowInner::CallOnInProcessChildren(Method aMethod, - Args&... aArgs) { +CallState nsGlobalWindowInner::CallOnInProcessDescendantsInternal( + BrowsingContext* aBrowsingContext, bool aChildOnly, Method aMethod, + Args&&... aArgs) { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsCurrentInnerWindow()); + MOZ_ASSERT(aBrowsingContext); CallState state = CallState::Continue; + for (const RefPtr& bc : aBrowsingContext->Children()) { + if (nsCOMPtr pWin = bc->GetDOMWindow()) { + auto* win = nsGlobalWindowOuter::Cast(pWin); + if (nsGlobalWindowInner* inner = win->GetCurrentInnerWindowInternal()) { + // Call the descendant method using our helper CallDescendant() template + // method. This allows us to handle both void returning methods and + // methods that return CallState explicitly. For void returning methods + // we assume CallState::Continue. + typedef decltype((inner->*aMethod)(aArgs...)) returnType; + state = CallDescendant(inner, aMethod, aArgs...); - nsCOMPtr docShell = GetDocShell(); - if (!docShell) { - return state; - } - - for (const RefPtr& bc : GetBrowsingContext()->Children()) { - nsCOMPtr pWin = bc->GetDOMWindow(); - if (!pWin) { - continue; + if (state == CallState::Stop) { + return state; + } + } } - auto* win = nsGlobalWindowOuter::Cast(pWin); - nsGlobalWindowInner* inner = win->GetCurrentInnerWindowInternal(); - - // This is a bit hackish. Only freeze/suspend windows which are truly our - // subwindows. - nsCOMPtr frame = pWin->GetFrameElementInternal(); - if (!mDoc || !frame || mDoc != frame->OwnerDoc() || !inner) { - continue; - } - - // Call the child method using our helper CallChild() template method. - // This allows us to handle both void returning methods and methods - // that return CallState explicitly. For void returning methods we - // assume CallState::Continue. - typedef decltype((inner->*aMethod)(aArgs...)) returnType; - state = CallChild(inner, aMethod, aArgs...); - - if (state == CallState::Stop) { - return state; + if (!aChildOnly) { + state = CallOnInProcessDescendantsInternal(bc.get(), aChildOnly, aMethod, + aArgs...); + if (state == CallState::Stop) { + return state; + } } } diff --git a/dom/base/nsGlobalWindowInner.h b/dom/base/nsGlobalWindowInner.h index f3bd4e2734fc..18d87be7fa04 100644 --- a/dom/base/nsGlobalWindowInner.h +++ b/dom/base/nsGlobalWindowInner.h @@ -1038,17 +1038,38 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, nsPIDOMWindowOuter* GetInProcessParentInternal(); private: + template + mozilla::CallState CallOnInProcessDescendantsInternal( + mozilla::dom::BrowsingContext* aBrowsingContext, bool aChildOnly, + Method aMethod, Args&&... aArgs); + // Call the given method on the immediate children of this window. The // CallState returned by the last child method invocation is returned or // CallState::Continue if the method returns void. template - mozilla::CallState CallOnInProcessChildren(Method aMethod, Args&... aArgs); + mozilla::CallState CallOnInProcessChildren(Method aMethod, Args&&... aArgs) { + MOZ_ASSERT(IsCurrentInnerWindow()); + return CallOnInProcessDescendantsInternal(GetBrowsingContext(), true, + aMethod, aArgs...); + } + + // Call the given method on the descendant of this window. The CallState + // returned by the last descendant method invocation is returned or + // CallState::Continue if the method returns void. + template + mozilla::CallState CallOnInProcessDescendants(Method aMethod, + Args&&... aArgs) { + MOZ_ASSERT(IsCurrentInnerWindow()); + return CallOnInProcessDescendantsInternal(GetBrowsingContext(), false, + aMethod, aArgs...); + } // Helper to convert a void returning child method into an implicit // CallState::Continue value. template typename std::enable_if::value, mozilla::CallState>::type - CallChild(nsGlobalWindowInner* aWindow, Method aMethod, Args&... aArgs) { + CallDescendant(nsGlobalWindowInner* aWindow, Method aMethod, + Args&&... aArgs) { (aWindow->*aMethod)(aArgs...); return mozilla::CallState::Continue; } @@ -1057,7 +1078,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget, template typename std::enable_if::value, mozilla::CallState>::type - CallChild(nsGlobalWindowInner* aWindow, Method aMethod, Args&... aArgs) { + CallDescendant(nsGlobalWindowInner* aWindow, Method aMethod, + Args&&... aArgs) { return (aWindow->*aMethod)(aArgs...); } diff --git a/dom/base/test/iframe1_bug1640766.html b/dom/base/test/iframe1_bug1640766.html new file mode 100644 index 000000000000..51da4f22f033 --- /dev/null +++ b/dom/base/test/iframe1_bug1640766.html @@ -0,0 +1,20 @@ + + + +Iframe 1 for Bug 1640766 + + +
Iframe 1
+ + + diff --git a/dom/base/test/iframe2_bug1640766.html b/dom/base/test/iframe2_bug1640766.html new file mode 100644 index 000000000000..6a5ca30796ac --- /dev/null +++ b/dom/base/test/iframe2_bug1640766.html @@ -0,0 +1,10 @@ + + + +Iframe 2 for Bug 1640766 + + +
Iframe 2
+ + + diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index dfe2c0e6f2a4..b937968c56bb 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -603,6 +603,10 @@ support-files = file_bug1100912.html [test_bug1499169.html] skip-if = toolkit == 'android' # Timeouts on android due to page closing issues with embedded pdf [test_bug1576154.html] +[test_bug1640766.html] +support-files = + iframe1_bug1640766.html + iframe2_bug1640766.html [test_bug1648887.html] [test_caretPositionFromPoint.html] [test_change_policy.html] diff --git a/dom/base/test/test_bug1640766.html b/dom/base/test/test_bug1640766.html new file mode 100644 index 000000000000..ea77c99e5942 --- /dev/null +++ b/dom/base/test/test_bug1640766.html @@ -0,0 +1,67 @@ + + + + + Test for Bug 1640766 + + + + +Mozilla Bug 1640766 +

+ +
+
+
+ +