From e84c0b82361d2d12494073c130f524e6386d90f4 Mon Sep 17 00:00:00 2001 From: Haik Aftandilian Date: Tue, 18 May 2021 04:54:25 +0000 Subject: [PATCH] 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 --- .../test/file_fullscreen-focus-inner.html | 24 +++++++ dom/html/test/file_fullscreen-focus.html | 67 +++++++++++++++++++ dom/html/test/mochitest.ini | 2 + dom/html/test/test_fullscreen-api.html | 1 + widget/cocoa/nsCocoaWindow.h | 7 ++ widget/cocoa/nsCocoaWindow.mm | 22 ++++++ 6 files changed, 123 insertions(+) create mode 100644 dom/html/test/file_fullscreen-focus-inner.html create mode 100644 dom/html/test/file_fullscreen-focus.html diff --git a/dom/html/test/file_fullscreen-focus-inner.html b/dom/html/test/file_fullscreen-focus-inner.html new file mode 100644 index 000000000000..73d39a9d83e5 --- /dev/null +++ b/dom/html/test/file_fullscreen-focus-inner.html @@ -0,0 +1,24 @@ + + + + Focus test - child window + + + + + + + + diff --git a/dom/html/test/file_fullscreen-focus.html b/dom/html/test/file_fullscreen-focus.html new file mode 100644 index 000000000000..be91025f45e9 --- /dev/null +++ b/dom/html/test/file_fullscreen-focus.html @@ -0,0 +1,67 @@ + + + + + Test fullscreen request is blocked when window is not focused + + + + + + + + +
+ + diff --git a/dom/html/test/mochitest.ini b/dom/html/test/mochitest.ini index 7bd06dc17de0..819b6a5ada07 100644 --- a/dom/html/test/mochitest.ini +++ b/dom/html/test/mochitest.ini @@ -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 diff --git a/dom/html/test/test_fullscreen-api.html b/dom/html/test/test_fullscreen-api.html index c29e21f24048..583c3bd755c6 100644 --- a/dom/html/test/test_fullscreen-api.html +++ b/dom/html/test/test_fullscreen-api.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" }, diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index 182e7ec88925..499fe2c66296 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -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; diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index 5f4eba4c44e4..45593c31474f 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -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 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);