From 47e66cd7d982a59b1cce803d0d777130ee72f19c Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Wed, 7 Jul 2021 12:08:18 +0000 Subject: [PATCH] Bug 1716762 - Don't allow focus to move to remote iframe which is display: none; r=emilio Make it behave the same as in-process iframe. Differential Revision: https://phabricator.services.mozilla.com/D118002 --- docshell/base/nsDocShell.cpp | 5 + dom/base/nsFrameLoader.cpp | 19 +++ dom/base/nsFrameLoader.h | 2 + dom/base/nsFrameLoaderOwner.cpp | 4 + ...cus_display_none_xorigin_iframe_inner.html | 15 ++ dom/base/test/mochitest.ini | 3 + ...est_focus_display_none_xorigin_iframe.html | 134 ++++++++++++++++++ layout/generic/nsSubDocumentFrame.cpp | 1 + 8 files changed, 183 insertions(+) create mode 100644 dom/base/test/file_focus_display_none_xorigin_iframe_inner.html create mode 100644 dom/base/test/test_focus_display_none_xorigin_iframe.html diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index bfa9469d9e0e..29f3dc480dd9 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -7990,6 +7990,7 @@ nsresult nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer, } nscolor bgcolor = NS_RGBA(0, 0, 0, 0); + bool isUnderHiddenEmbedderElement = false; // Ensure that the content viewer is destroyed *after* the GC - bug 71515 nsCOMPtr contentViewer = mContentViewer; if (contentViewer) { @@ -8001,6 +8002,7 @@ nsresult nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer, // presentation shell, so we can use it for the next document. if (PresShell* presShell = contentViewer->GetPresShell()) { bgcolor = presShell->GetCanvasBackground(); + isUnderHiddenEmbedderElement = presShell->IsUnderHiddenEmbedderElement(); } contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr); @@ -8046,6 +8048,9 @@ nsresult nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer, if (RefPtr presShell = mContentViewer->GetPresShell()) { presShell->SetCanvasBackground(bgcolor); presShell->ActivenessMaybeChanged(); + if (isUnderHiddenEmbedderElement) { + presShell->SetIsUnderHiddenEmbedderElement(isUnderHiddenEmbedderElement); + } } // XXX: It looks like the LayoutState gets restored again in Embed() diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index f4919c8af85e..7e960a31f10d 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -2473,6 +2473,25 @@ void nsFrameLoader::SendIsUnderHiddenEmbedderElement( } } +void nsFrameLoader::PropagateIsUnderHiddenEmbedderElement( + bool aIsUnderHiddenEmbedderElement) { + bool isUnderHiddenEmbedderElement = true; + if (Document* ownerDoc = GetOwnerDoc()) { + if (PresShell* presShell = ownerDoc->GetPresShell()) { + isUnderHiddenEmbedderElement = presShell->IsUnderHiddenEmbedderElement(); + } + } + + isUnderHiddenEmbedderElement |= aIsUnderHiddenEmbedderElement; + if (nsDocShell* docShell = GetExistingDocShell()) { + if (PresShell* presShell = docShell->GetPresShell()) { + presShell->SetIsUnderHiddenEmbedderElement(isUnderHiddenEmbedderElement); + } + } else { + SendIsUnderHiddenEmbedderElement(isUnderHiddenEmbedderElement); + } +} + void nsFrameLoader::UpdateBaseWindowPositionAndSize( nsSubDocumentFrame* aIFrame) { nsCOMPtr baseWindow = GetDocShell(IgnoreErrors()); diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h index 923aa91ad79c..0d96f8d00486 100644 --- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -144,6 +144,8 @@ class nsFrameLoader final : public nsStubMutationObserver, } nsresult UpdatePositionAndSize(nsSubDocumentFrame* aIFrame); void SendIsUnderHiddenEmbedderElement(bool aIsUnderHiddenEmbedderElement); + void PropagateIsUnderHiddenEmbedderElement( + bool aIsUnderHiddenEmbedderElement); // When creating a nsFrameLoaderOwner which is a static clone, a // `nsFrameLoader` is not immediately attached to it. Instead, it is added to diff --git a/dom/base/nsFrameLoaderOwner.cpp b/dom/base/nsFrameLoaderOwner.cpp index fa8b31f416b7..a742ba38f9ce 100644 --- a/dom/base/nsFrameLoaderOwner.cpp +++ b/dom/base/nsFrameLoaderOwner.cpp @@ -213,6 +213,10 @@ void nsFrameLoaderOwner::ChangeFrameLoaderCommon(Element* aOwner) { mozilla::ChromeOnlyDispatch::eYes)) ->RunDOMEventWhenSafe(); } + + mFrameLoader->PropagateIsUnderHiddenEmbedderElement( + !aOwner->GetPrimaryFrame() || + !aOwner->GetPrimaryFrame()->StyleVisibility()->IsVisible()); } void nsFrameLoaderOwner::ChangeRemoteness( diff --git a/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html b/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html new file mode 100644 index 000000000000..5831df882cae --- /dev/null +++ b/dom/base/test/file_focus_display_none_xorigin_iframe_inner.html @@ -0,0 +1,15 @@ + + +

Inner

+
+ diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index a5fc7821dd74..e287a0d10ae8 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -669,6 +669,9 @@ skip-if = toolkit == 'android' && !is_fennec # Bug 1525959 [test_focus_design_mode.html] support-files = file_focus_design_mode_inner.html +[test_focus_display_none_xorigin_iframe.html] +support-files = + file_focus_display_none_xorigin_iframe_inner.html [test_getAttribute_after_createAttribute.html] [test_getElementById.html] [test_getTranslationNodes.html] diff --git a/dom/base/test/test_focus_display_none_xorigin_iframe.html b/dom/base/test/test_focus_display_none_xorigin_iframe.html new file mode 100644 index 000000000000..b04141b0fef0 --- /dev/null +++ b/dom/base/test/test_focus_display_none_xorigin_iframe.html @@ -0,0 +1,134 @@ + + + + + +Test for Bug 1716762 + + + + +Mozilla Bug 1716762
+
+ + + + diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 8fc0c1886c36..82440a4461f4 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -895,6 +895,7 @@ static nsView* BeginSwapDocShellsForViews(nsView* aSibling); void nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) { + PropagateIsUnderHiddenEmbedderElementToSubView(true); if (mPostedReflowCallback) { PresShell()->CancelReflowCallback(this); mPostedReflowCallback = false;