Bug 1585070 - move nsPIDOMWindowOuter::mIsActive to BrowsingContext. r=kmag

A new `BrowsingContext` field has been added to track the active
browser window for the `:-moz-window-inactive` pseudoclass. This
field takes the place of `nsPIDOMWindowOuter::mIsActive`.

With this change `:-moz-window-inactive` is now fission compatible.

Differential Revision: https://phabricator.services.mozilla.com/D86422
This commit is contained in:
Steven MacLeod 2020-11-20 15:16:58 +00:00
parent 271d075cff
commit 6cd960cfb3
18 changed files with 233 additions and 254 deletions

View File

@ -4,98 +4,110 @@
/* eslint-env mozilla/frame-script */
const testPage = getRootDirectory(gTestPath) + "file_window_activation.html";
const testPage2 = getRootDirectory(gTestPath) + "file_window_activation2.html";
const testPageChrome =
getRootDirectory(gTestPath) + "file_window_activation.html";
const testPageHttp = testPageChrome.replace(
"chrome://mochitests/content",
"http://example.com"
);
const testPageWindow =
getRootDirectory(gTestPath) + "file_window_activation2.html";
add_task(async function reallyRunTests() {
let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, testPage);
let browser1 = tab1.linkedBrowser;
let chromeTab1 = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
testPageChrome
);
let chromeBrowser1 = chromeTab1.linkedBrowser;
// This can't use openNewForegroundTab because if we focus tab2 now, we
// This can't use openNewForegroundTab because if we focus chromeTab2 now, we
// won't send a focus event during test 6, further down in this file.
let tab2 = BrowserTestUtils.addTab(gBrowser, testPage);
let browser2 = tab2.linkedBrowser;
await BrowserTestUtils.browserLoaded(browser2);
let chromeTab2 = BrowserTestUtils.addTab(gBrowser, testPageChrome);
let chromeBrowser2 = chromeTab2.linkedBrowser;
await BrowserTestUtils.browserLoaded(chromeBrowser2);
let httpTab = BrowserTestUtils.addTab(gBrowser, testPageHttp);
let httpBrowser = httpTab.linkedBrowser;
await BrowserTestUtils.browserLoaded(httpBrowser);
function failTest() {
ok(false, "Test received unexpected activate/deactivate event");
}
// The content should not receive activate or deactivate events. If it
// does, fail the test.
BrowserTestUtils.waitForContentEvent(browser1, "activate", true).then(
failTest
);
BrowserTestUtils.waitForContentEvent(browser2, "activate", true).then(
failTest
);
BrowserTestUtils.waitForContentEvent(browser1, "deactivate", true).then(
failTest
);
BrowserTestUtils.waitForContentEvent(browser2, "deactivate", true).then(
failTest
);
// chrome:// url tabs should not receive "activate" or "deactivate" events
// as they should be sent to the top-level window in the parent process.
for (let b of [chromeBrowser1, chromeBrowser2]) {
BrowserTestUtils.waitForContentEvent(b, "activate", true).then(failTest);
BrowserTestUtils.waitForContentEvent(b, "deactivate", true).then(failTest);
}
gURLBar.focus();
gBrowser.selectedTab = tab1;
gBrowser.selectedTab = chromeTab1;
// The test performs four checks, using -moz-window-inactive on two child tabs.
// The test performs four checks, using -moz-window-inactive on three child
// tabs (2 loading chrome:// urls and one loading an http:// url).
// First, the initial state should be transparent. The second check is done
// while another window is focused. The third check is done after that window
// is closed and the main window focused again. The fourth check is done after
// switching to the second tab.
// Step 1 - check the initial state
let colorBrowser1 = await getBackgroundColor(browser1, true);
let colorBrowser2 = await getBackgroundColor(browser2, true);
is(colorBrowser1, "rgba(0, 0, 0, 0)", "first window initial");
is(colorBrowser2, "rgba(0, 0, 0, 0)", "second window initial");
let colorChromeBrowser1 = await getBackgroundColor(chromeBrowser1, true);
let colorChromeBrowser2 = await getBackgroundColor(chromeBrowser2, true);
let colorHttpBrowser = await getBackgroundColor(httpBrowser, true);
is(colorChromeBrowser1, "rgba(0, 0, 0, 0)", "first tab initial");
is(colorChromeBrowser2, "rgba(0, 0, 0, 0)", "second tab initial");
is(colorHttpBrowser, "rgba(0, 0, 0, 0)", "third tab initial");
// Step 2 - open and focus another window
let otherWindow = window.open(testPage2, "", "chrome");
let otherWindow = window.open(testPageWindow, "", "chrome");
await SimpleTest.promiseFocus(otherWindow);
colorBrowser1 = await getBackgroundColor(browser1, true);
colorBrowser2 = await getBackgroundColor(browser2, true);
is(colorBrowser1, "rgb(255, 0, 0)", "first window lowered");
is(colorBrowser2, "rgb(255, 0, 0)", "second window lowered");
colorChromeBrowser1 = await getBackgroundColor(chromeBrowser1, false);
colorChromeBrowser2 = await getBackgroundColor(chromeBrowser2, false);
colorHttpBrowser = await getBackgroundColor(httpBrowser, false);
is(colorChromeBrowser1, "rgb(255, 0, 0)", "first tab lowered");
is(colorChromeBrowser2, "rgb(255, 0, 0)", "second tab lowered");
is(colorHttpBrowser, "rgb(255, 0, 0)", "third tab lowered");
// Step 3 - close the other window again
otherWindow.close();
colorBrowser1 = await getBackgroundColor(browser1, true);
colorBrowser2 = await getBackgroundColor(browser2, true);
is(colorBrowser1, "rgba(0, 0, 0, 0)", "first window raised");
is(colorBrowser2, "rgba(0, 0, 0, 0)", "second window raised");
colorChromeBrowser1 = await getBackgroundColor(chromeBrowser1, true);
colorChromeBrowser2 = await getBackgroundColor(chromeBrowser2, true);
colorHttpBrowser = await getBackgroundColor(httpBrowser, true);
is(colorChromeBrowser1, "rgba(0, 0, 0, 0)", "first tab raised");
is(colorChromeBrowser2, "rgba(0, 0, 0, 0)", "second tab raised");
is(colorHttpBrowser, "rgba(0, 0, 0, 0)", "third tab raised");
// Step 4 - switch to the second tab
gBrowser.selectedTab = tab2;
colorBrowser1 = await getBackgroundColor(browser1, false);
colorBrowser2 = await getBackgroundColor(browser2, false);
is(colorBrowser1, "rgba(0, 0, 0, 0)", "first window after tab switch");
is(colorBrowser2, "rgba(0, 0, 0, 0)", "second window after tab switch");
gBrowser.selectedTab = chromeTab2;
colorChromeBrowser1 = await getBackgroundColor(chromeBrowser1, true);
colorChromeBrowser2 = await getBackgroundColor(chromeBrowser2, true);
colorHttpBrowser = await getBackgroundColor(httpBrowser, true);
is(colorChromeBrowser1, "rgba(0, 0, 0, 0)", "first tab after tab switch");
is(colorChromeBrowser2, "rgba(0, 0, 0, 0)", "second tab after tab switch");
is(colorHttpBrowser, "rgba(0, 0, 0, 0)", "third tab after tab switch");
BrowserTestUtils.removeTab(tab1);
BrowserTestUtils.removeTab(tab2);
BrowserTestUtils.removeTab(chromeTab1);
BrowserTestUtils.removeTab(chromeTab2);
BrowserTestUtils.removeTab(httpTab);
otherWindow = null;
});
function getBackgroundColor(browser, ifChanged) {
return SpecialPowers.spawn(browser, [], () => {
return new Promise(resolve => {
let oldColor = null;
let timer = content.setInterval(() => {
let area = content.document.getElementById("area");
if (!area) {
return; /* hasn't loaded yet */
}
function getBackgroundColor(browser, expectedActive) {
return SpecialPowers.spawn(
browser,
[!expectedActive],
async hasPseudoClass => {
let area = content.document.getElementById("area");
await ContentTaskUtils.waitForCondition(() => {
return area;
}, "Page has loaded");
await ContentTaskUtils.waitForCondition(() => {
return area.matches(":-moz-window-inactive") == hasPseudoClass;
}, `Window is considered ${hasPseudoClass ? "inactive" : "active"}`);
let color = content.getComputedStyle(area).backgroundColor;
if (oldColor != color || !ifChanged) {
content.clearInterval(timer);
oldColor = color;
resolve(color);
}
}, 20);
});
});
return content.getComputedStyle(area).backgroundColor;
}
);
}

View File

@ -542,6 +542,23 @@ void BrowsingContext::CleanUpDanglingRemoteOuterWindowProxies(
js::RemapRemoteWindowProxies(aCx, &cb, aOuter);
}
bool BrowsingContext::GetIsActiveBrowserWindow() {
if (!XRE_IsParentProcess()) {
return Top()->GetIsActiveBrowserWindowInternal();
}
// chrome:// urls loaded in the parent won't receive
// their own activation so we defer to the top chrome
// Browsing Context when in the parent process.
RefPtr<CanonicalBrowsingContext> chromeTop =
Canonical()->TopCrossChromeBoundary();
return chromeTop->GetIsActiveBrowserWindowInternal();
}
void BrowsingContext::SetIsActiveBrowserWindow(bool aActive) {
Unused << SetIsActiveBrowserWindowInternal(aActive);
}
bool BrowsingContext::FullscreenAllowed() const {
for (auto* current = this; current; current = current->GetParent()) {
if (!current->GetFullscreenAllowedByOwner()) {
@ -2311,6 +2328,36 @@ bool BrowsingContext::CheckOnlyOwningProcessCanSet(ContentParent* aSource) {
return true;
}
bool BrowsingContext::CanSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>,
const bool& aValue, ContentParent* aSource) {
// Should only be set in the parent process.
return XRE_IsParentProcess() && !aSource && IsTop();
}
void BrowsingContext::DidSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>,
bool aOldValue) {
bool isActivateEvent = GetIsActiveBrowserWindowInternal();
// The browser window containing this context has changed
// activation state so update window inactive document states
// for all in-process documents.
PreOrderWalk([isActivateEvent](BrowsingContext* aContext) {
if (RefPtr<Document> doc = aContext->GetExtantDocument()) {
doc->UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE, true);
if (XRE_IsContentProcess() &&
(!aContext->GetParent() || !aContext->GetParent()->IsInProcess())) {
// Send the inner window an activate/deactivate event if
// the context is the top of a sub-tree of in-process
// contexts.
nsContentUtils::DispatchEventOnlyToChrome(
doc, doc->GetWindow()->GetCurrentInnerWindow(),
isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
CanBubble::eYes, Cancelable::eYes, nullptr);
}
}
});
}
bool BrowsingContext::CanSet(FieldIndex<IDX_AllowContentRetargeting>,
const bool& aAllowContentRetargeting,
ContentParent* aSource) {

View File

@ -96,6 +96,10 @@ class WindowProxyHolder;
/* If true, we're within the nested event loop in window.open, and this \
* context may not be used as the target of a load */ \
FIELD(PendingInitialization, bool) \
/* Indicates if the browser window is active for the purpose of the \
* :-moz-window-inactive pseudoclass. Only read from or set on the \
* top BrowsingContext. */ \
FIELD(IsActiveBrowserWindowInternal, bool) \
FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy) \
/* Current opener for the BrowsingContext. Weak reference */ \
FIELD(OpenerId, uint64_t) \
@ -287,6 +291,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
Document* GetDocument() const {
return mDocShell ? mDocShell->GetDocument() : nullptr;
}
Document* GetExtantDocument() const {
return mDocShell ? mDocShell->GetExtantDocument() : nullptr;
}
// This cleans up remote outer window proxies that might have been left behind
// when the browsing context went from being remote to local. It does this by
@ -484,6 +491,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
bool UseGlobalHistory() const { return GetUseGlobalHistory(); }
bool GetIsActiveBrowserWindow();
void SetIsActiveBrowserWindow(bool aActive);
uint64_t BrowserId() const { return GetBrowserId(); }
bool IsLoading();
@ -852,6 +863,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
void DidSet(FieldIndex<IDX_IsActive>, bool aOldValue);
bool CanSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>, const bool& aValue,
ContentParent* aSource);
void DidSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>, bool aOldValue);
// Ensure that we only set the flag on the top level browsingContext.
// And then, we do a pre-order walk in the tree to refresh the
// volume of all media elements.

