Commit d6d6369c authored by Carsten Schoenert's avatar Carsten Schoenert
Browse files

Update upstream source from tag 'upstream/91.5.0'

Update to upstream version '91.5.0'
with Debian dir 123e4050905111567fdcfc362690b6e44ba68ded
parents 0dd00fd2 8d4e5f80
......@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Merge day clobber
\ No newline at end of file
Bug 1717151 - ANGLE update requires clobber
......@@ -15,6 +15,8 @@ skip-if =
[browser_test_textcaret.js]
[browser_test_focus_browserui.js]
[browser_test_focus_dialog.js]
skip-if =
os == 'win' && bits == 64 && webrender && !debug # Bug 1484212
[browser_test_focus_urlbar.js]
skip-if =
os == 'win' && os_version == '10.0' && webrender # Bug 1492259
......
......@@ -11,26 +11,24 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class DOMFullscreenChild extends JSWindowActorChild {
receiveMessage(aMessage) {
let window = this.contentWindow;
if (!window) {
if (!aMessage.data.remoteFrameBC) {
this.sendAsyncMessage("DOMFullscreen:Exit", {});
}
return;
}
let windowUtils = window.windowUtils;
if (!windowUtils) {
return;
}
let windowUtils = window?.windowUtils;
switch (aMessage.name) {
case "DOMFullscreen:Entered": {
if (!windowUtils) {
// If we are not able to enter fullscreen, tell the parent to just
// exit.
this.sendAsyncMessage("DOMFullscreen:Exit", {});
break;
}
let remoteFrameBC = aMessage.data.remoteFrameBC;
if (remoteFrameBC) {
let remoteFrame = remoteFrameBC.embedderElement;
this._isNotTheRequestSource = true;
windowUtils.remoteFrameFullscreenChanged(remoteFrame);
} else {
this._waitForMozAfterPaint = true;
this._lastTransactionId = windowUtils.lastTransactionId;
if (
!windowUtils.handleFullscreenRequests() &&
......@@ -45,23 +43,39 @@ class DOMFullscreenChild extends JSWindowActorChild {
break;
}
case "DOMFullscreen:CleanUp": {
let remoteFrameBC = aMessage.data.remoteFrameBC;
if (remoteFrameBC) {
this._isNotTheRequestSource = true;
}
let isNotTheRequestSource = !!aMessage.data.remoteFrameBC;
// If we've exited fullscreen at this point, no need to record
// transaction id or call exit fullscreen. This is especially
// important for pre-e10s, since in that case, it is possible
// that no more paint would be triggered after this point.
if (this.document.fullscreenElement) {
this._lastTransactionId = windowUtils.lastTransactionId;
windowUtils.exitFullscreen();
this._isNotTheRequestSource = isNotTheRequestSource;
// Need to wait for the MozAfterPaint after exiting fullscreen if
// this is the request source.
this._waitForMozAfterPaint = !this._isNotTheRequestSource;
// windowUtils could be null if the associated window is not current
// active window. In this case, document must be in the process of
// exiting fullscreen, it is okay to not ask it to exit fullscreen.
if (windowUtils) {
this._lastTransactionId = windowUtils.lastTransactionId;
windowUtils.exitFullscreen();
}
} else if (isNotTheRequestSource) {
// If we are not the request source and have exited fullscreen, reply
// Exited to parent as parent is waiting for our reply.
this.sendAsyncMessage("DOMFullscreen:Exited", {});
} else {
// If we've already exited fullscreen, it is possible that no more
// paint would be triggered, so don't wait for MozAfterPaint.
// TODO: There might be some way to move this code around a bit to
// make it easier to follow. Somehow handle the "local" case in
// one place and the isNotTheRequestSource case after that.
this.sendAsyncMessage("DOMFullscreen:Painted", {});
}
break;
}
case "DOMFullscreen:Painted": {
Services.obs.notifyObservers(this.contentWindow, "fullscreen-painted");
Services.obs.notifyObservers(window, "fullscreen-painted");
break;
}
}
......@@ -99,15 +113,20 @@ class DOMFullscreenChild extends JSWindowActorChild {
delete this._isNotTheRequestSource;
this.sendAsyncMessage(aEvent.type.replace("Moz", ""), {});
} else {
let rootWindow = this.contentWindow.windowRoot;
rootWindow.addEventListener("MozAfterPaint", this);
if (!this.document || !this.document.fullscreenElement) {
// If we receive any fullscreen change event, and find we are
// actually not in fullscreen, also ask the parent to exit to
// ensure that the parent always exits fullscreen when we do.
this.sendAsyncMessage("DOMFullscreen:Exit", {});
}
break;
}
if (this._waitForMozAfterPaint) {
delete this._waitForMozAfterPaint;
this._listeningWindow = this.contentWindow.windowRoot;
this._listeningWindow.addEventListener("MozAfterPaint", this);
}
if (!this.document || !this.document.fullscreenElement) {
// If we receive any fullscreen change event, and find we are
// actually not in fullscreen, also ask the parent to exit to
// ensure that the parent always exits fullscreen when we do.
this.sendAsyncMessage("DOMFullscreen:Exit", {});
}
break;
}
......@@ -120,8 +139,8 @@ class DOMFullscreenChild extends JSWindowActorChild {
!this._lastTransactionId ||
aEvent.transactionId > this._lastTransactionId
) {
let rootWindow = this.contentWindow.windowRoot;
rootWindow.removeEventListener("MozAfterPaint", this);
this._listeningWindow.removeEventListener("MozAfterPaint", this);
delete this._listeningWindow;
this.sendAsyncMessage("DOMFullscreen:Painted", {});
}
break;
......
......@@ -9,7 +9,19 @@ var EXPORTED_SYMBOLS = ["DOMFullscreenParent"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
class DOMFullscreenParent extends JSWindowActorParent {
waitingForChildFullscreen = false;
// These properties get set by browser-fullScreenAndPointerLock.js.
// TODO: Bug 1743703 - Consider moving the messaging component of
// browser-fullScreenAndPointerLock.js into the actor
waitingForChildEnterFullscreen = false;
waitingForChildExitFullscreen = false;
// Cache the next message recipient actor and in-process browsing context that
// is computed by _getNextMsgRecipientActor() of
// browser-fullScreenAndPointerLock.js, this is used to ensure the fullscreen
// cleanup messages goes the same route as fullscreen request, especially for
// the cleanup that happens after actor is destroyed.
// TODO: Bug 1743703 - Consider moving the messaging component of
// browser-fullScreenAndPointerLock.js into the actor
nextMsgRecipient = null;
updateFullscreenWindowReference(aWindow) {
if (aWindow.document.documentElement.hasAttribute("inDOMFullscreen")) {
......@@ -19,35 +31,71 @@ class DOMFullscreenParent extends JSWindowActorParent {
}
}
cleanupDomFullscreen(aWindow) {
if (!aWindow.FullScreen) {
return;
}
// If we don't need to wait for child reply, i.e. cleanupDomFullscreen
// doesn't message to child, and we've exit the fullscreen, there won't be
// DOMFullscreen:Painted message from child and it is possible that no more
// paint would be triggered, so just notify fullscreen-painted observer.
if (
!aWindow.FullScreen.cleanupDomFullscreen(this) &&
!aWindow.document.fullscreen
) {
Services.obs.notifyObservers(aWindow, "fullscreen-painted");
}
}
didDestroy() {
this._didDestroy = true;
let window = this._fullscreenWindow;
if (!window) {
if (this.waitingForChildExitFullscreen) {
this.waitingForChildExitFullscreen = false;
// We were destroyed while waiting for our DOMFullscreenChild to exit
// and have exited fullscreen, run cleanup steps anyway.
let topBrowsingContext = this.browsingContext.top;
let browser = topBrowsingContext.embedderElement;
if (browser) {
this.cleanupDomFullscreen(browser.ownerGlobal);
}
}
return;
}
if (this.waitingForChildFullscreen) {
// We were killed while waiting for our DOMFullscreenChild
// to transition to fullscreen so we abort the entire
// fullscreen transition to prevent getting stuck in a
// partial fullscreen state. We need to go through the
// document since window.Fullscreen could be undefined
// at this point.
//
// This could reject if we're not currently in fullscreen
// so just ignore rejection.
window.document.exitFullscreen().catch(() => {});
return;
if (this.waitingForChildEnterFullscreen) {
this.waitingForChildEnterFullscreen = false;
if (window.document.fullscreen) {
// We were destroyed while waiting for our DOMFullscreenChild
// to transition to fullscreen so we abort the entire
// fullscreen transition to prevent getting stuck in a
// partial fullscreen state. We need to go through the
// document since window.Fullscreen could be undefined
// at this point.
//
// This could reject if we're not currently in fullscreen
// so just ignore rejection.
window.document.exitFullscreen().catch(() => {});
return;
}
this.cleanupDomFullscreen(window);
}
// Need to resume Chrome UI if the window is still in fullscreen UI
// to avoid the window stays in fullscreen problem. (See Bug 1620341)
if (window.document.documentElement.hasAttribute("inDOMFullscreen")) {
if (window.FullScreen) {
window.FullScreen.cleanupDomFullscreen(this);
}
this.cleanupDomFullscreen(window);
if (window.windowUtils) {
window.windowUtils.remoteFrameFullscreenReverted();
}
} else if (this.waitingForChildExitFullscreen) {
this.waitingForChildExitFullscreen = false;
// We were destroyed while waiting for our DOMFullscreenChild to exit and
// have exited fullscreen, run cleanup steps anyway.
this.cleanupDomFullscreen(window);
}
this.updateFullscreenWindowReference(window);
}
......@@ -65,6 +113,8 @@ class DOMFullscreenParent extends JSWindowActorParent {
let window = browser.ownerGlobal;
switch (aMessage.name) {
case "DOMFullscreen:Request": {
this.waitingForChildExitFullscreen = false;
this.nextMsgRecipient = null;
this.requestOrigin = this;
this.addListeners(window);
window.windowUtils.remoteFrameFullscreenChanged(browser);
......@@ -77,24 +127,29 @@ class DOMFullscreenParent extends JSWindowActorParent {
aMessage.data.originNoSuffix
);
}
this.updateFullscreenWindowReference(window);
break;
}
case "DOMFullscreen:Entered": {
this.waitingForChildFullscreen = false;
this.nextMsgRecipient = null;
this.waitingForChildEnterFullscreen = false;
window.FullScreen.enterDomFullscreen(browser, this);
this.updateFullscreenWindowReference(window);
break;
}
case "DOMFullscreen:Exit": {
this.waitingForChildEnterFullscreen = false;
window.windowUtils.remoteFrameFullscreenReverted();
break;
}
case "DOMFullscreen:Exited": {
window.FullScreen.cleanupDomFullscreen(this);
this.waitingForChildExitFullscreen = false;
this.cleanupDomFullscreen(window);
this.updateFullscreenWindowReference(window);
break;
}
case "DOMFullscreen:Painted": {
this.waitingForChildExitFullscreen = false;
Services.obs.notifyObservers(window, "fullscreen-painted");
this.sendAsyncMessage("DOMFullscreen:Painted", {});
TelemetryStopwatch.finish("FULLSCREEN_CHANGE_MS");
......@@ -143,7 +198,7 @@ class DOMFullscreenParent extends JSWindowActorParent {
if (!this.hasBeenDestroyed() && !this.requestOrigin) {
this.requestOrigin = this;
}
window.FullScreen.cleanupDomFullscreen(this);
this.cleanupDomFullscreen(window);
this.updateFullscreenWindowReference(window);
this.removeListeners(window);
break;
......@@ -197,6 +252,10 @@ class DOMFullscreenParent extends JSWindowActorParent {
}
hasBeenDestroyed() {
if (this._didDestroy) {
return true;
}
// The 'didDestroy' callback is not always getting called.
// So we can't rely on it here. Instead, we will try to access
// the browsing context to judge wether the actor has
......
......@@ -285,7 +285,7 @@ class NetErrorParent extends JSWindowActorParent {
this.browser.reload();
break;
case "Browser:OpenCaptivePortalPage":
Services.obs.notifyObservers(null, "ensure-captive-portal-tab");
this.browser.ownerGlobal.CaptivePortalWatcher.ensureCaptivePortalTab();
break;
case "Browser:PrimeMitm":
this.primeMitm(this.browser);
......
......@@ -44,7 +44,6 @@ var CaptivePortalWatcher = {
},
init() {
Services.obs.addObserver(this, "ensure-captive-portal-tab");
Services.obs.addObserver(this, "captive-portal-login");
Services.obs.addObserver(this, "captive-portal-login-abort");
Services.obs.addObserver(this, "captive-portal-login-success");
......@@ -79,7 +78,6 @@ var CaptivePortalWatcher = {
},
uninit() {
Services.obs.removeObserver(this, "ensure-captive-portal-tab");
Services.obs.removeObserver(this, "captive-portal-login");
Services.obs.removeObserver(this, "captive-portal-login-abort");
Services.obs.removeObserver(this, "captive-portal-login-success");
......@@ -96,9 +94,6 @@ var CaptivePortalWatcher = {
observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "ensure-captive-portal-tab":
this.ensureCaptivePortalTab();
break;
case "captive-portal-login":
this._captivePortalDetected();
break;
......
......@@ -483,10 +483,10 @@ var FullScreen = {
remoteFrameBC: inProcessBC,
});
// Record that the actor is waiting for its child to enter
// fullscreen so that if it dies we can abort.
targetActor.waitingForChildFullscreen = true;
if (inProcessBC) {
// Record that the actor is waiting for its child to enter
// fullscreen so that if it dies we can abort.
targetActor.waitingForChildEnterFullscreen = true;
// We aren't messaging the request origin yet, skip this time.
return;
}
......@@ -562,13 +562,20 @@ var FullScreen = {
* the cleanup.
*/
cleanupDomFullscreen(aActor) {
let needToWaitForChildExit = false;
let [target, inProcessBC] = this._getNextMsgRecipientActor(aActor);
if (target) {
target.sendAsyncMessage("DOMFullscreen:CleanUp", {
remoteFrameBC: inProcessBC,
});
needToWaitForChildExit = true;
if (!target.waitingForChildExitFullscreen) {
// Record that the actor is waiting for its child to exit fullscreen so
// that if it dies we can continue cleanup.
target.waitingForChildExitFullscreen = true;
target.sendAsyncMessage("DOMFullscreen:CleanUp", {
remoteFrameBC: inProcessBC,
});
}
if (inProcessBC) {
return;
return needToWaitForChildExit;
}
}
......@@ -585,12 +592,17 @@ var FullScreen = {
);
document.documentElement.removeAttribute("inDOMFullscreen");
return needToWaitForChildExit;
},
_abortEnterFullscreen() {
// This function is called synchronously in fullscreen change, so
// we have to avoid calling exitFullscreen synchronously here.
setTimeout(() => document.exitFullscreen(), 0);
//
// This could reject if we're not currently in fullscreen
// so just ignore rejection.
setTimeout(() => document.exitFullscreen().catch(() => {}), 0);
if (TelemetryStopwatch.running("FULLSCREEN_CHANGE_MS")) {
// Cancel the stopwatch for any fullscreen change to avoid
// errors if it is started again.
......@@ -612,9 +624,27 @@ var FullScreen = {
* in process browsing context which is its child. Will be
* [null, null] if there is no OOP parent actor and request origin
* is unset. [null, null] is also returned if the intended actor or
* the calling actor has been destroyed.
* the calling actor has been destroyed or its associated
* WindowContext is in BFCache.
*/
_getNextMsgRecipientActor(aActor) {
// Walk up the cached nextMsgRecipient to find the next available actor if
// any.
if (aActor.nextMsgRecipient) {
let nextMsgRecipient = aActor.nextMsgRecipient;
while (nextMsgRecipient) {
let [actor] = nextMsgRecipient;
if (
!actor.hasBeenDestroyed() &&
actor.windowContext &&
!actor.windowContext.isInBFCache
) {
return nextMsgRecipient;
}
nextMsgRecipient = actor.nextMsgRecipient;
}
}
if (aActor.hasBeenDestroyed()) {
return [null, null];
}
......@@ -645,11 +675,16 @@ var FullScreen = {
if (parentBC && parentBC.currentWindowGlobal) {
target = parentBC.currentWindowGlobal.getActor("DOMFullscreen");
inProcessBC = childBC;
aActor.nextMsgRecipient = [target, inProcessBC];
} else {
target = aActor.requestOrigin;
}
if (!target || target.hasBeenDestroyed()) {
if (
!target ||
target.hasBeenDestroyed() ||
target.windowContext?.isInBFCache
) {
return [null, null];
}
return [target, inProcessBC];
......
......@@ -1095,7 +1095,7 @@ var gPopupBlockerObserver = {
// XXXjst - Note that when this is fixed to work with multi-framed sites,
// also back out the fix for bug 343772 where
// nsGlobalWindow::CheckOpenAllow() was changed to also
// check if the top window's location is whitelisted.
// check if the top window's location is allow-listed.
let browser = gBrowser.selectedBrowser;
var uriOrPrincipal = browser.contentPrincipal.isContentPrincipal
? browser.contentPrincipal
......@@ -1113,7 +1113,7 @@ var gPopupBlockerObserver = {
pm.testPermissionFromPrincipal(browser.contentPrincipal, "popup") ==
pm.ALLOW_ACTION
) {
// Offer an item to block popups for this site, if a whitelist entry exists
// Offer an item to block popups for this site, if an allow-list entry exists
// already for it.
let blockString = gNavigatorBundle.getFormattedString("popupBlock", [
uriHost,
......@@ -1132,12 +1132,6 @@ var gPopupBlockerObserver = {
blockedPopupAllowSite.hidden = true;
}
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
blockedPopupAllowSite.setAttribute("disabled", "true");
} else {
blockedPopupAllowSite.removeAttribute("disabled");
}
let blockedPopupDontShowMessage = document.getElementById(
"blockedPopupDontShowMessage"
);
......
......@@ -1607,6 +1607,7 @@
aTab.setAttribute("label", aLabel);
aTab.setAttribute("labeldirection", isRTL ? "rtl" : "ltr");
aTab.toggleAttribute("labelendaligned", isRTL != (document.dir == "rtl"));
// Dispatch TabAttrModified event unless we're setting the label
// before the TabOpen event was dispatched.
......
......@@ -28,10 +28,16 @@ async function checkCaptivePortalTabReference(evt, currState) {
portalTab != portalTab2,
"waitForNewTab in openCaptivePortalLoginTab should not have completed at this point if references were held to the old captive portal tab after login/abort."
);
gBrowser.removeTab(errorTab);
gBrowser.removeTab(portalTab);
gBrowser.removeTab(portalTab2);
let errorTabReloaded = BrowserTestUtils.waitForErrorPage(
errorTab.linkedBrowser
);
Services.obs.notifyObservers(null, "captive-portal-login-success");
await errorTabReloaded;
gBrowser.removeTab(errorTab);
}
add_task(async function setup() {
......
......@@ -18,7 +18,17 @@ add_task(async function checkCaptivePortalCertErrorUI() {
"Checking that the alternate cert error UI is shown when we are behind a captive portal"
);
// Open a second window in the background. Later, we'll check that
// when we click the button to open the captive portal tab, the tab
// only opens in the active window and not in the background one.
let secondWindow = await openWindowAndWaitForFocus();
await SimpleTest.promiseFocus(window);
await portalDetected();
// Check that we didn't open anything in the background window.
ensureNoPortalTab(secondWindow);
let tab = await openCaptivePortalErrorTab();
let browser = tab.linkedBrowser;
let portalTabPromise = BrowserTestUtils.waitForNewTab(
......@@ -50,6 +60,9 @@ add_task(async function checkCaptivePortalCertErrorUI() {
"Login page should be open in a new foreground tab."
);
// Check that we didn't open anything in the background window.
ensureNoPortalTab(secondWindow);
// Make sure clicking the "Open Login Page" button again focuses the existing portal tab.
await BrowserTestUtils.switchTab(gBrowser, tab);
// Passing an empty function to BrowserTestUtils.switchTab lets us wait for an arbitrary
......@@ -67,6 +80,9 @@ add_task(async function checkCaptivePortalCertErrorUI() {
let portalTab2 = await portalTabPromise;
is(portalTab2, portalTab, "The existing portal tab should be focused.");
// Check that we didn't open anything in the background window.
ensureNoPortalTab(secondWindow);
let portalTabClosing = BrowserTestUtils.waitForTabClosing(portalTab);
let errorTabReloaded = BrowserTestUtils.waitForErrorPage(browser);
......@@ -86,6 +102,7 @@ add_task(async function checkCaptivePortalCertErrorUI() {
});
await BrowserTestUtils.removeTab(tab);
await BrowserTestUtils.closeWindow(secondWindow);
});
add_task(async function testCaptivePortalAdvancedPanel() {
......@@ -142,5 +159,10 @@ add_task(async function testCaptivePortalAdvancedPanel() {
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
certOverrideService.clearValidityOverride("expired.example.com", -1, {});
let errorTabReloaded = BrowserTestUtils.waitForErrorPage(browser);
Services.obs.notifyObservers(null, "captive-portal-login-success");
await errorTabReloaded;
await BrowserTestUtils.removeTab(tab);
});
<
......@@ -4,7 +4,7 @@
const baseURL = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content",
"http://example.com"
"https://example.com"
);
function clearAllPermissionsByPrefix(aPrefix) {
......@@ -60,21 +60,42 @@ add_task(async function test_opening_blocked_popups() {
baseURL + "popup_blocker.html"
);
await testPopupBlockingToolbar(tab);
});
add_task(async function test_opening_blocked_popups_privateWindow() {
let win = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
// Open the test page.
let tab = await BrowserTestUtils.openNewForegroundTab(
win.gBrowser,
baseURL + "popup_blocker.html"
);
await testPopupBlockingToolbar(tab);
await BrowserTestUtils.closeWindow(win);
});
async function testPopupBlockingToolbar(tab) {
let win = tab.ownerGlobal;
// Wait for the popup-blocked notification.
let notification;
await TestUtils.waitForCondition(
() =>
(notification = gBrowser
(notification = win.gBrowser
.getNotificationBox()
.getNotificationWithValue("popup-blocked"))
);
// Show the menu.
let popupShown = BrowserTestUtils.waitForEvent(window, "popupshown");
let popupFilled = waitForBlockedPopups(2);
let popupShown = BrowserTestUtils.waitForEvent(win, "popupshown");
let popupFilled = waitForBlockedPopups(2, {
doc: win.document,
});
EventUtils.synthesizeMouseAtCenter(
notification.buttonContainer.querySelector("button"),
{}
{},
win
);
let popup_event = await popupShown;
let menu = popup_event.target;
......@@ -87,10 +108,10 @@ add_task(async function test_opening_blocked_popups() {
function onTabOpen(event) {
popupTabs.push(event.target);
}