mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1639328 - Make sure BrowserChilds for OOP iframes start in a consistent state. r=smaug
Right now they start with a FullyHidden() effect info, but with a "visible" widget, and thus active docshell and so on. That's no good :) Differential Revision: https://phabricator.services.mozilla.com/D86364
This commit is contained in:
parent
8b95c9a06f
commit
6c008dd4fd
@ -6237,11 +6237,13 @@ already_AddRefed<PresShell> Document::CreatePresShell(
|
|||||||
|
|
||||||
void Document::UpdateFrameRequestCallbackSchedulingState(
|
void Document::UpdateFrameRequestCallbackSchedulingState(
|
||||||
PresShell* aOldPresShell) {
|
PresShell* aOldPresShell) {
|
||||||
// If the condition for shouldBeScheduled changes to depend on some other
|
// If this condition changes to depend on some other variable, make sure to
|
||||||
// variable, add UpdateFrameRequestCallbackSchedulingState() calls to the
|
// call UpdateFrameRequestCallbackSchedulingState() calls to the places where
|
||||||
// places where that variable can change.
|
// that variable can change. Also consider if you should change
|
||||||
bool shouldBeScheduled = mPresShell && IsEventHandlingEnabled() &&
|
// WouldScheduleFrameRequestCallbacks() instead of adding more stuff to this
|
||||||
!mFrameRequestCallbacks.IsEmpty();
|
// condition.
|
||||||
|
bool shouldBeScheduled =
|
||||||
|
WouldScheduleFrameRequestCallbacks() && !mFrameRequestCallbacks.IsEmpty();
|
||||||
if (shouldBeScheduled == mFrameRequestCallbacksScheduled) {
|
if (shouldBeScheduled == mFrameRequestCallbacksScheduled) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return;
|
||||||
@ -6269,7 +6271,7 @@ void Document::TakeFrameRequestCallbacks(nsTArray<FrameRequest>& aCallbacks) {
|
|||||||
mFrameRequestCallbacksScheduled = false;
|
mFrameRequestCallbacksScheduled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Document::ShouldThrottleFrameRequests() {
|
bool Document::ShouldThrottleFrameRequests() const {
|
||||||
if (mStaticCloneCount > 0) {
|
if (mStaticCloneCount > 0) {
|
||||||
// Even if we're not visible, a static clone may be, so run at full speed.
|
// Even if we're not visible, a static clone may be, so run at full speed.
|
||||||
return false;
|
return false;
|
||||||
|
@ -2682,10 +2682,17 @@ class Document : public nsINode,
|
|||||||
|
|
||||||
uint32_t EventHandlingSuppressed() const { return mEventsSuppressed; }
|
uint32_t EventHandlingSuppressed() const { return mEventsSuppressed; }
|
||||||
|
|
||||||
bool IsEventHandlingEnabled() {
|
bool IsEventHandlingEnabled() const {
|
||||||
return !EventHandlingSuppressed() && mScriptGlobalObject;
|
return !EventHandlingSuppressed() && mScriptGlobalObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WouldScheduleFrameRequestCallbacks() const {
|
||||||
|
// If this function changes to depend on some other variable, make sure to
|
||||||
|
// call UpdateFrameRequestCallbackSchedulingState() calls to the places
|
||||||
|
// where that variable can change.
|
||||||
|
return mPresShell && IsEventHandlingEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
void DecreaseEventSuppression() {
|
void DecreaseEventSuppression() {
|
||||||
MOZ_ASSERT(mEventsSuppressed);
|
MOZ_ASSERT(mEventsSuppressed);
|
||||||
--mEventsSuppressed;
|
--mEventsSuppressed;
|
||||||
@ -3017,7 +3024,7 @@ class Document : public nsINode,
|
|||||||
* throttled. We throttle requestAnimationFrame for documents which aren't
|
* throttled. We throttle requestAnimationFrame for documents which aren't
|
||||||
* visible (e.g. scrolled out of the viewport).
|
* visible (e.g. scrolled out of the viewport).
|
||||||
*/
|
*/
|
||||||
bool ShouldThrottleFrameRequests();
|
bool ShouldThrottleFrameRequests() const;
|
||||||
|
|
||||||
// This returns true when the document tree is being teared down.
|
// This returns true when the document tree is being teared down.
|
||||||
bool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; }
|
bool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; }
|
||||||
|
@ -4401,3 +4401,14 @@ nsDOMWindowUtils::GetWebrtcRawDeviceId(nsAString& aRawDeviceId) {
|
|||||||
aRawDeviceId.AppendInt(rawDeviceId);
|
aRawDeviceId.AppendInt(rawDeviceId);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsDOMWindowUtils::GetEffectivelyThrottlesFrameRequests(bool* aResult) {
|
||||||
|
Document* doc = GetDocument();
|
||||||
|
if (!doc) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
*aResult = !doc->WouldScheduleFrameRequestCallbacks() ||
|
||||||
|
doc->ShouldThrottleFrameRequests();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
8
dom/base/test/file_bug1639328.html
Normal file
8
dom/base/test/file_bug1639328.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<script>
|
||||||
|
onmessage = function(e) {
|
||||||
|
parent.postMessage({
|
||||||
|
throttledFrameRequests: SpecialPowers.DOMWindowUtils.effectivelyThrottlesFrameRequests,
|
||||||
|
}, e.origin);
|
||||||
|
};
|
||||||
|
</script>
|
@ -305,6 +305,8 @@ skip-if = (os == "android" || headless) # See
|
|||||||
skip-if = headless # fails in clipboard mode
|
skip-if = headless # fails in clipboard mode
|
||||||
[test_bug166235.html]
|
[test_bug166235.html]
|
||||||
skip-if = headless # headless != clipboard
|
skip-if = headless # headless != clipboard
|
||||||
|
[test_bug1639328.html]
|
||||||
|
support-files = file_bug1639328.html
|
||||||
[test_bug199959.html]
|
[test_bug199959.html]
|
||||||
[test_bug218236.html]
|
[test_bug218236.html]
|
||||||
[test_bug218277.html]
|
[test_bug218277.html]
|
||||||
|
64
dom/base/test/test_bug1639328.html
Normal file
64
dom/base/test/test_bug1639328.html
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for bug 1639328</title>
|
||||||
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||||
|
<style>
|
||||||
|
/* To ensure that they're all in the viewport when displayed */
|
||||||
|
iframe {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<iframe id="http" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
|
||||||
|
<iframe id="https" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
|
||||||
|
<iframe id="same-origin" src="file_bug1639328.html"></iframe>
|
||||||
|
<iframe id="display-none-http" style="display: none" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
|
||||||
|
<iframe id="display-none-https" style="display: none" src="https://example.com/tests/dom/base/test/file_bug1639328.html"></iframe>
|
||||||
|
<iframe id="display-none-same-origin" style="display: none" src="file_bug1639328.html"></iframe>
|
||||||
|
<script>
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
function getOneMessage(frame) {
|
||||||
|
info("querying " + frame.src);
|
||||||
|
let resolve;
|
||||||
|
let promise = new Promise(r => { resolve = r; });
|
||||||
|
window.addEventListener("message", function(e) {
|
||||||
|
info("got " + JSON.stringify(e.data));
|
||||||
|
resolve(e.data);
|
||||||
|
}, { once: true });
|
||||||
|
frame.contentWindow.postMessage("ping", "*");
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ticks(n) {
|
||||||
|
for (let i = 0; i < n; ++i) {
|
||||||
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkFrame(frame, shouldThrottle) {
|
||||||
|
let message = await getOneMessage(frame);
|
||||||
|
is(message.throttledFrameRequests, shouldThrottle, frame.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onload = async function() {
|
||||||
|
await SimpleTest.promiseFocus(window);
|
||||||
|
await ticks(2);
|
||||||
|
is(SpecialPowers.DOMWindowUtils.effectivelyThrottlesFrameRequests, false, "Should not be throttling main page");
|
||||||
|
for (let frame of document.querySelectorAll("iframe")) {
|
||||||
|
let shouldThrottle = frame.style.display == "none";
|
||||||
|
await checkFrame(frame, shouldThrottle);
|
||||||
|
info("Switching display of " + frame.id);
|
||||||
|
frame.style.display = shouldThrottle ? "" : "none";
|
||||||
|
await ticks(2);
|
||||||
|
await checkFrame(frame, !shouldThrottle);
|
||||||
|
info("And switching display back for " + frame.id);
|
||||||
|
frame.style.display = shouldThrottle ? "none" : "";
|
||||||
|
await ticks(2);
|
||||||
|
await checkFrame(frame, shouldThrottle);
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.finish();
|
||||||
|
};
|
||||||
|
</script>
|
@ -2060,6 +2060,9 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||||||
// Returns true if we are using overlay scrollbars.
|
// Returns true if we are using overlay scrollbars.
|
||||||
readonly attribute bool usesOverlayScrollbars;
|
readonly attribute bool usesOverlayScrollbars;
|
||||||
|
|
||||||
|
// Returns true if we are effectively throttling frame requests.
|
||||||
|
readonly attribute bool effectivelyThrottlesFrameRequests;
|
||||||
|
|
||||||
// Returns the ID for the underlying window widget, which can
|
// Returns the ID for the underlying window widget, which can
|
||||||
// be compared against the rawId from a nsIMediaDevice to determine
|
// be compared against the rawId from a nsIMediaDevice to determine
|
||||||
// if the window is being shared.
|
// if the window is being shared.
|
||||||
|
@ -524,8 +524,7 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
|
|||||||
// frames.
|
// frames.
|
||||||
if (mIsTopLevel) {
|
if (mIsTopLevel) {
|
||||||
nsContentUtils::SetScrollbarsVisibility(
|
nsContentUtils::SetScrollbarsVisibility(
|
||||||
window->GetDocShell(),
|
docShell, !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS));
|
||||||
!!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsWeakPtr weakPtrThis = do_GetWeakReference(
|
nsWeakPtr weakPtrThis = do_GetWeakReference(
|
||||||
@ -548,6 +547,11 @@ nsresult BrowserChild::Init(mozIDOMWindowProxy* aParent,
|
|||||||
rv = mSessionStoreListener->Init();
|
rv = mSessionStoreListener->Init();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// We've all set up, make sure our visibility state is consistent. This is
|
||||||
|
// important for OOP iframes, which start off as hidden.
|
||||||
|
UpdateVisibility();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,8 +189,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||||||
dom::BrowsingContext* aBrowsingContext, uint32_t aChromeFlags,
|
dom::BrowsingContext* aBrowsingContext, uint32_t aChromeFlags,
|
||||||
bool aIsTopLevel);
|
bool aIsTopLevel);
|
||||||
|
|
||||||
nsresult Init(mozIDOMWindowProxy* aParent,
|
MOZ_CAN_RUN_SCRIPT nsresult Init(mozIDOMWindowProxy* aParent,
|
||||||
WindowGlobalChild* aInitialWindowChild);
|
WindowGlobalChild* aInitialWindowChild);
|
||||||
|
|
||||||
/** Return a BrowserChild with the given attributes. */
|
/** Return a BrowserChild with the given attributes. */
|
||||||
static already_AddRefed<BrowserChild> Create(
|
static already_AddRefed<BrowserChild> Create(
|
||||||
|
@ -1014,7 +1014,8 @@ nsresult ContentChild::ProvideWindowCommon(
|
|||||||
|
|
||||||
// Now that |newChild| has had its IPC link established, call |Init| to set it
|
// Now that |newChild| has had its IPC link established, call |Init| to set it
|
||||||
// up.
|
// up.
|
||||||
nsPIDOMWindowOuter* parentWindow = parent ? parent->GetDOMWindow() : nullptr;
|
RefPtr<nsPIDOMWindowOuter> parentWindow =
|
||||||
|
parent ? parent->GetDOMWindow() : nullptr;
|
||||||
if (NS_FAILED(newChild->Init(parentWindow, windowChild))) {
|
if (NS_FAILED(newChild->Init(parentWindow, windowChild))) {
|
||||||
return NS_ERROR_ABORT;
|
return NS_ERROR_ABORT;
|
||||||
}
|
}
|
||||||
|
@ -104,15 +104,13 @@ class ContentChild final : public PContentChild,
|
|||||||
nsCString updateURL;
|
nsCString updateURL;
|
||||||
};
|
};
|
||||||
|
|
||||||
nsresult ProvideWindowCommon(BrowserChild* aTabOpener,
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult ProvideWindowCommon(
|
||||||
nsIOpenWindowInfo* aOpenWindowInfo,
|
BrowserChild* aTabOpener, nsIOpenWindowInfo* aOpenWindowInfo,
|
||||||
uint32_t aChromeFlags, bool aCalledFromJS,
|
uint32_t aChromeFlags, bool aCalledFromJS, bool aWidthSpecified,
|
||||||
bool aWidthSpecified, nsIURI* aURI,
|
nsIURI* aURI, const nsAString& aName, const nsACString& aFeatures,
|
||||||
const nsAString& aName,
|
bool aForceNoOpener, bool aForceNoReferrer,
|
||||||
const nsACString& aFeatures, bool aForceNoOpener,
|
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
|
||||||
bool aForceNoReferrer,
|
BrowsingContext** aReturn);
|
||||||
nsDocShellLoadState* aLoadState,
|
|
||||||
bool* aWindowIsNew, BrowsingContext** aReturn);
|
|
||||||
|
|
||||||
bool Init(MessageLoop* aIOLoop, base::ProcessId aParentPid,
|
bool Init(MessageLoop* aIOLoop, base::ProcessId aParentPid,
|
||||||
const char* aParentBuildID, UniquePtr<IPC::Channel> aChannel,
|
const char* aParentBuildID, UniquePtr<IPC::Channel> aChannel,
|
||||||
@ -493,7 +491,7 @@ class ContentChild final : public PContentChild,
|
|||||||
|
|
||||||
bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*);
|
bool DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvConstructBrowser(
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY mozilla::ipc::IPCResult RecvConstructBrowser(
|
||||||
ManagedEndpoint<PBrowserChild>&& aBrowserEp,
|
ManagedEndpoint<PBrowserChild>&& aBrowserEp,
|
||||||
ManagedEndpoint<PWindowGlobalChild>&& aWindowEp, const TabId& aTabId,
|
ManagedEndpoint<PWindowGlobalChild>&& aWindowEp, const TabId& aTabId,
|
||||||
const IPCTabContext& aContext, const WindowGlobalInit& aWindowInit,
|
const IPCTabContext& aContext, const WindowGlobalInit& aWindowInit,
|
||||||
|
Loading…
Reference in New Issue
Block a user