Bug 1708324 - [Fission] Full screen button for YouTube video embedded on Reddit doesn't work r=spohl

During fullscreen transitions on Mac, ignore occlusion events caused by the widget DOM fullscreen transition effect which uses a temporary window.

Add a test that attempts to enter fullscreen from a non-focused window. This test is to ensure the fix (and future fixes) do not regress the focus requirement for fullscreen.

Differential Revision: https://phabricator.services.mozilla.com/D115046
This commit is contained in:
Haik Aftandilian 2021-05-18 04:54:25 +00:00
Родитель 30aa92212a
Коммит e84c0b8236
6 изменённых файлов: 123 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Focus test - child window</title>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
</head>
<body>
<script type="application/javascript">
function enterFullscreen() {
addFullscreenErrorContinuation(() => { opener.enteredFullscreen(false); });
addFullscreenChangeContinuation("enter", () => {
opener.enteredFullscreen(true);
});
document.body.requestFullscreen();
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<!--
Test that a fullscreen request fails if the window is not focused.
Open window1, open window2, focus window2, and then attempt to fullscreen
window1 while it is not focused. The fullscreen attempt should be rejected
because the window is not focused.
-->
<head>
<title>Test fullscreen request is blocked when window is not focused</title>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="file_fullscreen-utils.js"></script>
</head>
<body>
<script type="application/javascript">
function ok(condition, msg) {
opener.ok(condition, "[focus] " + msg);
}
var window1, window2;
function openWindow() {
var w = window.open("file_fullscreen-focus-inner.html", "",
"width=500,height=500");
return w;
}
function begin() {
window1 = openWindow();
window1.focus();
SimpleTest.waitForFocus(function(){
window2 = openWindow();
window2.focus();
SimpleTest.waitForFocus(function(){
// Now that window2 is focused, attempt to fullscreen window1.
// This should fail.
window1.enterFullscreen("one");
}, window2);
}, window1);
}
async function enteredFullscreen(enteredSuccessfully) {
ok(!enteredSuccessfully, "window1 did not enter fullscreen");
if (enteredSuccessfully) {
await window1.document.exitFullscreen()
}
window1.close();
window2.close();
opener.nextTest();
}
</script>
</pre>
<div id="full-screen-element"></div>
</body>
</html>

Просмотреть файл

@ -451,6 +451,8 @@ support-files =
file_fullscreen-event-order.html
file_fullscreen-featurePolicy.html
file_fullscreen-featurePolicy-inner.html
file_fullscreen-focus.html
file_fullscreen-focus-inner.html
file_fullscreen-hidden.html
file_fullscreen-lenient-setters.html
file_fullscreen-multiple-inner.html

Просмотреть файл

@ -36,6 +36,7 @@ var gTestWindows = [
{ test: "file_fullscreen-denied.html" },
{ test: "file_fullscreen-api.html" },
{ test: "file_fullscreen-hidden.html" },
{ test: "file_fullscreen-focus.html" },
{ test: "file_fullscreen-svg-element.html" },
{ test: "file_fullscreen-navigation.html" },
{ test: "file_fullscreen-scrollbar.html" },

Просмотреть файл

@ -265,6 +265,7 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
virtual bool PrepareForFullscreenTransition(nsISupports** aData) override;
virtual void PerformFullscreenTransition(FullscreenTransitionStage aStage, uint16_t aDuration,
nsISupports* aData, nsIRunnable* aCallback) override;
virtual void CleanupFullscreenTransition() override;
nsresult MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen = nullptr) final;
nsresult MakeFullScreenWithNativeTransition(bool aFullScreen,
nsIScreen* aTargetScreen = nullptr) final;
@ -409,6 +410,12 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {
bool mInFullScreenMode;
bool mInFullScreenTransition; // true from the request to enter/exit fullscreen
// (MakeFullScreen() call) to EnteredFullScreen()
// Ignore occlusion events caused by displaying the temporary fullscreen
// window during the fullscreen transition animation because only focused
// contexts are permitted to enter DOM fullscreen.
int mIgnoreOcclusionCount;
bool mModal;
bool mFakeModal;

Просмотреть файл

@ -136,6 +136,7 @@ nsCocoaWindow::nsCocoaWindow()
mSheetNeedsShow(false),
mInFullScreenMode(false),
mInFullScreenTransition(false),
mIgnoreOcclusionCount(0),
mModal(false),
mFakeModal(false),
mInNativeFullScreenMode(false),
@ -1516,6 +1517,17 @@ static bool AlwaysUsesNativeFullScreen() {
if (AlwaysUsesNativeFullScreen()) {
return false;
}
// Our fullscreen transition creates a new window occluding this window.
// That triggers an occlusion event which can cause DOM fullscreen requests
// to fail due to the context not being focused at the time the focus check
// is performed in the child process. Until the transition is cleaned up in
// CleanupFullscreenTransition(), ignore occlusion events for this window.
// If this method is changed to return false, the transition will not be
// performed and mIgnoreOcclusionCount should not be incremented.
MOZ_ASSERT(mIgnoreOcclusionCount >= 0);
mIgnoreOcclusionCount++;
nsCOMPtr<nsIScreen> widgetScreen = GetWidgetScreen();
NSScreen* cocoaScreen = ScreenHelperCocoa::CocoaScreenForScreen(widgetScreen);
@ -1535,6 +1547,11 @@ static bool AlwaysUsesNativeFullScreen() {
return true;
}
/* virtual */ void nsCocoaWindow::CleanupFullscreenTransition() {
MOZ_ASSERT(mIgnoreOcclusionCount > 0);
mIgnoreOcclusionCount--;
}
/* virtual */ void nsCocoaWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage,
uint16_t aDuration,
nsISupports* aData,
@ -2048,6 +2065,11 @@ void nsCocoaWindow::DispatchOcclusionEvent() {
return;
}
MOZ_ASSERT(mIgnoreOcclusionCount >= 0);
if (newOcclusionState && mIgnoreOcclusionCount > 0) {
return;
}
mIsFullyOccluded = newOcclusionState;
if (mWidgetListener) {
mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);