Bug 1696718 - Propagate popup window position update to descendants documents. r=kmag

Differential Revision: https://phabricator.services.mozilla.com/D108559
This commit is contained in:
Hiroyuki Ikezoe 2021-03-18 03:11:23 +00:00
Родитель 73695d66b4
Коммит 9a4563134c
5 изменённых файлов: 166 добавлений и 0 удалений

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

@ -172,6 +172,8 @@ disabled = bug 1438663
[browser_ext_popup_requestPermission.js]
[browser_ext_popup_select.js]
skip-if = debug || os != 'win' # FIXME: re-enable on debug build (bug 1442822)
[browser_ext_popup_select_in_oopif.js]
skip-if = tsan # bug 1699341
[browser_ext_popup_sendMessage.js]
[browser_ext_popup_shutdown.js]
[browser_ext_port_disconnect_on_crash.js]

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

@ -0,0 +1,120 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
// This test is based on browser_ext_popup_select.js.
const iframeSrc = encodeURIComponent(`
<html>
<style>
html,body {
margin: 0;
padding: 0;
}
</style>
<select>
<option>Foo</option>
<option>Bar</option>
<option>Baz</option>
</select>
</html>`);
add_task(async function testPopupSelectPopup() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
browser_action: {
default_popup: "popup.html",
browser_style: false,
},
},
files: {
"popup.html": `<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<style>
html,body {
margin: 0;
padding: 0;
}
iframe {
border: none;
}
</style>
<body>
<iframe src="https://example.com/document-builder.sjs?html=${iframeSrc}">
</iframe>
</body>
</html>`,
},
});
await extension.startup();
const browserForPopup = await openBrowserActionPanel(
extension,
undefined,
true
);
const iframe = await SpecialPowers.spawn(browserForPopup, [], async () => {
await ContentTaskUtils.waitForCondition(() => {
return content.document && content.document.querySelector("iframe");
});
const iframeElement = content.document.querySelector("iframe");
await ContentTaskUtils.waitForCondition(() => {
return iframeElement.browsingContext;
});
return iframeElement.browsingContext;
});
const selectRect = await SpecialPowers.spawn(iframe, [], async () => {
await ContentTaskUtils.waitForCondition(() => {
return content.document.querySelector("select");
});
const select = content.document.querySelector("select");
const focusPromise = new Promise(resolve => {
select.addEventListener("focus", resolve, { once: true });
});
select.focus();
await focusPromise;
const r = select.getBoundingClientRect();
return { left: r.left, bottom: r.bottom };
});
const selectPopup = document.getElementById("ContentSelectDropdown")
.firstElementChild;
const popupPromise = promisePopupShown(selectPopup);
BrowserTestUtils.synthesizeMouseAtCenter("select", {}, iframe);
await popupPromise;
let popupRect = selectPopup.getOuterScreenRect();
is(
Math.floor(browserForPopup.screenX + selectRect.left),
popupRect.left,
"Select popup has the correct x origin"
);
// On Mac select popup window appears on the target select element.
let expectedY = navigator.platform.includes("Mac")
? Math.floor(browserForPopup.screenY)
: Math.floor(browserForPopup.screenY + selectRect.bottom);
is(expectedY, popupRect.top, "Select popup has the correct y origin");
const onPopupHidden = BrowserTestUtils.waitForEvent(
selectPopup,
"popuphidden"
);
selectPopup.hidePopup();
await onPopupHidden;
await closeBrowserAction(extension);
await extension.unload();
});

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

@ -1065,6 +1065,20 @@ nsresult BrowserParent::UpdatePosition() {
return NS_OK;
}
void BrowserParent::NotifyPositionUpdatedForContentsInPopup() {
if (CanonicalBrowsingContext* bc = GetBrowsingContext()) {
bc->PreOrderWalk([](BrowsingContext* aContext) {
if (WindowGlobalParent* windowGlobalParent =
aContext->Canonical()->GetCurrentWindowGlobal()) {
if (RefPtr<BrowserParent> browserParent =
windowGlobalParent->GetBrowserParent()) {
browserParent->UpdatePosition();
}
}
});
}
}
void BrowserParent::UpdateDimensions(const nsIntRect& rect,
const ScreenIntSize& size) {
if (mIsDestroyed) {

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

@ -474,6 +474,11 @@ class BrowserParent final : public PBrowserParent,
nsresult UpdatePosition();
// Notify position update to all descendant documents in this browser parent.
// NOTE: This should use only for browsers in popup windows attached to the
// main browser window.
void NotifyPositionUpdatedForContentsInPopup();
void SizeModeChanged(const nsSizeMode& aSizeMode);
void HandleAccessKey(const WidgetKeyboardEvent& aEvent,

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

@ -52,6 +52,7 @@
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_xul.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/KeyboardEvent.h"
@ -1339,6 +1340,22 @@ nsRect nsMenuPopupFrame::ComputeAnchorRect(nsPresContext* aRootPresContext,
PresContext()->AppUnitsPerDevPixel());
}
static void NotifyPositionUpdatedForRemoteContents(nsIContent* aContent) {
for (nsIContent* content = aContent->GetFirstChild(); content;
content = content->GetNextSibling()) {
if (content->IsXULElement(nsGkAtoms::browser) &&
content->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::remote,
nsGkAtoms::_true, eIgnoreCase)) {
if (dom::BrowserParent* browserParent =
dom::BrowserParent::GetFrom(content)) {
browserParent->NotifyPositionUpdatedForContentsInPopup();
}
} else {
NotifyPositionUpdatedForRemoteContents(content);
}
}
}
nsresult nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame,
bool aIsMove, bool aSizedToPopup) {
if (!mShouldAutoPosition) return NS_OK;
@ -1695,6 +1712,14 @@ nsresult nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame,
}
}
// In the case this popup has remote contents having OOP iframes, it's
// possible that OOP iframe's nsSubDocumentFrame has been already reflowed
// thus, we will never have a chance to tell this parent browser's position
// update to the OOP documents without notifying it explicitly.
if (HasRemoteContent()) {
NotifyPositionUpdatedForRemoteContents(mContent);
}
return NS_OK;
}