View File

@ -263,12 +263,18 @@ CanonicalBrowsingContext::GetParentCrossChromeBoundary() {
return nullptr;
}
Nullable<WindowProxyHolder> CanonicalBrowsingContext::GetTopChromeWindow() {
already_AddRefed<CanonicalBrowsingContext>
CanonicalBrowsingContext::TopCrossChromeBoundary() {
RefPtr<CanonicalBrowsingContext> bc(this);
while (RefPtr<CanonicalBrowsingContext> parent =
bc->GetParentCrossChromeBoundary()) {
bc = parent.forget();
}
return bc.forget();
}
Nullable<WindowProxyHolder> CanonicalBrowsingContext::GetTopChromeWindow() {
RefPtr<CanonicalBrowsingContext> bc = TopCrossChromeBoundary();
if (bc->IsChrome()) {
return WindowProxyHolder(bc.forget());
}
@ -428,6 +434,34 @@ CanonicalBrowsingContext::ReplaceLoadingSessionHistoryEntryForLoad(
return MakeUnique<LoadingSessionHistoryInfo>(newEntry, aInfo->mLoadId);
}
void CanonicalBrowsingContext::CallOnAllTopDescendants(
const std::function<mozilla::CallState(CanonicalBrowsingContext*)>&
aCallback) {
#ifdef DEBUG
RefPtr<CanonicalBrowsingContext> parent = GetParentCrossChromeBoundary();
MOZ_ASSERT(!parent, "Should only call on top chrome BC");
#endif
nsTArray<RefPtr<BrowsingContextGroup>> groups;
BrowsingContextGroup::GetAllGroups(groups);
for (auto& browsingContextGroup : groups) {
for (auto& bc : browsingContextGroup->Toplevels()) {
if (bc == this) {
// Cannot be a descendent of myself so skip.
continue;
}
RefPtr<CanonicalBrowsingContext> top =
bc->Canonical()->TopCrossChromeBoundary();
if (top == this) {
if (aCallback(bc->Canonical()) == CallState::Stop) {
return;
}
}
}
}
}
void CanonicalBrowsingContext::SessionHistoryCommit(uint64_t aLoadId,
const nsID& aChangeID,
uint32_t aLoadType) {

View File

@ -102,6 +102,7 @@ class CanonicalBrowsingContext final : public BrowsingContext {
already_AddRefed<CanonicalBrowsingContext> GetParentCrossChromeBoundary();
already_AddRefed<CanonicalBrowsingContext> TopCrossChromeBoundary();
Nullable<WindowProxyHolder> GetTopChromeWindow();
nsISHistory* GetSessionHistory();
@ -113,6 +114,13 @@ class CanonicalBrowsingContext final : public BrowsingContext {
UniquePtr<LoadingSessionHistoryInfo> ReplaceLoadingSessionHistoryEntryForLoad(
LoadingSessionHistoryInfo* aInfo, nsIChannel* aChannel);
// Call the given callback on all top-level descendant BrowsingContexts.
// Return Callstate::Stop from the callback to stop calling
// further children.
void CallOnAllTopDescendants(
const std::function<mozilla::CallState(CanonicalBrowsingContext*)>&
aCallback);
void SessionHistoryCommit(uint64_t aLoadId, const nsID& aChangeID,
uint32_t aLoadType);

View File

@ -7023,19 +7023,11 @@ static void NotifyActivityChanged(nsISupports* aSupports) {
}
bool Document::IsTopLevelWindowInactive() const {
nsCOMPtr<nsIDocShellTreeItem> treeItem = GetDocShell();
if (!treeItem) {
return false;
if (BrowsingContext* bc = GetBrowsingContext()) {
return !bc->GetIsActiveBrowserWindow();
}
nsCOMPtr<nsIDocShellTreeItem> rootItem;
treeItem->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
if (!rootItem) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> domWindow = rootItem->GetWindow();
return domWindow && !domWindow->IsActive();
return false;
}
void Document::SetContainer(nsDocShell* aContainer) {

View File

@ -743,9 +743,6 @@ void nsFocusManager::WindowRaised(mozIDOMWindowProxy* aWindow,
baseWindow->SetVisibility(true);
}
// If this is a parent or single process window, send the activate event.
// Events for child process windows will be sent when ParentActivated
// is called.
if (XRE_IsParentProcess()) {
// Unsetting top-level focus upon lowering was inhibited to accommodate
// ATOK, so we need to do it here.
@ -835,9 +832,6 @@ void nsFocusManager::WindowLowered(mozIDOMWindowProxy* aWindow,
}
}
// If this is a parent or single process window, send the deactivate event.
// Events for child process windows will be sent when ParentActivated
// is called.
if (XRE_IsParentProcess()) {
ActivateOrDeactivate(window, false);
}
@ -969,10 +963,11 @@ void nsFocusManager::WindowShown(mozIDOMWindowProxy* aWindow,
}
}
if (nsIDocShell* docShell = window->GetDocShell()) {
if (nsCOMPtr<nsIBrowserChild> child = docShell->GetBrowserChild()) {
bool active = static_cast<BrowserChild*>(child.get())->ParentIsActive();
ActivateOrDeactivate(window, active);
if (XRE_IsParentProcess()) {
if (BrowsingContext* bc = window->GetBrowsingContext()) {
if (bc->IsTop()) {
bc->SetIsActiveBrowserWindow(bc->GetIsActiveBrowserWindow());
}
}
}
@ -1182,16 +1177,6 @@ nsresult nsFocusManager::FocusPlugin(Element* aPlugin) {
return NS_OK;
}
void nsFocusManager::ParentActivated(mozIDOMWindowProxy* aWindow,
bool aActive) {
nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
if (!window) {
return;
}
ActivateOrDeactivate(window, aActive);
}
nsFocusManager::BlurredElementInfo::BlurredElementInfo(Element& aElement)
: mElement(aElement),
mHadRing(aElement.State().HasState(NS_EVENT_STATE_FOCUSRING)) {}
@ -1351,29 +1336,32 @@ void nsFocusManager::EnsureCurrentWidgetFocused(CallerType aCallerType) {
void nsFocusManager::ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow,
bool aActive) {
MOZ_ASSERT(XRE_IsParentProcess());
if (!aWindow) {
return;
}
// Inform the DOM window that it has activated or deactivated, so that
// the active attribute is updated on the window.
aWindow->ActivateOrDeactivate(aActive);
if (BrowsingContext* bc = aWindow->GetBrowsingContext()) {
MOZ_ASSERT(bc->IsTop());
RefPtr<CanonicalBrowsingContext> chromeTop =
bc->Canonical()->TopCrossChromeBoundary();
MOZ_ASSERT(bc == chromeTop);
chromeTop->SetIsActiveBrowserWindow(aActive);
chromeTop->CallOnAllTopDescendants(
[aActive](CanonicalBrowsingContext* aBrowsingContext) -> CallState {
aBrowsingContext->SetIsActiveBrowserWindow(aActive);
return CallState::Continue;
});
}
// Send the activate event.
if (aWindow->GetExtantDoc()) {
nsContentUtils::DispatchEventOnlyToChrome(
aWindow->GetExtantDoc(), aWindow->GetCurrentInnerWindow(),
aActive ? u"activate"_ns : u"deactivate"_ns, CanBubble::eYes,
Cancelable::eYes, nullptr);
}
// Look for any remote child frames, iterate over them and send the activation
// notification.
nsContentUtils::CallOnAllRemoteChildren(
aWindow, [&aActive](BrowserParent* aBrowserParent) -> CallState {
Unused << aBrowserParent->SendParentActivated(aActive);
return CallState::Continue;
});
}
// Retrieves innerWindowId of the window of the last focused element to

View File

@ -256,12 +256,6 @@ class nsFocusManager final : public nsIFocusManager,
*/
void FireDelayedEvents(Document* aDocument);
/**
* Used in a child process to indicate that the parent window is now
* active or deactive.
*/
void ParentActivated(mozIDOMWindowProxy* aWindow, bool aActive);
/**
* Indicate that a plugin wishes to take the focus. This is similar to a
* normal focus except that the widget focus is not changed. Updating the

View File

@ -892,15 +892,6 @@ static bool AllDescendantsOfType(BrowsingContext* aParent,
return true;
}
static bool ParentWindowIsActive(Document* aDoc) {
nsCOMPtr<nsPIWindowRoot> root = nsContentUtils::GetWindowRoot(aDoc);
if (root) {
nsPIDOMWindowOuter* rootWin = root->GetWindow();
return rootWin && rootWin->IsActive();
}
return false;
}
void nsFrameLoader::MaybeShowFrame() {
nsIFrame* frame = GetPrimaryFrameOfOwningContent();
if (frame) {
@ -1090,15 +1081,20 @@ bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
return false;
}
if (BrowserHost* bh = mRemoteBrowser->AsBrowserHost()) {
RefPtr<BrowsingContext> bc = bh->GetBrowsingContext()->Top();
// Set to the current activation of the window.
bc->SetIsActiveBrowserWindow(bc->GetIsActiveBrowserWindow());
}
nsCOMPtr<nsISupports> container = mOwnerContent->OwnerDoc()->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
nsCOMPtr<nsIWidget> mainWidget;
baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
nsSizeMode sizeMode =
mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
OwnerShowInfo info(size, GetScrollbarPreference(mOwnerContent),
ParentWindowIsActive(mOwnerContent->OwnerDoc()),
sizeMode);
OwnerShowInfo info(size, GetScrollbarPreference(mOwnerContent), sizeMode);
if (!mRemoteBrowser->Show(info)) {
return false;
}
@ -1319,10 +1315,14 @@ nsresult nsFrameLoader::SwapWithOtherRemoteLoader(
otherBrowserParent->SetOwnerElement(ourContent);
// Update window activation state for the swapped owner content.
Unused << browserParent->SendParentActivated(
ParentWindowIsActive(otherContent->OwnerDoc()));
Unused << otherBrowserParent->SendParentActivated(
ParentWindowIsActive(ourContent->OwnerDoc()));
bool ourActive = otherBc->GetIsActiveBrowserWindow();
bool otherActive = ourBc->GetIsActiveBrowserWindow();
if (ourBc->IsTop()) {
ourBc->SetIsActiveBrowserWindow(otherActive);
}
if (otherBc->IsTop()) {
otherBc->SetIsActiveBrowserWindow(ourActive);
}
MaybeUpdatePrimaryBrowserParent(eBrowserParentChanged);
aOther->MaybeUpdatePrimaryBrowserParent(eBrowserParentChanged);

View File

@ -6754,79 +6754,6 @@ Location* nsGlobalWindowOuter::GetLocation() {
FORWARD_TO_INNER(Location, (), nullptr);
}
void nsGlobalWindowOuter::ActivateOrDeactivate(bool aActivate) {
if (!mDoc) {
return;
}
// Set / unset mIsActive on the top level window, which is used for the
// :-moz-window-inactive pseudoclass, and its sheet (if any).
nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
nsCOMPtr<nsIWidget> topLevelWidget;
if (mainWidget) {
// Get the top level widget (if the main widget is a sheet, this will
// be the sheet's top (non-sheet) parent).
topLevelWidget = mainWidget->GetSheetWindowParent();
if (!topLevelWidget) {
topLevelWidget = mainWidget;
}
}
SetActive(aActivate);
if (mainWidget != topLevelWidget) {
// This is a workaround for the following problem:
// When a window with an open sheet gains or loses focus, only the sheet
// window receives the NS_ACTIVATE/NS_DEACTIVATE event. However the
// styling of the containing top level window also needs to change. We
// get around this by calling nsPIDOMWindow::SetActive() on both windows.
// Get the top level widget's nsGlobalWindowOuter
nsCOMPtr<nsPIDOMWindowOuter> topLevelWindow;
// widgetListener should be an AppWindow
nsIWidgetListener* listener = topLevelWidget->GetWidgetListener();
if (listener) {
nsCOMPtr<nsIAppWindow> window = listener->GetAppWindow();
nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(window));
topLevelWindow = do_GetInterface(req);
}
if (topLevelWindow) {
topLevelWindow->SetActive(aActivate);
}
}
}
static CallState NotifyDocumentTree(Document& aDocument) {
aDocument.EnumerateSubDocuments(NotifyDocumentTree);
aDocument.UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE, true);
return CallState::Continue;
}
void nsGlobalWindowOuter::SetActive(bool aActive) {
nsPIDOMWindowOuter::SetActive(aActive);
if (mDoc) {
NotifyDocumentTree(*mDoc);
}
}
bool nsGlobalWindowOuter::IsTopLevelWindowActive() {
nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShell());
if (!treeItem) {
return false;
}
nsCOMPtr<nsIDocShellTreeItem> rootItem;
treeItem->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
if (!rootItem) {
return false;
}
nsCOMPtr<nsPIDOMWindowOuter> domWindow = rootItem->GetWindow();
return domWindow && domWindow->IsActive();
}
void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
bool changed = aIsBackground != IsBackground();
SetIsBackgroundInternal(aIsBackground);
@ -7794,7 +7721,6 @@ mozilla::dom::DocGroup* nsPIDOMWindowOuter::GetDocGroup() const {
nsPIDOMWindowOuter::nsPIDOMWindowOuter(uint64_t aWindowID)
: mFrameElement(nullptr),
mModalStateDepth(0),
mIsActive(false),
mIsBackground(false),
mMediaSuspend(StaticPrefs::media_block_autoplay_until_in_foreground()
? nsISuspendedTypes::SUSPENDED_BLOCK

View File

@ -290,9 +290,6 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
virtual nsPIDOMWindowOuter* GetPrivateRoot() override;
// Outer windows only.
virtual void ActivateOrDeactivate(bool aActivate) override;
virtual void SetActive(bool aActive) override;
virtual bool IsTopLevelWindowActive() override;
virtual void SetIsBackground(bool aIsBackground) override;
virtual void SetChromeEventHandler(
mozilla::dom::EventTarget* aChromeEventHandler) override;

View File

@ -736,8 +736,6 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy {
mozilla::dom::Element* GetFrameElementInternal() const;
void SetFrameElementInternal(mozilla::dom::Element* aFrameElement);
bool IsActive() { return mIsActive; }
void SetDesktopModeViewport(bool aDesktopModeViewport) {
mDesktopModeViewport = aDesktopModeViewport;
}
@ -766,8 +764,6 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy {
virtual nsPIDOMWindowOuter* GetPrivateRoot() = 0;
virtual void ActivateOrDeactivate(bool aActivate) = 0;
/**
* |top| gets the root of the window hierarchy.
*
@ -794,10 +790,6 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy {
*/
virtual nsPIDOMWindowOuter* GetInProcessScriptableParentOrNull() = 0;
virtual bool IsTopLevelWindowActive() = 0;
virtual void SetActive(bool aActive) { mIsActive = aActive; }
virtual void SetIsBackground(bool aIsBackground) = 0;
mozilla::dom::EventTarget* GetChromeEventHandler() const {
@ -1091,9 +1083,6 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy {
uint32_t mModalStateDepth;
// Tracks activation state that's used for :-moz-window-inactive.
bool mIsActive;
// Tracks whether our docshell is active. If it is, mIsBackground
// is false. Too bad we have so many different concepts of
// "active".

View File

@ -321,7 +321,6 @@ BrowserChild::BrowserChild(ContentChild* aManager, const TabId& aTabId,
mHasSiblings(false),
mIsTransparent(false),
mIPCOpen(false),
mParentIsActive(false),
mDidSetRealShowInfo(false),
mDidLoadURLInit(false),
mSkipKeyPress(false),
@ -1061,7 +1060,7 @@ mozilla::ipc::IPCResult BrowserChild::RecvCloneDocumentTreeIntoSelf(
void BrowserChild::DoFakeShow(const ParentShowInfo& aParentShowInfo) {
OwnerShowInfo ownerInfo{ScreenIntSize(), ScrollbarPreference::Auto,
mParentIsActive, nsSizeMode_Normal};
nsSizeMode_Normal};
RecvShow(aParentShowInfo, ownerInfo);
mDidFakeShow = true;
}
@ -1105,7 +1104,7 @@ mozilla::ipc::IPCResult BrowserChild::RecvShow(
}
ApplyParentShowInfo(aParentInfo);
RecvParentActivated(aOwnerInfo.parentWindowIsActive());
if (!mIsTopLevel) {
RecvScrollbarPreferenceChanged(aOwnerInfo.scrollbarPreference());
}
@ -1429,18 +1428,6 @@ mozilla::ipc::IPCResult BrowserChild::RecvDeactivate(uint64_t aActionId) {
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvParentActivated(
const bool& aActivated) {
mParentIsActive = aActivated;
nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE(fm, IPC_OK());
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
fm->ParentActivated(window, aActivated);
return IPC_OK();
}
mozilla::ipc::IPCResult BrowserChild::RecvSetKeyboardIndicators(
const UIStateChangeType& aShowFocusRings) {
nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());

View File

@ -565,8 +565,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
bool IPCOpen() const { return mIPCOpen; }
bool ParentIsActive() const { return mParentIsActive; }
const mozilla::layers::CompositorOptions& GetCompositorOptions() const;
bool AsyncPanZoomEnabled() const;
@ -714,8 +712,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
mozilla::ipc::IPCResult RecvSuppressDisplayport(const bool& aEnabled);
mozilla::ipc::IPCResult RecvParentActivated(const bool& aActivated);
mozilla::ipc::IPCResult RecvScrollbarPreferenceChanged(ScrollbarPreference);
mozilla::ipc::IPCResult RecvSetKeyboardIndicators(
@ -848,7 +844,6 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
bool mIsTransparent;
bool mIPCOpen;
bool mParentIsActive;
CSSSize mUnscaledInnerSize;
bool mDidSetRealShowInfo;
bool mDidLoadURLInit;

View File

@ -382,9 +382,8 @@ struct OwnerShowInfo {
// TODO(emilio): Margin preferences go here.
ScrollbarPreference scrollbarPreference;
// TODO(emilio): I think we should really be able to figure out these from the
// TODO(emilio): I think we should really be able to figure this out from the
// parent process too instead.
bool parentWindowIsActive;
nsSizeMode sizeMode;
};

View File

@ -748,8 +748,6 @@ child:
async DynamicToolbarOffsetChanged(ScreenIntCoord height);
async ParentActivated(bool aActivated);
async SetKeyboardIndicators(UIStateChangeType showFocusRings);
/**

View File

@ -195,15 +195,12 @@ static bool WindowCannotReceiveSensorEvent(nsPIDOMWindowInner* aWindow) {
}
nsPIDOMWindowOuter* windowOuter = aWindow->GetOuterWindow();
bool disabled =
windowOuter->IsBackground() || !windowOuter->IsTopLevelWindowActive();
if (disabled) {
BrowsingContext* topBC = aWindow->GetBrowsingContext()->Top();
if (windowOuter->IsBackground() || !topBC->GetIsActiveBrowserWindow()) {
return true;
}
// Check to see if this window is a cross-origin iframe:
auto topBC = aWindow->GetBrowsingContext()->Top();
if (!topBC->IsInProcess()) {
return true;
}

View File

@ -3670,9 +3670,9 @@ void nsWindow::OnContainerFocusOutEvent(GdkEventFocus* aEvent) {
if (IsChromeWindowTitlebar()) {
// DispatchDeactivateEvent() ultimately results in a call to
// nsGlobalWindowOuter::ActivateOrDeactivate(), which resets
// the mIsActive flag. We call UpdateMozWindowActive() to keep
// the flag in sync with GDK_WINDOW_STATE_FOCUSED.
// BrowsingContext::SetIsActiveBrowserWindow(), which resets
// the state. We call UpdateMozWindowActive() to keep it in
// sync with GDK_WINDOW_STATE_FOCUSED.
UpdateMozWindowActive();
}
@ -3918,7 +3918,7 @@ void nsWindow::OnWindowStateEvent(GtkWidget* aWidget,
mTitlebarBackdropState =
!(aEvent->new_window_state & GDK_WINDOW_STATE_FOCUSED);
// keep mIsActive in sync with GDK_WINDOW_STATE_FOCUSED
// keep IsActiveBrowserWindow in sync with GDK_WINDOW_STATE_FOCUSED
UpdateMozWindowActive();
ForceTitlebarRedraw();
@ -8140,11 +8140,12 @@ void nsWindow::UpdateMozWindowActive() {
// Update activation state for the :-moz-window-inactive pseudoclass.
// Normally, this follows focus; we override it here to follow
// GDK_WINDOW_STATE_FOCUSED.
mozilla::dom::Document* document = GetDocument();
if (document) {
nsPIDOMWindowOuter* window = document->GetWindow();
if (window) {
window->SetActive(!mTitlebarBackdropState);
if (mozilla::dom::Document* document = GetDocument()) {
if (nsPIDOMWindowOuter* window = document->GetWindow()) {
if (RefPtr<mozilla::dom::BrowsingContext> bc =
window->GetBrowsingContext()) {
bc->SetIsActiveBrowserWindow(!mTitlebarBackdropState);
}
}
}
}