diff options
Diffstat (limited to 'dom/base/nsFocusManager.cpp')
-rw-r--r-- | dom/base/nsFocusManager.cpp | 67 |
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. |