зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1640766 - Make nsGlobalWindowInner::Suspend/Resume suspend/resume all in-process descendants; r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D107762
This commit is contained in:
Родитель
f16dee35cf
Коммит
c5688b603e
|
@ -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 <typename Method, typename... Args>
|
||||
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<BrowsingContext>& bc : aBrowsingContext->Children()) {
|
||||
if (nsCOMPtr<nsPIDOMWindowOuter> 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<returnType>(inner, aMethod, aArgs...);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = GetDocShell();
|
||||
if (!docShell) {
|
||||
return state;
|
||||
}
|
||||
|
||||
for (const RefPtr<BrowsingContext>& bc : GetBrowsingContext()->Children()) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> 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<Element> 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<returnType>(inner, aMethod, aArgs...);
|
||||
|
||||
if (state == CallState::Stop) {
|
||||
return state;
|
||||
if (!aChildOnly) {
|
||||
state = CallOnInProcessDescendantsInternal(bc.get(), aChildOnly, aMethod,
|
||||
aArgs...);
|
||||
if (state == CallState::Stop) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1038,17 +1038,38 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
nsPIDOMWindowOuter* GetInProcessParentInternal();
|
||||
|
||||
private:
|
||||
template <typename Method, typename... Args>
|
||||
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 <typename Method, typename... Args>
|
||||
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 <typename Method, typename... Args>
|
||||
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 Return, typename Method, typename... Args>
|
||||
typename std::enable_if<std::is_void<Return>::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 Return, typename Method, typename... Args>
|
||||
typename std::enable_if<std::is_same<Return, mozilla::CallState>::value,
|
||||
mozilla::CallState>::type
|
||||
CallChild(nsGlobalWindowInner* aWindow, Method aMethod, Args&... aArgs) {
|
||||
CallDescendant(nsGlobalWindowInner* aWindow, Method aMethod,
|
||||
Args&&... aArgs) {
|
||||
return (aWindow->*aMethod)(aArgs...);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Iframe 1 for Bug 1640766</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>Iframe 1</div>
|
||||
<script type="application/javascript">
|
||||
if (parent == window) {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.src = "http://example.org/tests/dom/base/test/iframe2_bug1640766.html";
|
||||
document.body.appendChild(iframe);
|
||||
} else {
|
||||
window.onload = function() {
|
||||
top.opener.postMessage("ready", "*");
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Iframe 2 for Bug 1640766</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>Iframe 2</div>
|
||||
<iframe src="http://mochi.test:8888/tests/dom/base/test/iframe1_bug1640766.html"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -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]
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1640766
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1640766</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1640766">Mozilla Bug 1640766</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1640766 **/
|
||||
|
||||
function waitForMessage(aMsg) {
|
||||
return new Promise((aResolve) => {
|
||||
window.addEventListener("message", function handler(e) {
|
||||
if (e.data != aMsg) {
|
||||
return;
|
||||
}
|
||||
|
||||
info(`receive: ${e.data}`);
|
||||
window.removeEventListener("message", handler);
|
||||
aResolve(e.source);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function testSuspend(aWindow) {
|
||||
let timerRan = false;
|
||||
let timer = aWindow.setTimeout(function() {
|
||||
timerRan = true;
|
||||
}, 0);
|
||||
|
||||
return new Promise((aResolve) => {
|
||||
setTimeout(function() {
|
||||
ok(!timerRan, "timer should not run as the window is suspended");
|
||||
clearTimeout(timer);
|
||||
aResolve();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
let w = window.open("iframe1_bug1640766.html");
|
||||
let inner = await waitForMessage("ready");
|
||||
|
||||
var utils = SpecialPowers.getDOMWindowUtils(w);
|
||||
utils.enterModalState();
|
||||
|
||||
await testSuspend(w);
|
||||
await testSuspend(inner);
|
||||
|
||||
utils.leaveModalState();
|
||||
w.close();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче