mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
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:
parent
271d075cff
commit
6cd960cfb3
@ -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;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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".
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -748,8 +748,6 @@ child:
|
||||
|
||||
async DynamicToolbarOffsetChanged(ScreenIntCoord height);
|
||||
|
||||
async ParentActivated(bool aActivated);
|
||||
|
||||
async SetKeyboardIndicators(UIStateChangeType showFocusRings);
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user