summaryrefslogtreecommitdiffstats
path: root/dom/base/nsFocusManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/nsFocusManager.cpp')
-rw-r--r--dom/base/nsFocusManager.cpp67
1 files changed, 53 insertions, 14 deletions
diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp
index 5a4cf78d65..4e2d604693 100644
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -846,24 +846,27 @@ nsresult nsFocusManager::ContentRemoved(Document* aDocument,
NS_ENSURE_ARG(aDocument);
NS_ENSURE_ARG(aContent);
- RefPtr<nsPIDOMWindowOuter> window = aDocument->GetWindow();
- if (!window) {
+ nsPIDOMWindowOuter* windowPtr = aDocument->GetWindow();
+ if (!windowPtr) {
return NS_OK;
}
// if the content is currently focused in the window, or is an
// shadow-including inclusive ancestor of the currently focused element,
// reset the focus within that window.
- RefPtr<Element> previousFocusedElement = window->GetFocusedElement();
- if (!previousFocusedElement) {
+ Element* previousFocusedElementPtr = windowPtr->GetFocusedElement();
+ if (!previousFocusedElementPtr) {
return NS_OK;
}
if (!nsContentUtils::ContentIsHostIncludingDescendantOf(
- previousFocusedElement, aContent)) {
+ previousFocusedElementPtr, aContent)) {
return NS_OK;
}
+ RefPtr<nsPIDOMWindowOuter> window = windowPtr;
+ RefPtr<Element> previousFocusedElement = previousFocusedElementPtr;
+
RefPtr<Element> newFocusedElement = [&]() -> Element* {
if (auto* sr = ShadowRoot::FromNode(aContent)) {
if (sr->IsUAWidget() && sr->Host()->IsHTMLElement(nsGkAtoms::input)) {
@@ -1802,7 +1805,8 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
// focus, update the node in the window, and raise the window if desired.
if (allowFrameSwitch) {
AdjustWindowFocus(newBrowsingContext, true, IsWindowVisible(newWindow),
- actionId);
+ actionId, false /* aShouldClearAncestorFocus */,
+ nullptr /* aAncestorBrowsingContextToFocus */);
}
// set the focus node and method as needed
@@ -1975,7 +1979,9 @@ mozilla::dom::BrowsingContext* nsFocusManager::GetCommonAncestor(
bool nsFocusManager::AdjustInProcessWindowFocus(
BrowsingContext* aBrowsingContext, bool aCheckPermission, bool aIsVisible,
- uint64_t aActionId) {
+ uint64_t aActionId, bool aShouldClearAncestorFocus,
+ BrowsingContext* aAncestorBrowsingContextToFocus) {
+ MOZ_ASSERT_IF(aAncestorBrowsingContextToFocus, aShouldClearAncestorFocus);
if (ActionIdComparableAndLower(aActionId,
mActionIdForFocusedBrowsingContextInContent)) {
LOGFOCUS(
@@ -2026,6 +2032,17 @@ bool nsFocusManager::AdjustInProcessWindowFocus(
break;
}
+ if (aShouldClearAncestorFocus) {
+ // This is the BrowsingContext that receives the focus, no need to clear
+ // its focused element and the rest of the ancestors.
+ if (window->GetBrowsingContext() == aAncestorBrowsingContextToFocus) {
+ break;
+ }
+
+ window->SetFocusedElement(nullptr);
+ continue;
+ }
+
if (frameElement != window->GetFocusedElement()) {
window->SetFocusedElement(frameElement);
@@ -2041,18 +2058,22 @@ bool nsFocusManager::AdjustInProcessWindowFocus(
return needToNotifyOtherProcess;
}
-void nsFocusManager::AdjustWindowFocus(BrowsingContext* aBrowsingContext,
- bool aCheckPermission, bool aIsVisible,
- uint64_t aActionId) {
+void nsFocusManager::AdjustWindowFocus(
+ BrowsingContext* aBrowsingContext, bool aCheckPermission, bool aIsVisible,
+ uint64_t aActionId, bool aShouldClearAncestorFocus,
+ BrowsingContext* aAncestorBrowsingContextToFocus) {
+ MOZ_ASSERT_IF(aAncestorBrowsingContextToFocus, aShouldClearAncestorFocus);
if (AdjustInProcessWindowFocus(aBrowsingContext, aCheckPermission, aIsVisible,
- aActionId)) {
+ aActionId, aShouldClearAncestorFocus,
+ aAncestorBrowsingContextToFocus)) {
// Some ancestors of aBrowsingContext isn't in this process, so notify other
// processes to adjust their focused element.
mozilla::dom::ContentChild* contentChild =
mozilla::dom::ContentChild::GetSingleton();
MOZ_ASSERT(contentChild);
- contentChild->SendAdjustWindowFocus(aBrowsingContext, aIsVisible,
- aActionId);
+ contentChild->SendAdjustWindowFocus(aBrowsingContext, aIsVisible, aActionId,
+ aShouldClearAncestorFocus,
+ aAncestorBrowsingContextToFocus);
}
}
@@ -2423,6 +2444,22 @@ bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear,
if (ancestorWindowToFocus) {
ancestorWindowToFocus->SetFocusedElement(nullptr, 0, true);
}
+
+ // When the focus of aBrowsingContextToClear is cleared, it should
+ // also clear its ancestors's focus because ancestors should no longer
+ // be considered aBrowsingContextToClear is focused.
+ //
+ // We don't need to do this when aBrowsingContextToClear and
+ // aAncestorBrowsingContextToFocus is equal because ancestors don't
+ // care about this.
+ if (aBrowsingContextToClear &&
+ aBrowsingContextToClear != aAncestorBrowsingContextToFocus) {
+ AdjustWindowFocus(
+ aBrowsingContextToClear, false,
+ IsWindowVisible(aBrowsingContextToClear->GetDOMWindow()), aActionId,
+ true /* aShouldClearAncestorFocus */,
+ aAncestorBrowsingContextToFocus);
+ }
}
SetFocusedWindowInternal(nullptr, aActionId);
@@ -2569,7 +2606,9 @@ void nsFocusManager::Focus(
// focus can be traversed from the top level down to the newly focused
// window.
RefPtr<BrowsingContext> bc = aWindow->GetBrowsingContext();
- AdjustWindowFocus(bc, false, IsWindowVisible(aWindow), aActionId);
+ AdjustWindowFocus(bc, false, IsWindowVisible(aWindow), aActionId,
+ false /* aShouldClearAncestorFocus */,
+ nullptr /* aAncestorBrowsingContextToFocus */);
}
// indicate that the window has taken focus.