зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1236512 - Part 3: Set docShellIsActive to false when browser window is fully covered by another application; r=mconley
MozReview-Commit-ID: DLsmWp1h8pa
This commit is contained in:
Родитель
7a94f225de
Коммит
2ae9d877a0
|
@ -1111,7 +1111,8 @@
|
|||
oldBrowser.docShellIsActive = false;
|
||||
newBrowser.setAttribute("primary", "true");
|
||||
newBrowser.docShellIsActive =
|
||||
(window.windowState != window.STATE_MINIMIZED);
|
||||
(window.windowState != window.STATE_MINIMIZED &&
|
||||
!window.isFullyOccluded);
|
||||
}
|
||||
|
||||
var updateBlockedPopups = false;
|
||||
|
@ -3885,7 +3886,8 @@
|
|||
return this._switcher.shouldActivateDocShell(aBrowser);
|
||||
}
|
||||
return (aBrowser == this.selectedBrowser &&
|
||||
window.windowState != window.STATE_MINIMIZED) ||
|
||||
window.windowState != window.STATE_MINIMIZED &&
|
||||
!window.isFullyOccluded) ||
|
||||
this._printPreviewBrowsers.has(aBrowser);
|
||||
]]>
|
||||
</body>
|
||||
|
@ -4035,7 +4037,7 @@
|
|||
let browser = tab.linkedBrowser;
|
||||
let {tabParent} = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
if (state == this.STATE_LOADING) {
|
||||
this.assert(!this.minimized);
|
||||
this.assert(!this.minimizedOrFullyOccluded);
|
||||
browser.docShellIsActive = true;
|
||||
if (!tabParent) {
|
||||
this.onLayersReady(browser);
|
||||
|
@ -4061,8 +4063,9 @@
|
|||
}
|
||||
},
|
||||
|
||||
get minimized() {
|
||||
return window.windowState == window.STATE_MINIMIZED;
|
||||
get minimizedOrFullyOccluded() {
|
||||
return window.windowState == window.STATE_MINIMIZED ||
|
||||
window.isFullyOccluded;
|
||||
},
|
||||
|
||||
init() {
|
||||
|
@ -4078,6 +4081,7 @@
|
|||
window.addEventListener("MozLayerTreeCleared", this);
|
||||
window.addEventListener("TabRemotenessChange", this);
|
||||
window.addEventListener("sizemodechange", this);
|
||||
window.addEventListener("occlusionstatechange", this);
|
||||
window.addEventListener("SwapDocShells", this, true);
|
||||
window.addEventListener("EndSwapDocShells", this, true);
|
||||
|
||||
|
@ -4086,7 +4090,7 @@
|
|||
let tabIsLoaded = !browser.isRemoteBrowser ||
|
||||
browser.frameLoader.tabParent.hasPresented;
|
||||
|
||||
if (!this.minimized) {
|
||||
if (!this.minimizedOrFullyOccluded) {
|
||||
this.log("Initial tab is loaded?: " + tabIsLoaded);
|
||||
this.setTabState(tab, tabIsLoaded ? this.STATE_LOADED
|
||||
: this.STATE_LOADING);
|
||||
|
@ -4108,6 +4112,7 @@
|
|||
window.removeEventListener("MozLayerTreeCleared", this);
|
||||
window.removeEventListener("TabRemotenessChange", this);
|
||||
window.removeEventListener("sizemodechange", this);
|
||||
window.removeEventListener("occlusionstatechange", this);
|
||||
window.removeEventListener("SwapDocShells", this, true);
|
||||
window.removeEventListener("EndSwapDocShells", this, true);
|
||||
|
||||
|
@ -4129,7 +4134,8 @@
|
|||
this.assert(!this.loadTimer);
|
||||
this.assert(!this.loadingTab);
|
||||
this.assert(this.lastVisibleTab === this.requestedTab);
|
||||
this.assert(this.minimized || this.getTabState(this.requestedTab) == this.STATE_LOADED);
|
||||
this.assert(this.minimizedOrFullyOccluded ||
|
||||
this.getTabState(this.requestedTab) == this.STATE_LOADED);
|
||||
|
||||
this.destroy();
|
||||
|
||||
|
@ -4182,7 +4188,7 @@
|
|||
requestedBrowser.currentURI.spec != "about:blank";
|
||||
|
||||
let fl = requestedBrowser.frameLoader;
|
||||
shouldBeBlank = !this.minimized &&
|
||||
shouldBeBlank = !this.minimizedOrFullyOccluded &&
|
||||
(!fl.tabParent ||
|
||||
(!hasSufficientlyLoaded && !fl.tabParent.hasPresented));
|
||||
}
|
||||
|
@ -4218,7 +4224,7 @@
|
|||
|
||||
// Show or hide the spinner as needed.
|
||||
let needSpinner = this.getTabState(showTab) != this.STATE_LOADED &&
|
||||
!this.minimized &&
|
||||
!this.minimizedOrFullyOccluded &&
|
||||
!shouldBeBlank;
|
||||
|
||||
if (!needSpinner && this.spinnerTab) {
|
||||
|
@ -4280,7 +4286,7 @@
|
|||
// We've decided to try to load requestedTab.
|
||||
loadRequestedTab() {
|
||||
this.assert(!this.loadTimer);
|
||||
this.assert(!this.minimized);
|
||||
this.assert(!this.minimizedOrFullyOccluded);
|
||||
|
||||
// loadingTab can be non-null here if we timed out loading the current tab.
|
||||
// In that case we just overwrite it with a different tab; it's had its chance.
|
||||
|
@ -4349,7 +4355,7 @@
|
|||
|
||||
// If we're not loading anything, try loading the requested tab.
|
||||
let requestedState = this.getTabState(this.requestedTab);
|
||||
if (!this.loadTimer && !this.minimized &&
|
||||
if (!this.loadTimer && !this.minimizedOrFullyOccluded &&
|
||||
(requestedState == this.STATE_UNLOADED ||
|
||||
requestedState == this.STATE_UNLOADING)) {
|
||||
this.loadRequestedTab();
|
||||
|
@ -4504,8 +4510,8 @@
|
|||
}
|
||||
},
|
||||
|
||||
onSizeModeChange() {
|
||||
if (this.minimized) {
|
||||
onSizeModeOrOcclusionStateChange() {
|
||||
if (this.minimizedOrFullyOccluded) {
|
||||
for (let [tab, state] of this.tabState) {
|
||||
// Skip print preview browsers since they shouldn't affect tab switching.
|
||||
if (this.tabbrowser._printPreviewBrowsers.has(tab.linkedBrowser)) {
|
||||
|
@ -4639,8 +4645,9 @@
|
|||
this.onLayersCleared(event.originalTarget);
|
||||
} else if (event.type == "TabRemotenessChange") {
|
||||
this.onRemotenessChange(event.target);
|
||||
} else if (event.type == "sizemodechange") {
|
||||
this.onSizeModeChange();
|
||||
} else if (event.type == "sizemodechange" ||
|
||||
event.type == "occlusionstatechange") {
|
||||
this.onSizeModeOrOcclusionStateChange();
|
||||
} else if (event.type == "SwapDocShells") {
|
||||
this.onSwapDocShells(event.originalTarget, event.detail);
|
||||
} else if (event.type == "EndSwapDocShells") {
|
||||
|
@ -5115,8 +5122,10 @@
|
|||
this._handleKeyPressEventMac(aEvent);
|
||||
break;
|
||||
case "sizemodechange":
|
||||
case "occlusionstatechange":
|
||||
if (aEvent.target == window && !this._switcher) {
|
||||
this.mCurrentBrowser.preserveLayers(window.windowState == window.STATE_MINIMIZED);
|
||||
this.mCurrentBrowser.preserveLayers(
|
||||
window.windowState == window.STATE_MINIMIZED || window.isFullyOccluded);
|
||||
this.mCurrentBrowser.docShellIsActive = this.shouldActivateDocShell(this.mCurrentBrowser);
|
||||
}
|
||||
break;
|
||||
|
@ -5343,6 +5352,7 @@
|
|||
els.addSystemEventListener(document, "keypress", this, false);
|
||||
}
|
||||
window.addEventListener("sizemodechange", this);
|
||||
window.addEventListener("occlusionstatechange", this);
|
||||
|
||||
var uniqueId = this._generateUniquePanelID();
|
||||
this.mPanelContainer.childNodes[0].id = uniqueId;
|
||||
|
@ -5463,6 +5473,7 @@
|
|||
els.removeSystemEventListener(document, "keypress", this, false);
|
||||
}
|
||||
window.removeEventListener("sizemodechange", this);
|
||||
window.removeEventListener("occlusionstatechange", this);
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
let messageManager = window.getGroupMessageManager("browsers");
|
||||
|
|
|
@ -17,6 +17,9 @@ function frameScript() {
|
|||
inFullscreen: content.fullScreen
|
||||
});
|
||||
});
|
||||
addMessageListener("Test:WaitActivated", () => {
|
||||
waitUntilActive();
|
||||
});
|
||||
content.document.addEventListener("fullscreenchange", () => {
|
||||
sendAsyncMessage("Test:FullscreenChanged", {
|
||||
inDOMFullscreen: !!content.document.fullscreenElement,
|
||||
|
@ -65,6 +68,13 @@ const FS_CHANGE_DOM = 1 << 0;
|
|||
const FS_CHANGE_SIZE = 1 << 1;
|
||||
const FS_CHANGE_BOTH = FS_CHANGE_DOM | FS_CHANGE_SIZE;
|
||||
|
||||
function waitForDocActivated() {
|
||||
return new Promise(resolve => {
|
||||
listenOneMessage("Test:Activated", resolve);
|
||||
gMessageManager.sendAsyncMessage("Test:WaitActivated");
|
||||
});
|
||||
}
|
||||
|
||||
function waitForFullscreenChanges(aFlags) {
|
||||
return new Promise(resolve => {
|
||||
let fullscreenData = null;
|
||||
|
@ -72,11 +82,18 @@ function waitForFullscreenChanges(aFlags) {
|
|||
function tryResolve() {
|
||||
if ((!(aFlags & FS_CHANGE_DOM) || fullscreenData) &&
|
||||
(!(aFlags & FS_CHANGE_SIZE) || sizemodeChanged)) {
|
||||
if (!fullscreenData) {
|
||||
queryFullscreenState().then(resolve);
|
||||
} else {
|
||||
resolve(fullscreenData);
|
||||
}
|
||||
// In the platforms that support reporting occlusion state (e.g. Mac),
|
||||
// enter/exit fullscreen mode will trigger docshell being set to
|
||||
// non-activate and then set to activate back again.
|
||||
// For those platform, we should wait until the docshell has been
|
||||
// activated again, otherwise, the fullscreen request might be denied.
|
||||
waitForDocActivated().then(() => {
|
||||
if (!fullscreenData) {
|
||||
queryFullscreenState().then(resolve);
|
||||
} else {
|
||||
resolve(fullscreenData);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (aFlags & FS_CHANGE_SIZE) {
|
||||
|
|
|
@ -80,6 +80,16 @@ function shouldSkipTest(test) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function waitForEvent(eventTarget, eventName, checkFn, callback) {
|
||||
eventTarget.addEventListener(eventName, function listener(event) {
|
||||
if (checkFn && !checkFn(event)) {
|
||||
return;
|
||||
}
|
||||
eventTarget.removeEventListener(eventName, listener);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (gTestIndex < gTestWindows.length) {
|
||||
let test = gTestWindows[gTestIndex];
|
||||
|
@ -95,7 +105,18 @@ function runNextTest() {
|
|||
// OS X Lion before we run the test.
|
||||
testWindow.addEventListener("load", function() {
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SimpleTest.waitForFocus(testWindow.begin, testWindow);
|
||||
SimpleTest.waitForFocus(function() {
|
||||
// For the platforms that support reporting occlusion state (e.g. Mac),
|
||||
// we should wait until the docshell has been activated again,
|
||||
// otherwise, the fullscreen request might be denied.
|
||||
if (testWindow.document.hidden) {
|
||||
waitForEvent(testWindow.document, "visibilitychange", (event) => {
|
||||
return !testWindow.document.hidden;
|
||||
}, testWindow.begin);
|
||||
return;
|
||||
}
|
||||
testWindow.begin();
|
||||
}, testWindow);
|
||||
});
|
||||
}, {once: true});
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ skip-if = !e10s
|
|||
[browser_bug1004814.js]
|
||||
[browser_bug1008941_dismissGeolocationHanger.js]
|
||||
tags = geolocation
|
||||
[browser_bug1236512.js]
|
||||
skip-if = os != "mac"
|
||||
[browser_bug1238427.js]
|
||||
[browser_bug1316330.js]
|
||||
skip-if = !e10s
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const testPageURL = "http://mochi.test:8888/browser/dom/tests/browser/dummy.html";
|
||||
|
||||
async function testContentVisibilityState(aIsHidden, aBrowser) {
|
||||
await ContentTask.spawn(aBrowser.selectedBrowser, aIsHidden, (aExpectedResult) => {
|
||||
is(content.document.hidden, aExpectedResult, "document.hidden");
|
||||
is(content.document.visibilityState, aExpectedResult ? "hidden" : "visible",
|
||||
"document.visibilityState");
|
||||
});
|
||||
}
|
||||
|
||||
async function waitContentVisibilityChange(aIsHidden, aBrowser) {
|
||||
await ContentTask.spawn(aBrowser.selectedBrowser, aIsHidden,
|
||||
async function(aExpectedResult) {
|
||||
let visibilityState = aExpectedResult ? "hidden" : "visible";
|
||||
if (content.document.hidden === aExpectedResult &&
|
||||
content.document.visibilityState === visibilityState) {
|
||||
ok(true, "already changed to expected visibility state");
|
||||
return;
|
||||
}
|
||||
|
||||
info("wait visibilitychange event");
|
||||
await ContentTaskUtils.waitForEvent(content.document, "visibilitychange",
|
||||
true /* capture */, (aEvent) => {
|
||||
info(`visibilitychange: ${content.document.hidden} ${content.document.visibilityState}`);
|
||||
return content.document.hidden === aExpectedResult &&
|
||||
content.document.visibilityState === visibilityState;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This test is to test the visibility state will change to "hidden" when browser
|
||||
* window is fully covered by another non-translucent application. Note that we
|
||||
* only support this on Mac for now, other platforms don't support reporting
|
||||
* occlusion state.
|
||||
*/
|
||||
add_task(async function() {
|
||||
info("creating test window");
|
||||
// Specify the width, height, left and top, so that the new window can be
|
||||
// fully covered by "window".
|
||||
let winTest = await BrowserTestUtils.openNewBrowserWindow({ width: 500,
|
||||
height: 500,
|
||||
left: 200,
|
||||
top: 200 });
|
||||
let browserTest = winTest.gBrowser;
|
||||
|
||||
info(`loading test page: ${testPageURL}`);
|
||||
browserTest.selectedBrowser.loadURI(testPageURL);
|
||||
await BrowserTestUtils.browserLoaded(browserTest.selectedBrowser);
|
||||
|
||||
info("test init visibility state");
|
||||
await testContentVisibilityState(false /* isHidden */, browserTest);
|
||||
|
||||
info("test window should report 'hidden' if it is fully covered by another " +
|
||||
"window");
|
||||
await new Promise(resolve => waitForFocus(resolve, window));
|
||||
await waitContentVisibilityChange(true /* isHidden */, browserTest);
|
||||
|
||||
info("test window should still report 'hidden' since it is still fully covered " +
|
||||
"by another window");
|
||||
let tab = BrowserTestUtils.addTab(browserTest);
|
||||
await BrowserTestUtils.switchTab(browserTest, tab);
|
||||
await BrowserTestUtils.removeTab(browserTest.selectedTab);
|
||||
await testContentVisibilityState(true /* isHidden */, browserTest);
|
||||
|
||||
info("test window should report 'visible' if it is not fully covered by " +
|
||||
"another window");
|
||||
await new Promise(resolve => waitForFocus(resolve, winTest));
|
||||
await waitContentVisibilityChange(false /* isHidden */, browserTest);
|
||||
|
||||
info("closing test window");
|
||||
await BrowserTestUtils.closeWindow(winTest);
|
||||
});
|
|
@ -605,6 +605,14 @@ this.BrowserTestUtils = {
|
|||
features += ",height=" + options.height;
|
||||
}
|
||||
|
||||
if (options.left) {
|
||||
features += ",left=" + options.left;
|
||||
}
|
||||
|
||||
if (options.top) {
|
||||
features += ",top=" + options.top;
|
||||
}
|
||||
|
||||
if (options.hasOwnProperty("remote")) {
|
||||
let remoteState = options.remote ? "remote" : "non-remote";
|
||||
features += `,${remoteState}`;
|
||||
|
|
Загрузка…
Ссылка в новой задаче